最簡單的辦法是一家領先的空間scanf()
添加到格式字符串。例如,如果要提示用戶提供了錯誤的輸入時再輸入一個字符,你可以這樣做:
沒有與這種簡單的方法有問題,但。如果用戶輸入"aaap"
然後輸出結果將是:
Enter "p" if you want to sort and shuffle a list of players or enter "s" if you want to sort a list of slots: aaap
Please enter "p" or "s": Please enter "p" or "s": Please enter "p" or "s": You chose p
Choose "a"scending or "d"escending sort:
或者更糟的是,如果用戶輸入正確的第一個字符,後跟其他字符,如"sfffa"
:
Enter "p" if you want to sort and shuffle a list of players or enter "s" if you want to sort a list of slots: sfffa
You chose s
Choose "a"scending or "d"escending sort: Please enter "a" or "d": Please enter "a" or "d": Please enter "a" or "d": You chose a
因爲scanf()
葉輸入流中不匹配的字符,必須在再次讀取輸入流之前處理這些字符。在使用" %c"
的簡單解決方案中,初始空間導致scanf()
跳過前導空格字符,但將拾取其他任何字符。在現實世界中,您不能指望用戶通過提供良好行爲的輸入來進行合作。
一個典型的便攜式解決方案是在循環中使用getchar()
來清除輸入操作後的輸入流。您可能需要改變輸入迴路的邏輯有點做到這一點:
#include <stdio.h>
...
char tmp;
int c;
int scanf_ret;
do {
printf("Enter \"p\" if you want to sort and shuffle a list of players "
"or enter \"s\" if you want to sort a list of slots: "); // prompt
scanf_ret = scanf("%c", &tmp);
while ((c = getchar()) != '\n' && c != EOF) {
continue; // discard extra characters
}
} while (scanf_ret != 1 || (tmp != 'p' && tmp != 's'));
調用scanf()
後,進入一個循環,讀取並丟棄剩餘的輸入流中的任何字符。請注意,c
是int
,並且EOF
在循環中進行了明確測試。如果發生錯誤,或者用戶從鍵盤發出信號EOF
,或者輸入已從文件重定向,則getchar()
功能可能會返回EOF
。在這種情況下未能測試EOF
將導致無限循環條件。
即使用戶輸入了不可預知的輸入,該解決方案也能正常工作,因爲輸入流在輸入後總是被清除。並且請注意,不需要格式字符串中的前導空格。另一種解決方案是使用fgets()
將一行輸入讀入緩衝區,並使用sscanf()
來解析緩衝區。
#include <stdio.h>
#include <stdlib.h>
...
char buffer[1000];
char tmp;
int sscanf_ret;
do {
printf("Enter \"p\" if you want to sort and shuffle a list of players "
"or enter \"s\" if you want to sort a list of slots: "); // prompt
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
fprintf(stderr, "Error in fgets()\n");
exit(EXIT_FAILURE);
}
sscanf_ret = sscanf(buffer, "%c", &tmp);
} while (sscanf_ret != 1 || (tmp != 'p' && tmp != 's'));
的fgets()
函數獲取輸入的一整行,通過換行,或從輸入流中獲取(sizeof buffer) - 1
字符,如果緩衝器不是足夠大以容納所有字符的輸入流中和\0
終止子。通過提供一個大小緩衝區,這應該工作得很好。用戶仍然可以輸入大量的字符,並且這不會溢出緩衝區,但字符會留在輸入流中以供下一次讀取操作查找。爲避免此類問題,如果還有多餘的字符,應在使用上面的getchar()
循環調用fgets()
後清除輸入流。
所有這些技術都有它們的位置。顯然,最後兩個比第一個更健壯,並且由於用戶不太可能在輸入提示符(包括換行符)處輸入999個字符,它們幾乎是平等的。但是,爲了避免所有的驚喜,在獲得用戶輸入之後明確地清除輸入流是最好的。
你有沒有做過任何基本的調試?就像使用調試器和/或調試打印語句來找出'tmp'在工作和不工作時需要什麼值? – kaylum
它在我的系統上正常工作。 – Jarvis
在此之前你讀過什麼?在輸入中是否留下換行符?你應該考慮使用'if(scanf(「%c」,&tmp)!= 1){...句柄錯誤...}'%c'之前的空格不是偶然的 - 它跳過空格(空格,換行符),並等待輸入其他內容(「p」或「s」)。 –