scanf 函式分析

2022-01-25 14:12:12 字數 3647 閱讀 3293

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

intmain()

輸入和輸出結果為:

可以看到我在相鄰的兩個待輸入字段之間新增了多個空白符,但是這並不會影響輸入(當有%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 #include 

intmain()

與上乙個例子不同的是第乙個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 #include 

intmain()

這次我們在第乙個%d和逗號之間新增了乙個\n(其實只要是空白符即可)。

輸入輸出結果

這次我們發現在95和逗號之間新增了多個空白符也正確,這是因為新增的\n會讓scanf()跳過%d和逗號之間的空白符。將\n換成空格也是正確的(只要是空白符就行)

比如換成空格:

#include #include 

intmain()

最後看一種含有%c的情況

我們輸入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)

結果是正確   ^^

先寫到這裡啦,有問題再補充。。

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

補充:當scanf中使用數字修飾限制欄位的長度時,遇到空白符(或非法字元)或者達到字段長度(二者滿足乙個即可)就意味著這個字段讀取完成了

再補充一點,關於scanf的返回值,scanf返回正確讀入資料的個數。0表示乙個都沒有正確輸入,eof表示讀到了eof,在linux中ctrl+d表示eof

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

scanf函式分析

scanf 是c語言中的乙個輸出函式。與printf函式一樣,都被宣告在標頭檔案stdio.h裡,因此在使用scanf函式時要加上 include 在有一些實現中,printf函式與scanf函式在使用時可以不使用預編譯命令 include 它是格式輸入函式,即按使用者指定的格式從鍵盤上把資料輸入到...

OSTaskCreate()函式分析

int8u ostaskcreate void task void pd void p arg,os stk ptos,int8u prio 函式返回乙個8位的整型數,呼叫該函式需要四個引數。第乙個引數乙個指標,也就是使用者 的首位址,在平時使用中我們把自己建立的任務的名字作為這個引數就可以了 第三...

getopt函式分析

函式getopt主要用於拆分命令列引數,用這個函式就不自己寫命令列引數解析程式了,以下 摘自tcpdump原始碼,對這個函式比較感興趣,故對此進行分析注釋,因水平實在不敢恭維,不足之處希望能一起 函式getopt 有三個引數,nargc,nargv就是命令列傳過來的argc和argv字串ostr,它...