scanf()函數分析


首先,先來講一下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

 

如果你覺得對你有一絲的幫助,請點贊哦  ^^

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM