C 教材:序列編號

前一節說, C 語言的編譯程式不會替您看守序列維度: 如果您使用的序列編號,超過了當初宣告的維度, 它不會警告您,而會若無其事地執行。 現在,我們修改 digits.c,使得它多輸出 20 個整數,看看結果如何?


#include <stdio.h>

/* 故意使用超過序列維度的元素  (toolong.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<30; ++i)
        printf("%d ", ndigit[i]);
    putchar('\n');
}

執行這個程式,輸入它自己的原始碼,我在某台機器上得到的結果是
9 2 0 1 0 0 0 0 0 1 0 0 0 0 1 0 536867584 1 0 0 536867590 1 536867660 1 536867813 1 536867828 1 536867835 1
您若做同樣的實驗,應該會看到前 10 個數與我的結果相同, 這些數字依序代表前面那個程式裡面,0 -- 9 這些數目字各出現幾次。 但是後面的 20 個數,應該和我的結果不同。以下卵們解釋原因。

當我們宣告 int ndigit[10] 的時候, C 知道要為 ndigit[] 保留 40 bytes :空間 (10 個 int, 每個 4 bytes)。 當我們用 for (i=0; i<10; ++i) ndigit[i] = 0; 來定義它們的值, 作業系統為我們在記憶體中,找到一段連續 40 bytes 的自由空間 (free space); 也就是說,沒有被其他正在執行中的程式所佔據的記憶體。 ndigit[] 的 10 個整數,就依序被放在那 40 bytes 裡面。 比如說,那 40 bytes 的第一個 byte 的記憶體位址是 1024000, 那麼 ndigit[0] 就存放在

1024000 1024001 1024002 1024003
這四個位址內。 依此類推,ndigit[9] 就存放在
1024036 1024037 1024038 1024039
這四個位址內。 當我們在程式中指稱 ndigit[15] 的時候, 沒有任何人知道它已經超出了序列的範圍, 於是就按照正常程序:取得
1024060 1024061 1024062 1024063
這四個位址內的資料, 將它們組成一個 32-bit 的位元組,並以 int 的資料型態解讀之。 你要一個整數,它給你一個整數,可謂求仁得仁,沒什麼可以抱怨的。

問題是,當初作業系統保留給我們用的一段記憶體,只是從 1024000 到 1024039 這 40 個 bytes。在這段範圍以外的記憶體,極可能有其他程式正在使用。 誰也說不準,到底是哪些程式在使用?存放了哪些資料? 尤其對一個忙碌的多人多工 UNIX 系統而言,更是說不準。 所以,您會獲得什麼樣的結果,就完全聽天由命了。

習題

[BCC16-C]
單維彰 (2000/03/21) --- 00/03/31 (單)
[Prev] [Next] [Up]