scanf()作為 C 語(yǔ)言中的基本輸入,曾經(jīng)帶給我們初次編寫 C 程序的快樂(lè)。但是隨著 C 的不斷深入,我們卻發(fā)現(xiàn):原來(lái)最難理解的東西居然是我們自以為很熟悉的東西。 我們真正了解 scanf()嗎?那么看看下面的幾個(gè)例子吧。 一、關(guān)于 scanf()中的格式控制符 scanf()的格式控制符有多個(gè),但我只想討論一下%[]這個(gè)格式控制符。%[]可以用來(lái)進(jìn) 行多個(gè)字符的輸入,并對(duì)結(jié)束符進(jìn)行自定義。 ANSI C 標(biāo)準(zhǔn)向 scanf() 增加了一種新特性,稱為掃描集(scanset)。 掃描集定義一 個(gè)字符集合,可由 scanf() 讀入其中允許的字符并賦給對(duì)應(yīng)字符數(shù)組。 掃描集合由一對(duì) 方括號(hào)中的一串字符定義,左方括號(hào)前必須綴以百分號(hào)。 例如,以下的掃描集使 scanf() 讀入字符 A、B 和 C: %[ABC] 使用掃描集時(shí),scanf() 連續(xù)吃進(jìn)集合中的字符并放入對(duì)應(yīng)的字符數(shù)組,直到發(fā)現(xiàn)不在集 合中的字符為止(即掃描集僅讀匹配的字符)。返回時(shí),數(shù)組中放置以 null 結(jié)尾、由讀入 字符組成的字符串。 對(duì)于許多實(shí)現(xiàn)來(lái)說(shuō),用連字符可以說(shuō)明一個(gè)范圍。 例如,以下掃描集使 scanf() 接受字 母 A 到 Z:%[A-Z] 重要的是要注意掃描集是區(qū)分大小寫的。因此,希望掃描大、小寫 字符時(shí),應(yīng)該分別說(shuō)明大、小寫字母。 對(duì)于%[]還可以用^+任意字符(包括 eof)來(lái)結(jié)束字符串的輸入。比如%[^EOF]就是直到有 EOF 輸入,字符串才中止。 但一定要記住就是 c 語(yǔ)言是緩沖輸入,即使你%[^a],再你輸入回車之前輸入多少的 a 都是 不可能結(jié)束的。 如下面的一段程序: #include<stdio.h> int main() { char string[50]; /*scanf("%s",string);不能接收空格符*/ printf("Input [^\\n] string \n"); scanf(" %[^'\n']",string); printf("The s[^\\n] string :%s\n",string); fflush(stdin); printf("Input [^a] string \n"); scanf(" %[^a]",string); printf("'a' ends input :%s\n",string); printf("Input [A-F] string\n"); scanf(" %[A-F]",string); printf("String is: %s\n",string); return 0; } 運(yùn)行結(jié)果: ghost@ghost-desktop:~/Desktop/testzone/first$ ./t Input [^\n] string I love China! The s[^\n] string :I love China! Input [^a] string I love youa 'a' ends input :I love you Input [A-F] string String is: I love you ghost@ghost-desktop:~/Desktop/testzone/first$ 通過(guò)上述運(yùn)行結(jié)果,可能會(huì)感到疑惑,為什么 Input [A-F] string 根本就沒(méi)有輸入,哪來(lái) 的輸出呀?這個(gè)問(wèn)題就是我們將要討論的話題。 二、關(guān)于 scanf()的異常情況 scanf()會(huì)產(chǎn)生什么異常呢? 先來(lái)看一段程序: #include<stdio.h> int main() { int i; char ch; for(i=0;i<=3;i++) { printf("%d ---- ",i); scanf("%c", &ch); printf("\n"); //scanf("%*c"); //printf("\n%c\n",ch); //getchar(); } return 0; } 運(yùn)行結(jié)果: ghost@ghost-desktop:~/Desktop/testzone/first$ ./t 0 ---- a 1 ---- 2 ---- b 3 ---- ghost@ghost-desktop:~/Desktop/testzone/first$ 產(chǎn)生其原因在于: 因?yàn)?scanf %c 只是讀入一個(gè)字符,而你在輸入時(shí)實(shí)際上輸入的是:某個(gè)字符 +Enter,Enter 產(chǎn)生的\n 也會(huì)停留在輸入緩沖區(qū)中,下次調(diào)用 scanf %c 時(shí)就會(huì)直接讀到 它而不是等待你再次輸入!同理,getchar()也有類似的行為。所以我們才不提倡使用 scanf("%c", ...),尤其是把它在循環(huán)中。 解決的方法: (1)、將 scanf("%c", &ch); 修改為: scanf(" %c", &ch); /*在%前加上一個(gè)空格*/ (2)、將 scanf("%c", &ch); 修改為: scanf("%c%*c", &ch); (3)、函數(shù)名: fflush 功 能: 清除一個(gè)流 用 法: int fflush(FILE *stream); #include <stdio.h> int main() { int a; char c; do{ scanf("%d",&a); fflush(stdin); scanf("%c",&c); fflush(stdin); printf("a=%d c=%c\n",a,c); }while(c!='N'); return 0; } (4)、如何處理 scanf()函數(shù)誤輸入造成程序死鎖或出錯(cuò)? #include <stdio.h> int main() { int a,b,c; /*計(jì)算 a+b*/scanf("%d,%d",&a,&b); c=a+b; printf("%d+%d=%d",a,b,c); return 0; } 如上程序,如果正確輸入 a,b 的值,那么沒(méi)什么問(wèn)題。但是,不能保證使用者每一 次都能正確輸入,一旦輸入了錯(cuò)誤的類型,你的程序不是死鎖,就是得到一個(gè)錯(cuò)誤的結(jié)果, 這可能所有人都遇到過(guò)的問(wèn)題吧? 解決方法:scanf()函數(shù)執(zhí)行成功時(shí)的返回值是成功讀取的變量數(shù),即:這個(gè) scanf () 函數(shù)有幾個(gè)變量,如果 scanf()函數(shù)全部正常讀取,它就返回幾。但這里還要注意另一個(gè) 問(wèn)題,如果輸入了非法數(shù)據(jù),鍵盤緩沖區(qū)就可能還個(gè)有殘余信息問(wèn)題。 正確的例程: #include <stdio.h> int main() { int a,b,c; /*計(jì)算 a+b*/ while(scanf("%d,%d",&a,&b)!=2) fflush(stdin); c=a+b; printf("%d+%d=%d",a,b,c); return 0; } |
|