fgets读取字符数超存储数组大小:原代码正常复现却崩溃?
为什么fgets第二个参数超过数组长度会导致程序崩溃?
这是典型的缓冲区溢出触发未定义行为导致的问题,咱们一步步拆解原因:
1. 核心问题:数组空间不足,触发非法内存访问
你定义的str是一个仅能容纳80个字符的栈数组(char str[80];),而fgets的第二个参数表示的是最多写入的字符数(包含末尾的\0终止符)。当你传入200时,fgets会尝试往str所在的内存区域写入最多199个字符加1个终止符,这远远超出了str的80字节容量。
这种越界写入会覆盖栈上str之后的其他数据——比如你的FILE* fi指针变量,或者函数的返回地址。一旦这些关键数据被破坏,程序执行到后续步骤(比如fclose(fi)或者函数返回时)就会访问非法内存,直接崩溃。
2. 为什么原项目能“正常运行”?
这其实是未定义行为的典型表现:未定义行为不代表一定会崩溃,它的结果完全不可预测。可能原项目满足以下某个条件:
- 编译选项或栈内存布局和你在Eclipse中的环境不同,溢出的区域刚好是未被使用的栈空间,没有破坏关键数据;
- 项目中读取的
file文件里,每行内容都很短(远小于80字符),实际并没有触发真正的溢出; - 运气好,溢出的内容刚好没有影响到程序的关键执行流程。
但这绝对不是“正确”的运行,只是侥幸而已——哪天输入内容变长,或者环境变化,原项目一样会崩溃。
3. 正确的修复方式
永远要保证fgets的第二个参数不超过缓冲区的实际大小,最稳妥的方式是用sizeof(str)来自动获取数组长度,这样就算以后修改数组大小也不会出错:
fgets(str, sizeof(str), fi);
另外顺便提一句:你代码里的while(!feof(fi))也是一个常见的坑,它会导致最后一行被重复读取一次,建议改成检查fgets的返回值:
while(fgets(str, sizeof(str), fi) != NULL) { // do things }
内容的提问来源于stack exchange,提问作者Daycopo
相关产品推荐
相关产品推荐

