程序在缓冲区溢出时没有崩溃

我想从键盘读取一个string,并存储在buf 。 我设置了一个char buf[6]数组,这个数组最多可以存储5个字符和\0

然后我键入123 456 789它包含11个字符和一个\0 ,程序仍然可以运行,但是如果我input一个更长的string123 456 789 123 456 789它将在运行时崩溃。 这两个input也超出了buf的范围,但是一个可以运行,另一个崩溃?

这是我的代码:

 #include <stdio.h> #include <stdlib.h> #include <string.h> void read_str(); int main(){ read_str(); system("pause"); return 0; } void read_str(){ char buf[6] = {}; scanf("%[^\n]",buf); printf("%d\n",strlen(buf)); printf("%s\n",buf); } 

Solutions Collecting From Web of "程序在缓冲区溢出时没有崩溃"

这只是未定义的行为 ,写在分配内存的范围之外。 它现在可能工作,但不能依靠工作。 附件J.2的C99草案标准 未定义的行为说:

一个数组下标超出范围,即使一个对象明显可以用给定的下标访问(如左值表达式a [1] [7]给定了声明int a [4] [5])(6.5.6)。

请注意,第3.4.3节定义了第2段中的术语的未定义行为重点是我 ):

可能的未定义的行为范围包括从完全忽略情况和不可预测的结果 ,到在翻译或程序执行过程中以环境特征(有或没有发出诊断消息),终止翻译或执行(在发行的诊断消息)。

真正的原因很可能是因为你正在进行一个函数调用,所以你只是覆盖了你的栈的内容,而你实际上并没有记住你自己没有的内存,直到你尝试写下底层的字符的。 即使它不会崩溃,但这几乎总是不好的,因为你覆盖了程序放在那里的值是有原因的。 毕竟,如果每次重写缓冲区时总是崩溃,那么缓冲区溢出错误永远不会发生,我们知道它们的确如此。

例如,你的堆栈可能会向下扩展。 当你进行一个函数调用时,你可能会得到寄存器值,返回地址,参数值以及其他东西。 那么,只有这样,你的6个字节才能被分配。 如果所有其他的东西占用,比如说12个字节,那么你可以写18个字符到buf ,但仍然只能触摸不应该改变的内存,而是你的进程拥有的内存。 由于你的进程拥有它,你不会得到非法的内存访问,你不会崩溃。 一旦你超过了18个字节,那么你很可能进入你的进程不拥有的内存,你会得到一个段错误,游戏将会结束。

C的原因是你只是有不确定的行为,奇怪的事情发生,你甚至不应该尝试理解。