C和C++之间的差异:数组大小不受尊重

rub*_*bik 0 c c++ arrays

我正在学习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;
}
Run Code Online (Sandbox Code Playgroud)

当我输入一个超过两个字节的名字时,答案就是胡言乱语,但即使我不确切知道原因,我也知道出了问题,它试图恢复.
相反,如果我编写这个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;
}
Run Code Online (Sandbox Code Playgroud)

我期待类似的行为,因为我声明answer为char数组而不是字符串(可以动态调整其大小).但是当我输入很长的东西时,它会在我输入时打印出来.一个例子:

$ ./test
What is your name? asdfa
asdfa
$ ./test
What is your name? sdhjklwertiuoxcvbnm
sdhjklwertiuoxcvbnm
Run Code Online (Sandbox Code Playgroud)

那么,这里发生了什么?作为第二个问题,当我输入更长的东西时,C中会发生什么?

编辑:只是为了澄清,我知道我可以使用std::string而不是char数组(我已经在上面写了^^).我有兴趣知道程序为何表现出这种行为.现在我知道它是未定义的行为.另外,我纠正了C程序(scanf)中的错误.

Rak*_*kib 12

char answer[2];表示您的数组只能包含2个字符.如果你超过这个,那么内存就会溢出并且是未定义的行为.在数组中保留足够的空间,或者std::string如果使用数组不是必需的,则更好地使用.正如另一个答案指出的那样,你正在以错误的方式接受输入.

  • "你的数组只能包含2个字符"......其中一个必须是''\ 0',因为它是一个字符串. (6认同)
  • 详细说明,"未定义的行为"意味着任何事情都可能发生. (5认同)

das*_*ght 9

这是未定义的行为(UB):

scanf(answer);
Run Code Online (Sandbox Code Playgroud)

scanf函数会将未初始化的内容解释answer格式字符串,从而导致UB.

它应该是这样的:

scanf("%1s", answer);
Run Code Online (Sandbox Code Playgroud)

请注意,当您声明大小为2的字符数组时,这意味着它可以适合长度最多为1的C字符串,因为您需要一个字符用于null终止符.

请注意,当您在C++程序中为名称输入两个以上的字符时,您也会得到未定义的行为:写入数组的末尾是UB.幸运的是,很少需要在C++中将字符串读入字符数组,因为标准C++库提供了动态调整大小的类std::string,这是表示字符串的更好选择.


Bat*_*eba 6

你不能指望类似的行为.

在这两种情况下都可以预期未定义的行为:超出内存缓冲区是两种语言中未定义的行为,因此绝对允许任何事情发生.

  • 如果更多的编译器只采用旧的"[nasal demons](http://www.catb.org/jargon/html/N/nasal-demons.html)"方法,开发人员可能会更加谨慎. (4认同)