我碰到下面的代碼來:C:在scanf行爲for循環
int i;
for(; scanf("%s", &i);)
printf("hello");
按我的理解,如果我們提供的整數輸入scanf
將在閱讀不成功,因此返回0,所以環形不應該運行一次。然而,它通過接受所有類型的輸入作爲成功讀取而無限運行。
有人會好心解釋這種行爲嗎?
我碰到下面的代碼來:C:在scanf行爲for循環
int i;
for(; scanf("%s", &i);)
printf("hello");
按我的理解,如果我們提供的整數輸入scanf
將在閱讀不成功,因此返回0,所以環形不應該運行一次。然而,它通過接受所有類型的輸入作爲成功讀取而無限運行。
有人會好心解釋這種行爲嗎?
這是int
的錯誤格式說明符:應爲"%d"
。
它試圖將一個字符串讀入一個int
變量,可能會覆蓋內存。由於指定了"%s"
,因此將讀取所有輸入,因此scanf()
會返回大於零的值。
(編輯:。我不覺得這個答案應該被接受Upvoted可能,但不接受它並不能解釋無限循環可言,@hmjd確實是)
(這實際上並沒有回答這個問題,其他的答案做到這一點,但它是有趣和良好的就知道了。)
由於hmjd說,使用scanf
這樣會覆蓋內存("smash the stack"),因爲它開始寫i
在內存,然後繼續前進,即使在i
佔用的4字節內存(或8字節,在64位平臺上)之外。
爲了說明,考慮下面的代碼位:
#include<stdio.h>
int main() {
char str_above[8] = "ABCDEFG";
int i;
char str_below[8] = "ABCDEFG";
scanf("%s", &i);
printf("i = %d\n", i);
printf("str_above = %s\nstr_below = %s\n", str_above, str_below);
return 0;
}
編譯和運行它,並輸入1234567890
產生以下輸出:
i = 875770417
str_above = 567890
str_below = ABCDEFG
幾點:
i
與整數幾乎沒有對應關係(它與字符'1'
,...,'4'
的值以及系統的字節順序有關)。str_above
已被修飾以通過scanf
:字符'5'
,...,'0'
,'\0'
已溢出的記憶保留i
塊的端部與已被寫入爲str_above
保留的存儲器。str_above
稍後存儲在內存中,而i
以及str_below
存儲在內存中。 (換一種方式&str_above > &i
和&str_below < &i
。)這是爲「緩衝區溢出攻擊」,其中在棧上的值是由過多的數據寫入到一個數組修改的基礎。這就是爲什麼gets
是危險的(並且應該使用從不使用)並且使用scanf
與通用的%s
格式說明符也不應該完成。
請參閱我的答案頂部的編輯。 :) – huon