【问题标题】:String moved unexpectedly in C字符串在 C 中意外移动
【发布时间】:2013-06-11 18:28:32
【问题描述】:

作为指针练习,我做了一个字符串连接函数:

void
strcat(char *s, char *t)
{
    while(*s)
        s++;
    while(*s++ = *t++);
}

似乎工作得很好:

main()
{
    char *s = "Hello, ";
    char *t = "world!";

    strcat(s,t);
    printf("%s\n", s);

    return 0;
}

按预期生成Hello, world!。但是也发生了一些不想要的事情,打印字符串t 指向给orld!strcat 不可能改变 t。相反,似乎字符串已经移动了;在 strcat 之后递减 t 然后打印它会给出正确的字符串。

是什么移动了字符串? strcat 必须是它,但不知道它有什么问题。

如果重要,在 tcc 版本 0.9.26 (x86-64 Win64) 中编译。

【问题讨论】:

  • 请注意,以str 和字母开头的名称始终保留用于实现,因此您不应将新函数命名为该名称。

标签: c pointers string-concatenation memory-address


【解决方案1】:

这是未定义的行为:

  • 您正在写入分配给字符串文字的空间,并且
  • 您正在写超出分配的空间。

为了进行就地连接,目的地必须包含足够的空间来容纳连接的结果。解决方法如下:

main()
{
    char s[14] = "Hello, "; // 14 is enough to fit Hello, world!\0
    char *t = "world!";

    strcat(s,t);
    printf("%s\n", s);

    return 0;
}

注意:您可能希望更改函数的签名以表明第二个字符串不会被修改:

void strcat(char *s, const char *t)

【讨论】:

    【解决方案2】:

    你的变量 t 的内容是“world!\0”,它在内存中就在你的另一个变量 s 之后,它包含了“Hello, \0”。您的 strcat 函数覆盖了变量 s 中的空终止符,并继续将内存覆盖到变量 t 中。

    最初,分配的内存可以显示为“Hello, \0world!\0” 运行 strcat 函数后,它可能显示为 "Hello, world!\0\0" 最后一个空终止符从未更改,但其他所有内容看起来好像它已向左移动,因为您的 strcat 函数覆盖了第一个空终结者。

    你的指针 t 仍然指向它之前所在的内存位置。由于那里的内存发生了变化,所以 t 处的内容可以显示为“orld!\0\0”。

    当你打印这个时,它显示为“orld!”

    当然,这都是未定义的行为。您不能 100% 肯定这种情况每次都会发生,应该不惜一切代价避免这种情况。

    【讨论】:

      【解决方案3】:

      尝试更多类似的东西:

      main()
      {
          char *s = "Hello, ";
          char newStr[256];
          strcpy(newStr, s);
      
          char *t = "world!";
      
          strcat(newStr,t);
          printf("%s\n", newStr);
      
          return 0;
      }
      

      否则,您正在修改未定义的字符串文字。它现在恰好正在更改t,但其他编译器甚至其他尝试都会产生新的结果。

      【讨论】:

        猜你喜欢
        • 2022-01-13
        • 1970-01-01
        • 2022-11-20
        • 1970-01-01
        • 1970-01-01
        • 2013-12-13
        • 2017-10-04
        • 2019-04-26
        • 2023-03-18
        相关资源
        最近更新 更多