为什么使用sscanf会修改原始char数组的内容?
异常原因分析
该问题的核心是栈缓冲区溢出触发的C语言未定义行为,具体原因如下:
- C标准库的
sscanf函数使用%s格式符读取字符串时,不会校验目标缓冲区的容量,会持续读取到空白字符(空格、换行、制表符等)为止,且会自动在读取的内容末尾追加字符串结束符\0。如果读取的内容总长度超过目标缓冲区的大小,就会发生越界写入,直接覆盖栈上相邻的其他内存空间。 - 你的代码中,
sscanf读取的第四段子串为newlinetest,共11个字符,加上自动追加的\0总长度为12字节,但你定义的parm4缓冲区长度只有10,不足以容纳读取的内容,发生越界写入。 - 栈上的局部变量是按编译器分配的顺序连续存储的,初始代码中
s数组正好处于parm4溢出写入的内存区域,parm4越界写入的内容将s数组的第二个字节覆盖为\0,因此打印s时只会输出第一个字符t。 - 当你将
parm1的长度调整为90后,栈上局部变量的内存布局发生变化,parm4溢出写入的内容不再覆盖s数组的有效区域,因此s的输出看起来恢复正常,但这只是随机的巧合,缓冲区溢出的本质问题并没有解决,仍然属于未定义行为,随时可能出现程序崩溃、输出异常等问题。
修复建议
- 使用带长度限制的格式符控制读取长度:在
%s中加入最大读取字符数,需要预留1字节给结束符\0,例如parm4长度为10,格式符应写为%9s,完整的sscanf写法为sscanf(s, "%9s %3s %255s %9s", parm1, parm2, parm3, parm4); - 优先使用带显式长度参数的输入函数,避免无限制读取导致的溢出问题。
内容的提问来源于stack exchange,提问作者squinky
相关产品推荐
相关产品推荐

