我想从键盘读取一个字符串并存储在buf
中。我设置了一个char buf[6]
数组,这个数组最多可以存储5个字符和\0
。
然后我输入123 456 789
它包含11个字符和\0
,程序仍然可以运行,但如果我输入更长的字符串123 456 789 123 456 789
,它将在运行时崩溃。
这两个输入也超出了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);
}
答案 0 :(得分:3)
这只是undefined behavior在分配的内存范围之外写入。它可能现在可以工作但不能依赖它工作。附件J.2
未定义行为中的C99 draft standard表示:
数组下标超出范围,即使某个对象显然可以使用 给定下标(如左边的表达式a [1] [7]给出声明int a [4] [5])(6.5.6)。
请注意,定义 2 段中的术语的3.4.3
未定义行为部分(强调我的):
可能的未定义行为包括完全忽略具有不可预测结果的情况,在翻译或程序执行期间以环境特征的文档化方式行事(有或没有发出诊断消息),终止翻译或执行(发布诊断信息)。
答案 1 :(得分:3)
真正的原因很可能是你刚刚在函数调用中覆盖了堆栈的内容,并且在你尝试编写字符之前实际上并没有获得你不拥有的内存超越它的底部。即使它没有崩溃,这几乎总是坏的,因为你覆盖了程序放在那里的值是有原因的。毕竟,如果每次覆盖缓冲区时总是崩溃,那么缓冲区溢出错误就永远不会发生,我们知道它们会发生错误。
例如,您的筹码可能会向下增长。进行函数调用时,可能会获得寄存器值,返回地址,参数值以及放置到堆栈中的其他内容。然后,只有这样,才会分配buf
的6个字节。如果所有其他内容占用,比如说12个字节,那么你可以写18个字符到buf
,但仍然只是触摸你不应该改变的内存,而是你的进程拥有。由于您的进程拥有它,您将不会获得非法内存访问,并且您不会崩溃。一旦你超过18个字节,那么你很可能会进入你的进程不拥有的内存,你将得到一个段错误,游戏将会启动。
C的原因是你只是有未定义的行为,并且发生了奇怪的事情,你甚至不应该试图理解。