深入解析scanf()/getchar()和gets()等函數針對字串輸入的問題

來源:互聯網
上載者:User
 深入解析scanf()/getchar()和gets()等函數 
----------------------------------------------------
| 問題描述一:(分析scanf()和getchar()讀取字元)   |
----------------------------------------------------
    scanf(), getchar()等都是標準輸入函數,一般人都會覺得這幾個函數非常簡單,沒什麼特殊的。但是有時候卻就是因為使用這些函數除了問題,卻找不出其中的原因。下面先看一個很簡單的程式:
程式1:
    #include <stdio.h>
    int main()
    {
char ch1, ch2;
scanf("%c", &ch1); 
scanf("%c", &ch2);
printf("%d %d\n", ch1, ch2);
return 0;
    }
    或者是:
    #include <stdio.h>
    int main()
    {
char ch1, ch2;
ch1 = getchar();
ch2 = getchar();
printf("%d %d\n", ch1, ch2);
return 0;
    }
    程式的本意很簡單,就是從鍵盤讀入兩個字元,然後列印出這兩個字元的ASCII碼值。可是執行程式後會發現除了問題:當從鍵盤輸入一個字元後,就列印出了結果,根本就沒有輸入第二個字元程式就結束了。例如使用者輸入字元'a', 列印結果是97,10。這是為什麼呢?
【分析】:
    首先我們呢看一下輸入操作的原理, 程式的輸入都建有一個緩衝區,即輸入緩衝區。一次輸入過程是這樣的,當一次鍵盤輸入結束時會將輸入的資料存入輸入緩衝區,而cin函數直接從輸入緩衝區中取資料。正因為cin函數是直接從緩衝區取資料的,所以有時候當緩衝區中有殘留資料時,cin函數會直接取得這些殘留資料而不會請求鍵盤輸入,這就是例子中為什麼會出現輸入語句失效的原因!
    其實這裡的10恰好是斷行符號符!這是因為scanf()和getchar()函數是從輸入資料流緩衝區中讀取值的,而並非從鍵盤(也就是終端)緩衝區讀取。而讀取時遇到斷行符號(\n)而結束的,這個\n會一起讀入輸入資料流緩衝區的,所以第一次接受輸入時取走字元後會留下字元\n,這樣第二次的讀入函數直接從緩衝區中把\n取走了,顯然讀取成功了,所以不會再從終端讀取!這就是為什麼這個程式只執行了一次輸入操作就結束的原因! 
----------------------------------------------------
| 問題描述二:(分析scanf()和gets()讀取字串)   |
----------------------------------------------------
首先我們看一下scanf()讀取字串的問題:
程式2:
    #include <stdio.h>
    int main()
    {
char str1[20], str2[20];
scanf("%s",str1); 
printf("%s\n",str1);    
scanf("%s",str2); 
printf("%s\n",str2); 
return 0;
    }
    程式的功能是讀入一個字串輸出,在讀入一個字串輸出。可我們會發現輸入的字串中不能出現空格,例如:
測試一輸入:
Hello world!
輸出:
Hello
world!
【分析】到此程式執行完畢,不會執行第二次的讀取操作!這個問題的原因跟問題一類似,第一次輸入Hello world!後,字串Hello world!都會被讀到輸入緩衝區中,而scanf()函數取資料是遇到斷行符號、空格、TAB就會停止,也就是第一個scanf()會取出"Hello",而"world!"還在緩衝區中,這樣第二個scanf會直接取出這些資料,而不會等待從終端輸入。

測試二:
Hello[Enter] 
Hello[輸出]
world[Enter]
world[輸出]
【分析】程式執行了兩次從鍵盤讀入字串,說明第一次輸入結束時的斷行符號符被丟棄!即:scanf()讀取字串會捨棄最後的斷行符號符!

我們再看一下gets()讀取字串的情況:
用scanf來讀取一個字串時,字串中是不可以出現空格的,一旦出現空格,後面的資料就會捨棄殘留在緩衝區中。其實有另外一個函數是可以接受空格的,那就是gets(),下面我們看一下這個函數的應用,我們把程式2改動一下:
程式3:
#include <stdio.h>
int main()
{
char str1[20], str2[20];
gets(str1); 
printf("%s\n",str1);    
gets(str2); 
printf("%s\n",str2); 
return 0;
}
測試:
Hello world! [輸入]
Hello world! [輸出]
12345 [輸入]
12345 [輸出]
【分析】顯然與上一個程式的執行情況不同,這次程式執行了兩次從鍵盤的讀入,而且第一個字串取了Hello world! 接受了空格符,而沒有像上一個程式那樣分成了兩個字串!所以如果要讀入一個帶空格符的字串時因該用gets(), 而不宜用scanf()!

--------------------------------------------------------
| 問題描述三:(getchar()暫停程式,查看程式執行結果)|
--------------------------------------------------------
    不知道大家有沒有遇到過這樣的問題,有的編譯器程式執行完後的結果介面不會停下而是一閃就沒了,以至於看不到執行結果。所以很多人在程式最後加上getchar()語句,目的是想讓程式執行完後停下來,等待從終端接收一個字元再結束程式。可是發現有時候這樣根本沒用,程式照樣跳出去了。這是為什麼呢?
【分析】原因跟上面例子講的一樣,是因為輸入緩衝區中還有資料,所以getchar()會成果讀到資料,所以就跳出了!

------------------
|     【總結】    |
------------------
第一:要注意不同的函數是否接受空格符、是否捨棄最後的斷行符號符的問題!
讀取字元時:
scanf()以Space、Enter、Tab結束一次輸入,不會捨棄最後的斷行符號符(即斷行符號符會殘留在緩衝區中);
getchar()以Enter結束輸入,也不會捨棄最後的斷行符號符;
讀取字串時:
scanf()以Space、Enter、Tab結束一次輸入
gets()以Enter結束輸入(空格不結束),接受空格,會捨棄最後的斷行符號符!

第二:為了避免出現上述問題,必須要清空緩衝區的殘留資料,可以用以下的方法解決:
方法1:C語言裡提供了函數清空緩衝區,只要在讀資料之前先清空緩衝區就沒問題了!
       這個函數是fflush(stdin)。
方法2:自己取出緩衝區裡的殘留資料。
(說實話這個語句我也沒看懂,呵呵!為什麼格式控制是這樣的!希望高手指點一下!)
       scanf("%[^\n]",string);

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.