看《The C Programming Language》中關於scanf函數部分時隨意敲了幾行代碼,本以為簡單的不得了,都有點“不屑於”敲,卻沒想到這一敲竟然敲出個不小的問題,涉及到好多東西啊,哈哈!下面把我這次的經歷和大家分享一下,希望也能對大家有所幫助。
一、代碼實例
我當時敲的代碼:
點擊(此處)折疊或打開
#include<stdio.h>
int main()
{
int a;
int b;
char mon[20];
int count;
count = scanf("%d,%s,%d", &a,mon,&b);
printf("%d,%s,%d\n",a,mon,b);
printf("%d\n",count);
return 0;
}
運行結果:
ocean@ocean-desktop:~/桌面$ ./re
12,fefe,45 /*這是我的輸入*/
12,fefe,45,10359588
2
結果看起來挺像我們想要的結果的,只是最後多了個奇怪的數字;但仔細看下count的值我們就納悶了,怎麼是2不是3呢?怎麼scanf只讀了兩個值?到底怎麼回事呢?先用gdb調試一下吧,看看a和mon裡都是些什麼。
二、GDB調試情況
(gdb) p a
$1 = 12
(gdb) p mon
$2 = "fe,45\000\377\277\245\324\025\000\060\340\021\000K\205\004\b"
明白了吧?原來fe,45作為一個整體被存到mon裡了,b根本沒讀到值,顯示了個原內存裡的亂七八糟的數值(不相信的話可以在程序開頭給b賦個值,最後結果肯定是輸出當初賦的值,因為根本沒有給b讀入新的值),scanf真的只讀了兩個值,所以count顯示2。那為什麼會這樣呢?讓我們來看看scanf函數的相關信息吧。
三、scanf函數工作原理
scanf()是從輸入流緩沖區中讀取值的,而並非從鍵盤(也就是終端)緩沖區讀取。往輸入流緩沖區送數據是遇到回車(\n)而結束的,這個\n會一起讀入輸入流緩沖區。scanf() 開始讀取輸入以後,會在遇到的第一個空白字符空格(blank)、制表符(tab)或者換行符(newline)處停止讀取。
格式控制字符串中有普通字符(非格式字符)時,這些字符作為輸入數據的分隔符,在scanf函數讀入數據時自動去掉。
scanf()格式控制字符串中如果使用%s說明符,那麼空白字符以外的所有字符都是可以接受的,所以scanf() 跳過空白字符直到遇到第一個非空白字符,然後保存再次遇到空白字符之前的所有非空白字符。這就意味著%s使scanf() 讀取一個單詞,也就是說,一個不包含空白字符的字符串。
好,讓我們分析下上述的結果是如何出現的吧。
四、原因分析
首先,scanf()跳過空白字符(這裡沒有,因為第一個字符就是1)直到遇到一個非空白字符1,然後繼續讀2,讀到逗號這個非數字符號時scanf知道整數讀完了,將12賦給a,此時輸入流緩沖區中第一個開頭的字符是逗號;scanf繼續讀,讀到逗號與格式控制字符串的逗號匹配,pass;從f繼續讀,一直讀到下一個空白符——我們結束時敲的回車(scanf自動把這個回車符去掉了,沒有送到字符串裡),字符串讀完了,此時輸入流緩沖區裡第一個開頭的字符是我們敲的回車符;繼續讀,回車符與格式控制字符串裡的逗號不批配,讀取失敗,不讀了。 綜上所述,scanf確實只讀了一個整數和一個字符串,返回值是2。www.2cto.com
那有什麼辦法實現用逗號作為間隔符的情況呢?下面提供兩種方法:
五、解決方法
法1:
scanf("%d,%[^,],%d", &a,mon,&b);
printf("%d,%s,%d\n",a,mon,b);
相關知識:scanf中一種很少見但很有用的轉換字符:[…]和[ ^…]
%[…]如果輸入的字符屬於方括號內字 符串中某個字符,那麼就提取該字符;如果一經發現不屬於就結束提取。%[^…]如果一經發現輸入的字符屬於方括號內字符串中某個字符,那麼就結束提取;如果不屬於就提取該字符。這兩種方法會自動加上一個字符串結束符到已經提取的字符後面。例如:
點擊(此處)折疊或打開
#include<stdio.h>
main()
{
char strings[100];
scanf("%[1234567890]",strings);
printf("%s",strings);
return 0;
}
運行,輸入:1234werew後,結果是:1234。
采用這種方法,讀完fefe後遇到逗號便結束字符串的讀取,繼續讀時輸入流緩沖區的逗號與格式控制字符串中逗號剛好匹配,成功!
法2(不夠徹底):
scanf("%d,%s ,%d", &a,mon,&b); /*注意%s後面有個空格 */
printf("%d,%s,%d\n",a,mon,b);
並且在輸入時加個空格
12,fefe ,45 /*fefe和逗號之間加個空白*/
相關知識:當scanf()格式控制字符串中出現空白時,表示取數時跳過任何空白。
scanf讀到fefe後的空格後結束字符串的讀取,此時輸入流緩沖區第一個字符為空格;繼續讀,由於格式控制字符串裡有個空格,所以讀取時會跳過任何空白(不信可以在fefe後面多敲幾個空白試試,全都跳過,甚至連回車都跳過),讀到逗號匹配成功。
摘自 家裡蹲博客