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

C语言中scanf为何会修改非传入参数的其他变量值?

问题根因

这是典型的栈缓冲区溢出问题,根源是对C语言scanf的%s格式符行为不熟悉:

  • %s读取字符串时,会在读取到的所有字符末尾自动追加1个值为0x00的'\0'字符串结束符,这个结束符是强制写入的,占1字节内存。
  • 你定义的接收缓冲区unsigned char a[8]只有8字节长度,刚好能放下8位二进制输入字符,完全没有给'\0'预留存储空间,导致scanf写完8个输入字符后,会把结束符写到a数组之外的相邻内存上。

结合代码执行流程和栈内存布局,异常现象可以完全复现:

  1. 编译器安排栈内存时,循环内局部数组a的末尾紧邻mem数组的起始位置,也就是a数组后第1个字节的地址刚好就是mem[0]的存储地址。
  2. i=0轮次:先执行scanf读入第一行8个字符,写入a[0]~a[7],此时追加的'\0'写到mem[0]位置,但此时mem[0]还没被赋值,是未初始化的垃圾值,被写成0不会被注意到;随后通过内层循环计算,把mem[0]的值更新为正确的0x3E。
  3. i=1轮次:进入循环后首先执行scanf读入第二行输入,读完8个字符后再次往a数组后的相邻地址(也就是mem[0]的位置)写入'\0',直接把上一轮算好存在mem[0]里的0x3E覆盖成了0x00,和观察到的异常完全一致。
  4. 后续轮次没有出现异常,是因为a数组的相邻位置只对应mem[0],写入的结束符只会覆盖mem[0],不会影响其他mem元素。
修复方案

只需要给a数组多预留1字节存放字符串结束符即可,把数组定义改成:

unsigned char a[9]; // 8个输入字符 + 1个自动追加的'\0'结束符

如果要更稳妥,可以在scanf里加长度限制,强制最多读取8个字符,避免超长输入导致溢出:

scanf("%8s", a);

注意:就算加了长度限制,%s仍然会追加'\0',数组长度还是要留够9字节。


内容的提问来源于stack exchange,提问作者JASON CHAN

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 13:09:25