C 教材:序列 array 資料結構

以下的程式,要記錄輸入的純文字檔案中, 每個數目字各出現多少次。 我們可以為每個數目字宣告一個變數來計數。 例如宣告 int n0, n1, n2, n3, n4, n5, n6, n7, n8, n9;。 試想,如果這樣做,將會需要寫 10 層相套的 if-else 結構。 這是非常煩瑣的工作。 見以下範例。


#include <stdio.h>

/* 錯誤示範,請勿模倣  (digits-ifelse.c)*/
main() {
    int c, n0, n1, n2, n3, n4, n5, n6, n7, n8, n9;

    n0 = n1 = n2 = n3 = n4 = n5 = n6 = n7 = n8 = n9 = 0;
    while((c = getchar()) != EOF)
        if (c == '0')
            ++n0;
        else if (c == '1')
            ++n1;
        else if (c == '2')
            ++n2;
        else if (c == '3')
            ++n3;
        else if (c == '4')
            ++n4;
        else if (c == '5')
            ++n5;
        else if (c == '6')
            ++n6;
        else if (c == '7')
            ++n7;
        else if (c == '8')
            ++n8;
        else if (c == '9')
            ++n9;
    printf("%d %d %d %d %d %d %d %d %d %d\n", n0,n1,n2,n3,n4,n5,n6,n7,n8,n9);
}

現在我們介紹序列 (array) 資料型態。 其實,序列本身不是一個獨立的資料型態, 它是從基本的資料型態:包括 charintfloatdouble 衍生出來的資料結構。 看以下例子。


#include <stdio.h>

/* 計算 0 -- 9 每個數目字出現幾次  (digits.c) */
main() {
    int c, i, ndigit[10];
    
    for (i=0; i<10; ++i)
        ndigit[i] = 0;
    while((c = getchar()) != EOF)
        if (c >= '0' && c <= '9')
            ++ndigit[c-'0'];
    for (i=0; i<10; ++i)
        printf("%d ", ndigit[i]);
    putchar('\n');
}

以上的宣告指令表示 ndigit[] 是一個維度為 10 的 int 序列。 也就是說,有 10 個整數型態的資料,共用 ndigit[] 這個變數名字。 我們用序列的編號來分辨這 10 個整數。 在 C 語言中,序列編號一律從 0 開始。 所以,那 10 個整數的編號是從 0 到 9。 以 C 的語法而言,用 ndigit[i] 代表編號為 i 的整數。

注意,我們故意寫 ndigit[]。 這是書寫 C 語言的習慣。 在 ndigit 之後寫一對 [] 表示它是個序列變數。 如果只寫 ndigit 容易被誤解為普通變數。

同理,如果宣告了

char st[1024];
double v[256];
st[] 是個維度為 1024 的 char 序列v[] 是個維度為 256 的 double 序列

由於 '0''9' 的字碼是連號, 所以讀進來的數目字字元 c-'0' 就獲得了那個數目字所代表的整數。 這是初學者常常混淆的事。 當您在螢幕上看到 3 的時候, 計算機的內部記錄的是 3 的字碼, 按 C 語法寫,就是 '3';它的字碼是 51。 而 '3'-'0' 才真?得到了整數資料型態的 3。

以上那個程式,分別用 ndigit[i] 來記錄數目字 i 的出現次數。第一個 for-loop 是在定義 ndigit[] 所代表的 10 個整數值。 序列變數,就像所有變數一樣,都是要經過宣告和定義的手續, 才能開始使用的。 第二個 for-loop 是將 ndigit[] 的值依序輸出。 從這個例子,我們看到,定義和輸出序列, 都不能只說變數名字,而是要使用迭代結構來一一執行。 這也是初學者經常忘記的細節,請注意。

最後,看看 ++ndigit[c-'0']; 這個指令。 我們發現,在 [ ] 內的序列編號,可以是任何產生整數結果的 C 語句。 例如 ndigit[9/5+2] 也是可以的。 其次,我們看到,ndigit[i] 就像一個普通變數一樣,可以將它寫在任何 C 語句中容許變數出現的位置。 最後,我們要提醒讀者,若當初一個序列的宣告維度是 N, 則它的標號必須是從 0N-1。 C 語言的編譯程式不會替您看守: 如果您不慎使用到超過 N-1 的序列編號, 它不會警告您,而可能會發生不可預期的錯誤結果。

習題

  1. 用以上的程式去計算它自己的原始碼中,每個數目字各出現幾次。 數數看,答案是否正確?
  2. 寫一個程式,列出輸入的純文字檔中,每個英文字母的出現次數。 大小寫字母不分,當作同一個字母看待。
[BCC16-C]
單維彰 (2000/03/31) ---
[Prev] [Next] [Up]