C语言中%5c格式控制符导致输出异常的原因探究
scanf格式符误用导致的异常输出分析
#include <stdio.h> int main() { int y = 0, w = 0; scanf("%d %5c", &y, &w); printf("%d,%c\n", y, w); return 0; }
异常现象
- 输入
2000 12345,输出1845,1 - 输入
1000 12345,输出821,1 - 输入
2000 23456,输出1846,2 - 将
%5c改为%4c后,输入2000 12345输出2000,1
问题根源与数值解析
类型不匹配引发缓冲区溢出
变量w是int类型(通常占4字节),但scanf中使用了%c格式符配合%5c——这表示连续读取5个字符并写入目标地址。由于w仅能容纳4字节数据,前4个字符填满w的内存后,第5个字符会越界写入相邻变量y的内存空间,直接篡改y的原始值。奇怪数值的具体来源
以输入2000 12345为例:%d读取2000后,跳过空格,%5c读取1、2、3、4、5这5个字符。- 前4个字符按小端序(多数系统的字节存储规则)写入
w的4字节,printf("%c", w)会取w的最低字节(即'1'的ASCII码0x31),因此输出字符为1。 - 第5个字符
'5'的ASCII码是0x35,会覆盖y的最低字节:原y=2000的十六进制为0x000007D0,最低字节0xD0被替换为0x35,新值为0x00000735,转换成十进制就是1845。
其他数值同理:
- 输入
1000 12345:1000的十六进制是0x000003E8,最低字节0xE8被替换为0x35,得到0x00000335(十进制821)。 - 输入
2000 23456:第5个字符是'6'(ASCII码0x36),替换后y的十六进制为0x00000736(十进制1846)。
改为
%4c后恢复正常的原因%4c读取4个字符,刚好填满w的4字节内存,不会发生越界写入,因此y的内存未被篡改,保持初始读取的2000不变,输出自然正常。
内容的提问来源于stack exchange,提问作者kangaroo
相关产品推荐
相关产品推荐

