最近重讀了一下《C陷阱與缺陷》,發現一道題挺有意思的,這道題是一段簡單的代碼,如下所示:
#include <stdio.h>
int main(){
int i;
char c;
for(i = ;i < ;i++){
scanf("%d",&c);
printf("%d",i);
}
printf("\n");
return ;
}
注意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