[英]How do scanf and getchar work in C?
這讓我很困惑。
# include <stdio.h>
# include <limits.h>
int main()
{
int a;
int b;
printf("Enter two integers: ");
while(scanf("%d %d", &a, &b)!=2||b==0||a+b>INT_MAX||a*b>INT_MAX){
printf("Invalid entry, please re-enter: ");
while(getchar()=='\n');
}
printf("sum is %d, difference is %d, product is %lf, divid is %.2f, remainder is %d", a+b, a-b, (double)a*b, (float)a/b, a%b);
return 0;
}
使用上面的代碼,如果我輸入“a 1”,請按ENTER:
輸入無效,請重新輸入:
彈出,然后我輸入“2 B”按ENTER鍵,最后一個printf
將執行。
但是,如果我改變while(getchar()=='\\n');
to while(getchar()!='\\n');
,並使用相同的條目(我輸入“1”按ENTER鍵)
輸入無效,請重新輸入:
彈出,然后我輸入“2 B”按ENTER),最后一個printf
將不會執行,並且
輸入無效,請重新輸入:
再次彈出。
是什么導致這種差異? scanf
和getchar
究竟是如何工作的?
scanf()和getchar()讀取輸入緩沖區中的內容(標准輸入的標准輸入)。 當stdin為空時,程序將等待用戶用鍵盤寫東西。 當您按ENTER鍵時,您剛寫入的文本存儲在stdin中。 然后scanf()或getchar()可以讀取stdin中的內容。 請注意,按ENTER將在stdin中存儲'\\ n'字符(換行符)。 像while( getchar() != '\\n' );
這樣的代碼while( getchar() != '\\n' );
要求getchar()從stdin中讀取一個字符,而字符不是'\\ n'。 它將getchar()的返回值與'\\ n'進行比較。 所以這是一種“清理”輸入緩沖區的方法,否則你的程序會發瘋。
使用你發布的代碼:scanf()被調用,你寫“a 1”,它試圖讀取第一個整數,但它是一個字符('a'),所以它停止讀取。 printf()要求你重新輸入,然后調用getchar()並讀取'a'。 現在scanf()被第二次調用,讀取1,然后你必須輸入一些東西,你輸入“2 B”,所以scanf()中的第二個%d可以讀取2.現在scanf()的返回值為2 ,b不為0,其他條件為假,因此循環結束。 請注意,'B'字符仍然在stdin :)
scanf和getchar如何在C中工作?
可悲的是,他們往往不能很好地合作 。
代碼是在輸入文本出現問題時嘗試使用輸入行的其余部分的一個不好的示例。
如果scanf("%d %d", &a, &b)
無法在2 int
掃描,則會出現提示並使用getchar
讀取輸入,直到Enter或'\\n
'發生。
如果掃描了2個int
,則對a,b
執行各種錯誤測試
// poor code
while(scanf("%d %d", &a, &b)!=2||b==0||a+b>INT_MAX||a*b>INT_MAX){
printf("Invalid entry, please re-enter: ");
while(getchar()=='\n');
}
問題是代碼肯定打算讀取一行用戶輸入然后驗證它。 不幸的是,當沒有掃描2個int
時, scanf("%d %d"
可以消耗多個'\\n'
並且使stdin
內容不清楚。代碼是文件末尾的無限循環。
最好用fgets()
讀取一行輸入。 刷新stdout
確保在讀取輸入之前看到提示。
char buf[80];
const char *prompt = "Enter two integers: ";
for (;;) {
fputs(prompt, stdout);
fflush(stdout);
if (fgets(buf, sizeof buf, stdin) == NULL) Handle_EndOfFile_or_Error();
prompt = "Invalid entry, please re-enter: ";
int n;
if (sscanf(buf, "%d%d %n", &a, &b, &n) != 2) continue; // not 2 ints
if (buf[n]) continue; // extra text
if ((a < 0) ? (b < INT_MIN - a) : (b > INT_MAX - a)) continue; // + overflow
... // other tests
else break;
}
在第一種情況下( while (getchar() == '\\n');
), getchar()
讀取a
,但它不是換行符,因此循環退出,留下空格和輸入中的1
緩沖。 重復調用scanf()
跳過空格,讀取1
,跳過空白區域(包括換行符)並讀取2
,在輸入中留下空格和B
由於循環條件現在終止( scanf()
返回2
),因此執行printf()
。
在第二種情況下( while (getchar() != '\\n');
),此循環在停止之前讀取a
,空白, 1
和換行符。 當您鍵入2 B
,沒有兩個數字,因此scanf()
返回1
並且主循環繼續。
請注意,如果您指定EOF(通常是Unix上的Control-D ,Windows上的Control-Z ),您的代碼將進入無限循環 - 至少在大多數系統上。 你應該總是考慮EOF。 在上下文中,您可能需要以下內容:
int rc;
while (((rc = scanf(…)) != 2 && rc != EOF) || …)
你也可以在打印之前測試rc
和EOF
。
我試着總結一下你需要知道的東西。
首先,關於你的問題。 你知道scanf
的功能是讀取我們給出的輸入(數字)對嗎? 另一方面, getchar
就像scanf
只是它只用於字符/句子。 您不能使用getchar
輸入數字。
其次,你的代碼沒有問題,除了可以不使用像getchar
行。 也可以不使用while。 除非您想要制定某些條件,否則您可以使用if
/ else
函數進行組合。
第三,你不能像你那樣輸入數字:“ 1 a
”,“ 2 b
”。 這些被認為是無效的。 這是因為您在scanf
中使用的%d
僅指十進制數。 這意味着,您只能輸入數字1-9而不能輸入字母。 因此,當程序要求輸入2個整數時,您只需鍵入例如: 4 5
。 那是4
,空間, 5
。 這是正確的方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.