我学习C ++并且发现了一个我不理解的行为。如果我用C编写以下程序:
#include <stdio.h>
int main() {
char question[] = "What is your name? ";
char answer[2];
printf(question);
scanf("%ls", answer);
printf("%s\n", answer);
return 0;
}
当我输入一个超过两个字节的名字时,答案就是胡言乱语,但即使我不确切知道原因,我也知道出了问题并试图恢复。
相反,如果我编写这个C ++程序(有点等同于前者):
#include <iostream>
using namespace std;
int main() {
char question[] = "What is your name? ";
char answer[2];
cout << question;
cin >> answer;
cout << answer << endl;
return 0;
}
我期待类似的行为,因为我将answer
声明为char数组而不是字符串(可以动态调整其大小)。但是当我输入很长的东西时,它会在我输入时打印出来。一个例子:
$ ./test
What is your name? asdfa
asdfa
$ ./test
What is your name? sdhjklwertiuoxcvbnm
sdhjklwertiuoxcvbnm
那么,这里发生了什么?作为第二个问题,当我输入更长的东西时,C中会发生什么?
编辑:为了澄清,我知道我可以使用std::string
而不是char数组(我已经在^^上面写了它)。我有兴趣知道为什么这些程序展示 行为。现在我知道它的未定义行为。另外,我更正了C程序(scanf)中的错误。
答案 0 :(得分:12)
char answer[2];
表示您的数组只能包含2个字符。如果你超过这个,那么内存就会溢出并且是未定义的行为。如果使用数组不是必需的,则在数组中保留足够的空间,或者更好地使用std::string
。而另一个答案指出,你正在以错误的方式接受输入。
答案 1 :(得分:9)
这是未定义的行为(UB):
scanf(answer);
scanf
函数会将answer
的未初始化内容解释为格式字符串,从而导致UB。
应该是这样的:
scanf("%1s", answer);
请注意,当您声明大小为2的字符数组时,这意味着它可以适合长度最多为1的C字符串,因为您需要一个字符用于空终止符。
请注意,当您在C ++程序中为名称输入两个以上的字符时,您也会得到未定义的行为:写入数组的末尾是UB。幸运的是,很少需要在C ++中将字符串读入字符数组,因为标准C ++库提供了动态调整大小的类std::string
,这是表示字符串的更好选择。
答案 2 :(得分:6)
你不能指望类似的行为。
在这两种情况下都可以预期未定义的行为:在两种语言中超出内存缓冲区未定义的行为,所以绝对允许任何事情发生。
答案 3 :(得分:1)
char answer[2];
包含仅2个字节的空间。 (在NUL
终止字符串的情况下,1字节+ 1 NUL
个字符)
在C
和C++
访问超出数组大小的数据undefined。所以你现在应该问why
,how
等等。你应该不这样做。
处理这种未定义行为的正确方法是:
std::string