1. 程式人生 > >scanf()和getchar() 使用

scanf()和getchar() 使用

問題描述一:(分析scanf()和getchar()讀取字元)

scanf(), getchar()等都是標準輸入函式,一般人都會覺得這幾個函式非常簡單,沒什麼特殊的。但是有時候卻就是因為使用這些函式除了問題,卻找不出其中的原因。
下面先看一個很簡單的程式:

#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()讀取字串的問題:

#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(),下面我們看一下這個函式的應用:

#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);