scanf() 函式

& 指令有什麼用呢? 現在先講一個,以後還會看到其他用處。 相對於 printf() 做格式化的輸出, C 語言的標準函式庫之中,還有一個 scanf() 做格式化的輸入。 這個函式的設計有些特別,它不能接受變數名,必須給它變數的地址。 究竟為什麼這樣?這個問題最好暫時不去碰它,讀者此時先學習正確的語法即可, 背後的道理,以後自會明白。例如以下語句

int i, k;
k = scanf("%d", &i);
的意思就是說,從 stdin (標準輸入裝置) 讀入一個整數, 將它儲存在變數 i 裡面。 如果 scanf() 執行成功了,k 就是 1, 如果失敗了 k 就是 0, 如果讀到了檔案結束的符號 (例如使用者鍵入 Ctrl+D) k 就是 EOF (EOF 也就是 -1)。

常用的輸入格式如下:

getchar() 會從標準輸入裝置一個一個字元地讀進來, 它不會跳過任何字元。 但是 scanf() 會自動跳過所有的連續空白, 所謂空白包括了空格、跳格和折列指令 ('\n')。 當第一次呼叫 scanf() 的時候,它跳過所有的連續空白, 讀取第一個廣義字串,然後按照格式 (例如 %d%f 等等) 解釋讀進來的字串,如果解釋成功了,就將它儲存到指定的地址,並且返回 1; 如果沒有成功,就返回 0;如果讀進來的資料代表輸入檔案之結束,就返回 EOF。 當第二次呼叫 scanf() 的時候,它就跳過第一個廣義字串之後的所有連續空白, 讀取第二個廣義字串,依此類推。 底下這個小程式,示範 scanf() 的最基本用法。 它從標準輸入裝置依序讀取浮點數數,並依序輸出,直到檔案結束為止。
#include <stdio.h>

/* 測試 scanf() 及浮點數  (test-scanf.c) */
main() {
    float x;  
    while (scanf("%f", &x) != EOF)
        printf("%f\n", x);
}

假設這個程式已經被編譯成為可執行檔 a.out, 以下是一個實驗的結果:
prompt% a.out
1 -1.5 1.5e5 1.5e-5
1.000000
-1.500000
150000.000000
0.000015
Ctrl+D
prompt%

由實驗可見,輸入的浮點數可以是負數,也可以有指數符號。

底下,我們改寫 demo-stats.c, 使得它可以從標準輸入裝置取得一個序列的數值, 然後計算並輸出這些數的基本描述統計:個數、總和、平均、標準差、最大、最小、 超過「平均 + 標準差」的值、不到「平均 - 標準差」的值。 這個程式的寫法,有幾點值得注意之處:

  1. 因為我們事先不知道將要輸入多少個數,所以無法事先設定序列的維度。 因此,我們只好設定一個夠大的維度,萬一使用者輸入太多個數, 就停下來給錯誤訊息。現在暫時如此,以後會學到更完美的作法。
  2. 假設輸入的數都是整數。
  3. 將做統計的部分,寫成函式。這是為了以後的方便,現在暫時不談。
  4. while 迴圈結束時,n-1 是最後一個 x[] 序列的足標號碼,而 n 恰好就是 x[] 序列的有效維度。

#include <stdio.h>
#include <math.h>

/* 示範以 scanf() 輸入序列  (stats-scanf.c) */
#define DIM 512
void istats(int[], int);
  
main() {
    int i, n=0, x[DIM];
    while(scanf("%d", &i) != EOF)
        x[n++] = i;
    istats(x, n);
}
  
void istats(int x[], int N) {
    int i, sum, max, min;
    float mean, var, cut;
    sum = 0;
    max = -65536;
    min = 65536;
    for (i=0; i<N; ++i) {
        sum = sum + x[i];
        if (x[i] > max)
            max = x[i];
        if (x[i] < min)
            min = x[i];
    }
    mean = (sum*1.0)/N;
    printf("Num  = %4d\n", N);
    printf("Sum  = %4d\n", sum);
    printf("MAX  = %4d\n", max);
    printf("MIN  = %4d\n", min);
    printf("MEAN = %7.2f\n", mean);

    var = 0;
    for (i=0; i<N; ++i)
        var = var + (x[i] - mean)*(x[i] - mean);
    var = sqrt(var / (N-1));
    printf("VAR  = %7.2f\n", var);

    printf("HIGH =  ");
    cut = mean + var;
    for (i=0; i<N; ++i)
        if (x[i] >= cut)
            printf("%3d", x[i]);
    putchar('\n');
    printf("LOW  =  ");
    cut = mean - var;
    for (i=0; i<N; ++i)
        if (x[i] <= cut)
            printf("%3d", x[i]);
    putchar('\n');
}

我們可以把想要做統計的數寫在一個檔案中, 可以一數一列,也可以好幾個數一列,數與數之間用一個或多個空格、跳格隔開。 非常注意:如果輸入檔案中有非數字的字元,哪怕是標點符號也罷, 都會造成這個程式損毀、或是進入無窮迴圈。 以後我們再學如何處理這種問題。

為了能夠重複 demo-stats.c 同樣的實驗數據, 請讀者自行下載儲存 g58.txt 這個文字檔案。 這裡面有同樣的 58 個整數, 請利用 UNIX 的檔案導向功能將這個純文字檔輸入給上述程式使用。

習題

  1. 用 C 語言寫一個程式,假設輸入的資料是每列一個整數, 此程式要計算那些輸入的整數當中,有幾個介於 0..9 之間,幾個介於 10..19 之間,... 幾個介於 80..89 之間,和有幾個介於 90..100 之間,然後輸出計算的結果。 寫完程式以後,讀入文字檔案 g58.txt 當作實驗。

[ 前一節 ]‧[ 後一節 ]‧[ 回目錄 ]



注意:此處所有文件均為原著,個別的版權宣告日後會一一公布, 整體版面設計亦尚未完成。但仍請勿抄襲文字與圖片,以免觸犯著作權法。

Created: Feb 27, 2001
Last Revised: Mar 2, 2001
© Copyright 2001 Wei-Chang Shann 單維彰

shann@math.ncu.edu.tw