C++字符数组打印结果不符预期及stack smashing detected错误原因
问题解答
代码、输入与输出
测试代码
#include <iostream> using namespace std; int main() { int n; // n=3 cin >> n; char a[n]; cin >> a; cout << a; return 0; }
输入
3 Hello
输出
Hello
疑问1:为何输出是“Hello”而非“Hel”?
原因在于以下几点:
cin >> a不做长度校验:这个输入操作会读取所有非空白字符(直到换行/空格),完全不管数组a的实际容量。你输入的"Hello"包含5个字符,加上C风格字符串必须的结束符\0,总共需要6字节空间,但数组只有3字节。- 越界写入栈内存:数组
a在栈上仅分配3字节,输入的'H'、'e'、'l'会存在数组内,剩下的'l'、'o'、'\0'直接写到数组之后的栈空间里——这属于未定义行为,内存被非法篡改,只是这次没触发崩溃。 cout以\0为结束标志:输出C风格字符串时,cout会从数组起始地址开始读取字符,直到碰到\0才停止。由于输入时把\0写在了"Hello"的末尾,所以cout会把所有越界写入的字符都输出,最终显示"Hello"。
疑问2:定义为char a[3]时为何触发“stack smashing detected”?
这是编译器的栈保护机制在起作用:
- 当你声明固定长度数组
char a[3]时,GCC等编译器会在数组的栈空间末尾插入一个特殊的“金丝雀(Stack Canary)”值,用来检测栈溢出。 - 输入"Hello"时,越界的字符会覆盖这个金丝雀值。
- 程序执行到
main函数末尾时,会检查金丝雀值是否被篡改。一旦发现异常,就会抛出"stack smashing detected"错误并终止程序——这是一种安全防护,防止栈溢出被恶意利用或导致程序崩溃。
而之前的变长数组char a[n]是C语言的扩展特性,部分编译器对VLA的栈保护支持不完善,所以没触发这个错误,但本质上同样是危险的越界写入行为。
内容的提问来源于stack exchange,提问作者Vikash Gola
相关产品推荐
相关产品推荐

