2

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

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) 中编译。

4

3 回答 3

4

这是未定义的行为:

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

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

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)
于 2013-06-11T18:31:03.333 回答
2

您的变量 t 的内容为“world!\0”,位于内存中的其他变量 s 之后,其中包含“Hello, \0”。您的 strcat 函数覆盖了变量 s 中的空终止符,并继续将内存覆盖到变量 t 中。

最初,分配的内存可能显示为“Hello, \0world!\0” 运行 strcat 函数后,它可能显示为“Hello, world!\0\0” 最后一个空终止符从未改变,但一切else 看起来好像它被移到了左边,因为你的 strcat 函数覆盖了第一个空终止符。

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

当您打印它时,它显示为“orld!”

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

于 2013-06-11T18:42:17.933 回答
1

尝试更多类似的东西:

main()
{
    char *s = "Hello, ";
    char newStr[256];
    strcpy(newStr, s);

    char *t = "world!";

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

    return 0;
}

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

于 2013-06-11T18:37:52.753 回答