首先,先來講一下scanf的讀取流程:
從鍵盤輸入的都是字符類型(一系列的字符),scanf()的作用就是將這個字符序列轉換成一個或多個指定的類型,並保存到變量中。
從鍵盤輸入的字符序列會先緩存到鍵盤緩沖區中,當用戶輸入回車,這時會清空鍵盤緩沖區,將鍵盤緩沖區的數據(包括回車)送入到stdin中
這時scanf()開始從stdin中讀取數據。
scanf()在讀取每個字段時都會忽略空白符(%c比較特殊)。以%d為例,scanf()會先忽略stdin中的空白符,直到遇到第一個0-9開始讀取,如果后面的字符依然是0-9就繼續讀取,直到遇到空白符或者非0-9的字符,scanf認為%d的讀取完畢,將讀取的字符序列轉換成十進制整型保存到變量中。最后遇到的空白符或非法字符將返回到stdin中去。
如果忽略掉前面的空白符后第一個遇到的是非法的字符(非0-9),比如a,這時a會被返回到stdin中,程序也將會跳出scanf()函數(不管%d后面是否還存在帶輸入項,如另一個%d,都會跳出整個scanf()函數)。
看一個例子:
#include <stdio.h> #include <stdlib.h> int main() { int a=123; int b=11; char c[10]; printf("請輸入:\n"); scanf("%d%d",&a,&b); scanf("%s",c); printf("a=%d,b=%d,c=%s\n",a,b,c); return 0; }
輸入和輸出結果為:
可以看到我在相鄰的兩個待輸入字段之間添加了多個空白符,但是這並不會影響輸入(當有%c的時候會有影響),這就是因為scanf()在讀取每個待輸入字段前都會跳過前面的空白符。
同樣的程序,在看一組輸入和輸出結果。
這個我先輸入了一個對於%d是非法的字符s,第一個scanf()讀取的時候會先跳過s前面的空白符,然后遇到s,發現s與%d不能匹配,這時候就會將s返回到stdin中,並跳過第一個scanf(),所以我們看到a和b的值都沒有被改變,然后開始執行第二個scanf(),這個時候遇到的第一個字符是s(之前scanf返回到stdin中),然后接着讀取,1、2、3、4知道遇到空白符,認為%s讀取結束,將讀入的字符序列轉換稱一個字符串(添加上'\0'),然后保存到c所指的地址中。
再來看一個格式字符串中含有普通字符的例子。
#include <stdio.h> #include <stdlib.h> int main() { int a=123; int b=11; char c[10]; printf("請輸入:\n"); scanf("%d,%d",&a,&b); scanf("%s",c); printf("a=%d,b=%d,c=%s\n",a,b,c); return 0; }
與上一個例子不同的是第一個scanf()的兩個%d之間多個一個",",這時在輸入的時候要特別注意也要輸入這個逗號,而且這個逗號相對於前一個%d的位置也要准確,否則scanf()就會讀取失敗,然后跳出這個scanf().
看一個正確的輸入:
如果我們輸入的時候95后面跟的不是逗號(全半角錯誤也不行),scanf就會讀取失敗,然后將該字符返回到stdin中,然后跳過這個scanf。
看一個錯誤的輸入
這次輸入時95后面的是中文形式的逗號,與代碼中英文形式的逗號不匹配,這個時候就會出錯,然后中文的逗號就會被返回到stdin中,並跳出第一個scanf,開始第二個scanf(),所以b的值沒有讀取進去。而c的值中也含有第一個scanf()返回到stdin中的逗號。
再看一中錯誤的輸入:
這次在95后面添加了幾個空白符,然后才是逗號。前面強調scanf在讀取每個待輸入的字段的時候都會跳過空白符,但是要明白,對於第一個scanf(),它的待輸入項就是兩個%d,逗號並不是它的待輸入項,所以逗號前面的空白符不會被跳過,所以出現了和代碼中的逗號不匹配的情況(實際的輸入是空格),所以也會像前一種情況一樣讀取錯誤,並跳過第一個scanf。
再看一種正確的輸入:
這個輸入中我們在逗號后面添加了多個空格,發現輸入時正確的。這是因為這些空格位於第二個%d的前面,也就是說位於第二個待輸入項的前面,這時scanf就會跳過這些空白符。
再看一種代碼:
#include <stdio.h> #include <stdlib.h> int main() { int a=123; int b=11; char c[10]; printf("請輸入:\n"); scanf("%d\n,%d",&a,&b); scanf("%s",c); printf("a=%d,b=%d,c=%s\n",a,b,c); return 0; }
這次我們在第一個%d和逗號之間添加了一個\n(其實只要是空白符即可)。
輸入輸出結果
這次我們發現在95和逗號之間添加了多個空白符也正確,這是因為添加的\n會讓scanf()跳過%d和逗號之間的空白符。將\n換成空格也是正確的(只要是空白符就行)
比如換成空格:
#include <stdio.h> #include <stdlib.h> int main() { int a=123; int b=11; char c[10]; printf("請輸入:\n"); scanf("%d ,%d",&a,&b); scanf("%s",c); printf("a=%d,b=%d,c=%s\n",a,b,c); return 0; }
最后看一種含有%c的情況
#include <stdio.h> #include <stdlib.h> int main() { int a=123; int b=11; char c; printf("請輸入:\n"); scanf("%d,%d",&a,&b); scanf("%c",&c); printf("a=%d,b=%d,c=%c\n",a,b,c); return 0; }
我們輸入95,21回車,scanf的讀取流程是這樣的:
首先遇到95然后遇到逗號,發現逗號和%d不匹配,就將95轉換成整型保存到a中,並將逗號返回到stdin中,然后繼續讀取,讀取到逗號(剛剛返回到stdin中的)發現和代碼中的逗號匹配,所以會跳過這個逗號,然后讀取到21,然后是回車,發現空白符,則認為第二個%d讀取結束,所以講21轉換成整型保存到b中,並返回空白符回車到stdin中,接着開始進行第二個scanf函數,其中%c可以讀取任何字符(通吃啦),所以空白符對於%c來說是合法的,回車自然也是合法的,所以它就將回車保存到了c中。所以我們看到輸出結果中c的內容為空,但是Press any key to continue前面有一行空行,這實際上就是讀入到c中的換行符。
所以如果我們輸入的是95,21空格(多個)x回車,那么空格就將被讀入到c中,除了第一個空格,其余的字符還在stdin中:
那么怎么解決這種問題呢? 因為畢竟我們想讓c讀取x,而並不是空格。
一種可能的解決方法是在第一個scanf()的最后一個%d后面加入一個空白符(空格、\n、\t都是可以的),以吸收21和x之間的空白符。(我才用的是\n)
#include <stdio.h> #include <stdlib.h> int main() { int a=123; int b=11; char c; printf("請輸入:\n"); scanf("%d,%d\n",&a,&b); scanf("%c",&c); printf("a=%d,b=%d,c=%c\n",a,b,c); return 0; }
結果是正確 ^^
先寫到這里啦,有問題再補充。。
如果你覺得對你有一絲的幫助,請點贊哦 ^^
補充:當scanf中使用數字修飾限制字段的長度時,遇到空白符(或非法字符)或者達到字段長度(二者滿足一個即可)就意味着這個字段讀取完成了
再補充一點,關於scanf的返回值,scanf返回正確讀入數據的個數。0表示一個都沒有正確輸入,EOF表示讀到了EOF,在linux中Ctrl+D表示EOF
如果你覺得對你有一絲的幫助,請點贊哦 ^^