使用strcat将字符串附加到字符数组(例如char p[] =“TEST”)是否有效?

3
#include<iostream>
#include<string.h>
using namespace std;
int main()
{

    char p [] = "TEST";
    strcat (p, "VAL");
    cout << p;
    return 0;
}

如果我理解正确,例如 char p [] = "TEST"; 这样的语句将从栈上分配空间。当我为这样的字符串调用 strcat() 时,p[] 的存储如何调整以容纳额外字符?
最后一个 cout 打印出 "TESTVAL"。这样调用 strcat 是否有效?如果是,它是如何工作的?我的理解可能有问题,但感觉自己失去了联系。所以这可能是一个愚蠢的问题。请给予一些指导。
3个回答

8
存储未调整,调用无效,代码行为未定义。

在这种情况下,我想知道为什么输出是正确的,没有任何运行时问题? - NeonGlow
3
@NeonGlow 仅仅是纯运气。 - Galik
2
@NeonGlow 只是运气不好。尝试使用比“VAL”更大的字符串进行strcat操作。例如,使用此答案在我的机器上会崩溃。 - molbdnilo
我正在使用ideone.com。现在使用了一个更大的字符串,导致运行时错误。感谢您的时间。这很有帮助。 - NeonGlow
2
未定义行为可能产生的结果之一是你认为正确的结果。 - Peter

3

when you write

char buffer[] = "some literal";

它被扩展到

char buffer[sizeof("some literal")] = "some literal";

这个大小正好能够存储"some literal",不多也不少。

当您在当前缓冲区的末尾连接另一个字符串时,您会写入数组的边界之外,导致未定义的行为。

另一个问题是,在C++中,我们通常使用std::string来处理字符串,它会自动为我们处理所有的内存调整。


感谢 char buffer[sizeof("some literal")] = "some literal"; 这段代码,我从未知道它的内部工作原理。 - NeonGlow
这并不一定是它内部工作原理的描述。它是以C或C++开发人员能够理解的方式描述其效果。没有要求C编译器在内部使用sizeof来计算提供的字符串字面量的长度。 - Peter
@Peter:明白了,谢谢。 - NeonGlow

2

p保留了5个字符的空间(4个字符再加上一个空终止符)。然后你又添加了3个字符,需要8个字符的空间(7个字符再加上一个空终止符)。你没有足够的空间来存储这些字符,将会覆盖堆栈。根据你的编译器和构建设置,你可能看不到任何区别,因为编译器可能在堆栈变量之间留下空间。在优化释放版本上,你可能会遇到崩溃。

如果你把代码改成下面这样,你应该可以看到sentinel1 & 2不再是0(具体哪一个被破坏了取决于编译器)。

#include<iostream>
#include<string.h>
using namespace std;
int main()
{
    int sentinel1 = 0;
    char p [] = "TEST";
    int sentinel2 = 0;
    strcat (p, "VAL");
   cout << p << sentinel1 << sentinel2;


   return 0;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接