You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言用户访问统计程序报栈缓冲区溢出警告但运行正常,原因是什么?

问题分析

溢出点位定位

  • 第一个明确溢出点:scanf("%s", &sign) 语句。sign是单字节char类型,%s是字符串读取格式符,读取到输入字符后会自动在末尾追加空终止符\0,至少会写入2字节数据,直接超出sign仅1字节的内存空间,产生栈溢出。
  • 第二个溢出风险:栈上分配超大数组。userslogginrank数组大小为1000000个int,按4字节/int计算占4MB,usersvisitations数组大小为100000个int占400KB,合计近4.4MB。而Windows系统默认栈空间仅1MB,就算是Linux系统默认栈空间也只有8MB,很容易超出栈容量限制触发栈溢出。
  • 第三个溢出风险:循环终止条件错误。do-while的终止条件写为end != 1 || i <= 999999,逻辑或的特性决定了就算end被置为1,只要i不超过999999就会继续循环,当i达到VISIT_MAX(1000000)之后继续写入userslogginrank[i]就会产生数组越界溢出。
  • 第四个潜在问题:局部数组未初始化。usersvisitations和userslogginrank都是栈上局部变量,没有手动初始化,其初始值是栈上残留的随机值,访问未写入的位置属于未定义行为。

程序仍可正常运行的原因

栈缓冲区溢出属于C语言的未定义行为,未定义行为不代表一定会崩溃,只是行为不受C标准约束,你遇到的正常运行只是特定场景下的巧合:

  1. scanf("%s", &sign)溢出的1字节数据如果刚好写到了栈上未被使用的内存区域,或者覆盖了不重要的临时数据,没有破坏函数返回地址、栈帧指针等关键数据,就不会触发崩溃。
  2. 如果你使用的是Linux/macOS等系统,默认栈空间大小为8MB,4.4MB的数组可以完全放下,不会触发栈空间不足的溢出。
  3. 运行程序时栈上残留的内存刚好是0值,所以usersvisitations的计数不会出现异常值,表现为功能正常。
  4. 你的测试输入量比较小,没有触发数组越界的场景,所以越界问题没有暴露。

修复建议

  • 将scanf("%s", &sign)改为scanf(" %c", &sign),用%c读取单个字符,前面加空格匹配输入中的空白符。
  • 把超大数组改为全局变量,或者用malloc动态分配内存,全局变量和动态分配的内存位于堆区,不受栈大小限制。
  • 修正循环终止条件为end != 1 && i < VISIT_MAX,避免数组越界。
  • 初始化usersvisitations数组所有元素为0,保证计数逻辑正确。

内容的提问来源于stack exchange,提问作者ondra hofmann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 22:36:03