C语言scanf函数奇遇记
C語(yǔ)言scanf函數(shù)奇遇記
作者:ocean??? 撰寫日期:2011-11-20
博客鏈接:http://oceanspace.tk
?
? ? 看《The C Programming Language》中關(guān)于scanf函數(shù)部分時(shí)隨意敲了幾行代碼,本以為簡(jiǎn)單的不得了,都有點(diǎn)“不屑于”敲,卻沒想到這一敲竟然敲出個(gè)不小的問題,涉及到好多東西啊,哈哈!下面把我這次的經(jīng)歷和大家分享一下,希望也能對(duì)大家有所幫助。
一、代碼實(shí)例
我當(dāng)時(shí)敲的代碼:
#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;
}
運(yùn)行結(jié)果:
ocean@ocean-desktop:~/桌面$ ./re
12,fefe,45?? /*這是我的輸入*/
12,fefe,45,10359588
2
?????? 結(jié)果看起來挺像我們想要的結(jié)果的,只是最后多了個(gè)奇怪的數(shù)字;但仔細(xì)看下count的值我們就納悶了,怎么是2不是3呢?怎么scanf只讀了兩個(gè)值?到底怎么回事呢?先用gdb調(diào)試一下吧,看看a和mon里都是些什么。
二、GDB調(diào)試情況
(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作為一個(gè)整體被存到mon里了,b根本沒讀到值,顯示了個(gè)原內(nèi)存里的亂七八糟的數(shù)值(不相信的話可以在程序開頭給b賦個(gè)值,最后結(jié)果肯定是輸出當(dāng)初賦的值,因?yàn)楦緵]有給b讀入新的值),scanf真的只讀了兩個(gè)值,所以count顯示2。那為什么會(huì)這樣呢?讓我們來看看scanf函數(shù)的相關(guān)信息吧。
三、scanf函數(shù)工作原理
?????? scanf()是從輸入流緩沖區(qū)中讀取值的,而并非從鍵盤(也就是終端)緩沖區(qū)讀取。往輸入流緩沖區(qū)送數(shù)據(jù)是遇到回車(\n)而結(jié)束的,這個(gè)\n會(huì)一起讀入輸入流緩沖區(qū)。scanf() 開始讀取輸入以后,會(huì)在遇到的第一個(gè)空白字符空格(blank)、制表符(tab)或者換行符(newline)處停止讀取。
?????? 格式控制字符串中有普通字符(非格式字符)時(shí),這些字符作為輸入數(shù)據(jù)的分隔符,在scanf函數(shù)讀入數(shù)據(jù)時(shí)自動(dòng)去掉。
?????? scanf()格式控制字符串中如果使用%s說明符,那么空白字符以外的所有字符都是可以接受的,所以scanf() 跳過空白字符直到遇到第一個(gè)非空白字符,然后保存再次遇到空白字符之前的所有非空白字符。這就意味著%s使scanf() 讀取一個(gè)單詞,也就是說,一個(gè)不包含空白字符的字符串。
?????? 好,讓我們分析下上述的結(jié)果是如何出現(xiàn)的吧。
四、原因分析
?????? 首先,scanf()跳過空白字符(這里沒有,因?yàn)榈谝粋€(gè)字符就是1)直到遇到一個(gè)非空白字符1,然后繼續(xù)讀2,讀到逗號(hào)這個(gè)非數(shù)字符號(hào)時(shí)scanf知道整數(shù)讀完了,將12賦給a,此時(shí)輸入流緩沖區(qū)中第一個(gè)開頭的字符是逗號(hào);scanf繼續(xù)讀,讀到逗號(hào)與格式控制字符串的逗號(hào)匹配,pass;從f繼續(xù)讀,一直讀到下一個(gè)空白符——我們結(jié)束時(shí)敲的回車(scanf自動(dòng)把這個(gè)回車符去掉了,沒有送到字符串里),字符串讀完了,此時(shí)輸入流緩沖區(qū)里第一個(gè)開頭的字符是我們敲的回車符;繼續(xù)讀,回車符與格式控制字符串里的逗號(hào)不批配,讀取失敗,不讀了。?? 綜上所述,scanf確實(shí)只讀了一個(gè)整數(shù)和一個(gè)字符串,返回值是2。
?????? 那有什么辦法實(shí)現(xiàn)用逗號(hào)作為間隔符的情況呢?下面提供兩種方法:
五、解決方法
法1:
?????? scanf("%d,%[^,],%d", &a,mon,&b);
?????? printf("%d,%s,%d\n",a,mon,b);
?????? 相關(guān)知識(shí):scanf中一種很少見但很有用的轉(zhuǎn)換字符:[...]和[ ^...]
?????? %[...]如果輸入的字符屬于方括號(hào)內(nèi)字 符串中某個(gè)字符,那么就提取該字符;如果一經(jīng)發(fā)現(xiàn)不屬于就結(jié)束提取。%[^...]如果一經(jīng)發(fā)現(xiàn)輸入的字符屬于方括號(hào)內(nèi)字符串中某個(gè)字符,那么就結(jié)束提取;如果不屬于就提取該字符。這兩種方法會(huì)自動(dòng)加上一個(gè)字符串結(jié)束符到已經(jīng)提取的字符后面。例如:
#include<stdio.h>main()
{
char strings[100];
scanf("%[1234567890]",strings);
printf("%s",strings);
return 0;
}
運(yùn)行,輸入:1234werew后,結(jié)果是:1234。
?????? 采用這種方法,讀完fefe后遇到逗號(hào)便結(jié)束字符串的讀取,繼續(xù)讀時(shí)輸入流緩沖區(qū)的逗號(hào)與格式控制字符串中逗號(hào)剛好匹配,成功!
法2(不夠徹底):
scanf("%d,%s ,%d", &a,mon,&b);?? /*注意%s后面有個(gè)空格 */
printf("%d,%s,%d\n",a,mon,b);
并且在輸入時(shí)加個(gè)空格
12,fefe ,45?? /*fefe和逗號(hào)之間加個(gè)空白*/
?????? 相關(guān)知識(shí):當(dāng)scanf()格式控制字符串中出現(xiàn)空白時(shí),表示取數(shù)時(shí)跳過任何空白。
scanf讀到fefe后的空格后結(jié)束字符串的讀取,此時(shí)輸入流緩沖區(qū)第一個(gè)字符為空格;繼續(xù)讀,由于格式控制字符串里有個(gè)空格,所以讀取時(shí)會(huì)跳過任何空白(不信可以在fefe后面多敲幾個(gè)空白試試,全都跳過,甚至連回車都跳過),讀到逗號(hào)匹配成功。
轉(zhuǎn)載于:https://www.cnblogs.com/happyblog/archive/2012/03/15/2398187.html
總結(jié)
以上是生活随笔為你收集整理的C语言scanf函数奇遇记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C# 5.0 CallerMemberN
- 下一篇: Web在线操作Office之Word