C语言用scanf先后读%d和%s时为何之前的整数变量会被修改
C语言变量异常修改问题诱因分析
核心原因是栈缓冲区溢出触发的未定义行为,具体细节如下:
- 数组容量不足:代码中定义的
char str[1]仅能容纳1个字节的数据,而C语言中scanf的%s格式符读取字符串时,会在有效输入字符末尾自动追加字符串结束符\0(ASCII值为0)。当输入ab时,共需要存储'a'、'b'、\0三个字节,远超过数组的1字节容量。 - 栈内存相邻覆盖:函数内的局部变量通常在栈空间连续分配,当前编译环境中
str数组的内存地址紧邻int变量n的低地址侧。写入str的溢出字节会直接覆盖n的内存空间:str[0]存储'a'(ASCII值97)- 溢出的第2个字节
'b'(ASCII值98)刚好覆盖n变量的低1字节,原本n的值为2,低字节被覆盖后整体取值变为98 - 再溢出的第3个字节
\0会继续覆盖更高地址的内存,可能触发其他不可预期的错误
- 代码写法不规范:
scanf("%s", &str)的传参写法错误,数组名str本身就是首地址,无需取地址,同时%s没有限制输入长度,是典型的不安全用法。
修复方案
将字符串数组调整为足够的容量,同时限制scanf的输入长度,留1字节存储结束符:
int main(){ int m, n; printf("M = "); scanf("%d", &m); printf("N = "); scanf("%d", &n); char str[128]; // 扩容到足够存储预期输入的大小 scanf("%127s", str); // 限制最多读取127个字符,避免溢出 printf(" %d\n", m); printf(" %d\n", n); printf(" %s\n", str); }
内容的提问来源于stack exchange,提问作者Minh Nguyen
相关产品推荐
相关产品推荐

