C陷阱与缺陷中有关scanf的一道题

来源:互联网 发布:ubuntu下安装sqlyog 编辑:程序博客网 时间:2024/05/17 03:30

最近重读了一下《C陷阱与缺陷》,发现一道题挺有意思的,这道题是一段简单的代码,如下所示:

#include <stdio.h>int main(){    int i;    char c;    for(i = 0;i < 5;i++){        scanf("%d",&c);        printf("%d",i);    }    printf("\n");    return 0;}

注意scanf(“%d”,&c),在读入时分两种情况:
(1)读入时是数字,此时程序会陷入死循环,读入一个数字就输出一个0,造成这种情况的原因是在字符c的地址上,程序以“%d”存储了一个整型数据,而字符c本来是一个字节,假设int占四个字节(我的机器上这样的),那么字符c的地址附近的内存会被覆盖。下面以图形化的形式说明这种情况

(gdb调试程序)

若当前时刻i = 1,打印i的地址是0xbffff3fc,c的地址是0xbffff3fb,未执行scanf时的内存内容如下

内容(从内存地址开始的四个字节内容) 内存地址 0x01 0x00 0x00 0x00 0xbffff3fc 0x01 0x01 0x00 0x00 0xbffff3fb

执行了scanf以后(假设读入了数字5),内存的情况如下图所以

内容(从内存地址开始的四个字节内容) 内存地址 0x00 0x00 0x00 0x00 0xbffff3fc 0x05 0x00 0x00 0x00 0xbffff3fb

显然,在执行完scanf后,从地址0xbffff3fb开始的四个字节被0x05 0x00 0x00 0x00 覆盖了,变量i的低端部分被置0,而i的高端部分本身就是0,那么此时i的值就变成了0,i的值始终都在0和1之间,就形成了最后的死循环。

(2)读入的是非数字的字符,那么scanf就会遇到读入数据与scanf期待的%d类型不符,导致stdin流出现堵塞,下次循环将不再读入数据除非清空stdin缓冲区,最终导致的结果就是直接输出01234

1 0
原创粉丝点击