#include <stdio.h>
int main()
{
int sum=0;
char s[10];
while(scanf("%[^\n]s", s)!=EOF)
{
printf("%s", s);
}
return 0;
}
此while循環落入任何字符串輸入的無限循環。爲什麼這個c程序陷入無限循環?
#include <stdio.h>
int main()
{
int sum=0;
char s[10];
while(scanf("%[^\n]s", s)!=EOF)
{
printf("%s", s);
}
return 0;
}
此while循環落入任何字符串輸入的無限循環。爲什麼這個c程序陷入無限循環?
鑑於
while(scanf("%[^\n]s", s)!=EOF)
{
printf("%s", s);
}
你問「?爲什麼這個C程序陷入無限循環」
因此,您必須瞭解scanf()
的工作原理。 scanf()
使用您的格式字符串解析來自stdin
的輸入,這是一個流,它可以按字符提供字符。
假設你已經在stdin
如下:
foo\n
bar\n
<<EOF>>
現在您的格式字符串有這種轉換%[^\n]
這意味着「匹配任何東西,但換行,並複製到一個字符緩衝區」。 s
後面的文字只是一個字面s
,因爲它前面沒有%
...所以如果有的話它會與字面s
相匹配。換句話說,這裏沒關係。
現在,第一次打電話給你的scanf()
,它將匹配foo
並使用它。它返回1
,因爲它匹配了一個元素。在此之後,stdin
看起來是這樣的:
\n
bar\n
<<EOF>>
注無與倫比的換行符仍然存在。您的下一個電話將再次以格式字符串開頭,以匹配,但換行符,但下一個字符是換行符。 scanf()
什麼都不匹配,因此返回0
。它不能返回EOF
,因爲如您所見,EOF
尚未到達。這是你的無限循環。
所以,你必須修復你的格式字符串。首先,刪除不匹配任何東西的s
。它在這裏並沒有真正受到傷害,但它仍然是錯誤的。然後,您可以利用空白匹配的scanf()
。空格是空格,標籤或換行。如果你的格式字符串包含空格,scanf()
將與一樣多的空格匹配(這也可以不是)。因此,一個簡單的辦法是隻啓動格式字符串用空格,這將「吃」的遺留的換行符:
while(scanf(" %[^\n]", s)!=EOF)
{
printf("%s", s);
}
現在這仍然是危險代碼,因爲[^\n]
匹配任何量字符,只要沒有換行符,但是緩衝區只有9個字符的空間加上終止0
。所以,你必須告訴scanf()
不超過該限制匹配更多,這可以通過將%
和轉換規範之間的數量來完成:
while(scanf(" %9[^\n]", s)!=EOF)
{
printf("%s", s);
}
該代碼會做你想做的事,安全的方式,但假設你想匹配更具體的東西,例如數字,你會得到一些意想不到的輸入:通過等待EOF
,你會再次有你的無限循環,因爲有輸入不匹配,所以你永遠不能達到EOF
(如上面與無與倫比的換行符)。因此,請始終檢查成功匹配的數量。在這裏,您希望只有一個匹配,因此該循環應該是這樣的:
while (scanf(" %9[^\n]", s) == 1)
{
printf("%s", s);
}
在實踐中,讀取整行,你不需要scanf()
,只是用fgets()
會更容易些。你的代碼可能看起來如此簡單(新行會被讀入s
以及):
while (fgets(s, 10, stdin))
{
printf("%s", s);
}
注意第二個參數10
這裏:fgets()
會自動考慮終止0
角色,所以你只要給它的大小你的緩衝區。
只是最後提示:這可能是即使不使用printf()
簡單時沒有格式化的事:
while (fgets(s, 10, stdin))
{
fputs(s, stdout);
}
正如你所說,最好使用'fgets()'。其次,使用'scanf()'是比較返回值與預期賦值的數量,而不是'EOF':'while(scanf(「%9 [^ \ n]」,s)== 1){/ * ... * /}' – pmg
@pmg謝謝,很好,我延長了答案。 –
int main()
{
int sum = 0;
char s[10];
int ret = scanf("%[^\n]s", s);
while (ret != EOF)
{
printf("%s", s);
memset(s,0,10);
ret = scanf("%[^\n]s", s);
}
return 0;
}
隨着調試,你可以看到第二個ret值在while塊爲0,也就是說,並不等於EOF,所以無限循環。
人scanf函數:
返回值
成功完成後,這些函數將返回成功匹配和分配的輸入項目的數量;如果發生早期匹配失敗,此數字可能爲零。
這意味着其他scanf匹配失敗,除了第一個。
但是爲什麼?
stdio有緩存,匹配只讀取stdin中的「\ n」,但是當你輸入「Enter」時,它會輸入「\ n \ r」,所以「\ r」會在stdin緩存併成爲其他scanf的輸入值,但無法匹配輸入,所以匹配失敗。並且scanf返回0,並且轉到無限循環。
但是,如果您只爲每個輸入輸入「\ n」,那沒關係!
你可以按「Alt」,同時按下「0」+「1」+「0」,釋放「Alt」,控制檯將只輸入「\ n」結果,程序會OK,不會進入無限循環!
這是我的測試結果:enter image description here
如果使用「scanf(」%[^ \ r \ n] s「,s);」 scanf也可以從無限循環停止,但不能再輸入。 – Jimmy
這是完全錯誤的。請注意'\ n'是C **中的換行符**,並且在文本模式下閱讀時,任何特定於平臺的換行符都被轉換爲'\ n'。另請注意,windows換行符是'\ r \ n',而不是'\ n \ r'。它繼續:'%[^ \ n]'不匹配換行符,它匹配*任何**,但**換行符* –
我不確定現在,我嘗試使用此scanf:「scanf(」 [^ \ n] s「,s);」 (開頭有空格),結果與「scanf(」%[^ \ r \ n] s「,s)一樣;」它可以停止循環,但不能再輸入。 – Jimmy
我們應該有一些*初學者從'scanf函數導遠()'*。對於初學者來說,'s'是錯誤的,因爲'[]'已經是一個轉換,'scanf()'會在它後面尋找一個字面的's'。 –
然後,當你解決這個問題時,你必須處理在第一個'scanf()'後面留下的換行符。 –
第二次拒絕'scanf(「%[^ \ n] s」,s)''中的換行符'然後相同。 – BLUEPIXY