From Gossip@caterpillar

C Gossip: 一維陣列

您現在要整理全班的程式設計小考成績,您希望寫個小程式,全班共有40名學生,所以您必須有40個變數來儲存學生的成績,現在問題來了,根據之前學過的, 難道您要宣告40個名稱不同的變數來儲存學生的成績資料嗎?

當然您知道不會這麼麻煩的,C提供「陣列」(Array)讓您可以宣告一個以「索引」(index)作為識別的資料結構,宣告陣列的方式如下:
資 料型態 名稱[大小];

資料型態可以是int、float、char等等之前所學過的資料型態宣告,以下是幾個宣告的範例:
int iarr[10];    // 宣告10個元素的整數陣列
double darr[10];    // 宣告10個元素的浮點數陣列
char carr[10];    // 宣告10個元素的字元陣列

這是靜態陣列的宣告方式,陣列長度必須事先決定,所以您不可以使用變數來事後決定陣列的長度,如果您要動態宣告陣列長度,可以使用一些資料結構與動態記憶 體宣告來解決陣列大小必須固定的問題,這在之後才會說明。

宣告陣列之後,陣列所配置到的記憶體空間中所儲存的數是未知的,所以在初始陣列元素值之前,當中的元素值是未知的,如果您在宣告變數時尚未決定陣列中的 值,可以這麼宣告陣列:
int irr[10] = {0};
double darr[10] = {0.0};
char carr[10] = {'\0'};

上面的幾個宣告,整數陣列中的元素都會被初始為0,浮點數陣列則會被初始為0.0,字元陣列則會被初始為空字元('\0'),在宣告陣列時初始陣列元素,可以避免其它的程式存取到非預期的數值。

您也可以在宣告陣列時初始所有的陣列值,例如:
int iarr[5] = {0, 1, 2, 3, 4};
double darr[5] = {0.0, 0.1, 0.2, 0.3, 0.4};
char carr[5] = {'A', 'B', 'C', 'D', 'E'};

當要存取陣列中的值時,可以使用下標(Subscript)運算子[ ] 加上「索引」(Index)指定要存取的陣列元素,C的索引值一律由0開始,而不是由1開始,這點初學者必須特別注意,下 面這個簡單的程式可以告訴您如何使用索引存取陣列元素:
#include <stdio.h>
#define LENGTH 10

int main(void) {
int iarr[LENGTH] = {0};
int i;

for(i = 0; i < LENGTH; i++) {
printf("%d ", iarr[i]);
}
putchar('\n');

for(i = 0; i < LENGTH; i++) {
iarr[i] = i;
}

for(i = 0; i < LENGTH; i++) {
printf("%d ", iarr[i]);
}
putchar('\n');

return 0;

}
0 0 0 0 0 0 0 0 0 00 1 2 3 4 5 6 7 8 9
由於陣列本身並不知道自己的長度資訊,所以您必須額外記錄陣列長度,就如程式中的LENGTH的作用,#define是前置處理器指令,#define LENGTH 10定義了,當編譯器看到LENGTH時,都自動取代為10,之後再進行編譯。

C中陣列的索引值由0開始並不是沒有原因的,事實上陣列名稱就指向陣列記憶體的第一個位置的位址,而索引值表示所指定的陣列元素相對於陣列第一個記憶 體位置的位移量(Offset),位移的量與資料型態長度有關,如果是int整數,則每次位移時是一個int整數的長度,例如在上例中iarr[0]索引 值為0,所以表示位移量為0,自然就是指第一個元素,而iarr[9]就是指相對於第一個元素的位移量為9,C就是根據陣列第一個元素的記憶體位置與 位移量來得到所指定要存取的陣列元素。

如果您在宣告陣列時只希望初始幾個元素,則可以這麼宣告:
int iarr[5] = {0, 1};
double darr[5] = {0.0, 0.1};
char carr[5] = {'A', 'B'};

像上例中,都只初始索引0與索引1的兩個元素,其它未初始的元素,整數的話會自動初始為0,浮點數的話會自動初始為0.0,字元的話會自動初始為空字元 ,其它未初始的元素值則是未知的。

如果您在宣告陣列時會一併初始所有的元素,則C允許您不宣告陣列元素大小,它會根據您指定的元素個數自動設定陣列大小,例如:
int iarr[] = {1, 2, 3};
double darr[] = {0.4, 3.2, 1.0, 4.2};
char carr[] = {'A', 'B'};

上面宣告中,iarr[]的元素個數會是3,darr[]的個數會是4,而carr[]的個數會是2。

陣列在使用時,得知陣列長度(元素個數)是必要的,您不可以存取超過陣列長度的記憶體,這會發生無法預期的結果,然而如何得知陣列的長度,您可以使用 sizeof()運算子,例如:
int iarr[] = {1, 2, 3, 4, 5, 6};
printf("陣列長度:%d\n", sizeof(iarr) / sizeof(iarr[0]));


這個例子會顯示陣列的長度為6;sizeof()會傳回變數所指向的記憶體空間所佔大小,您只要取得整個陣列的記憶體空間大小,再除以一個陣列元素的大 小,就可以如上取得陣列的長度了。

您不可以將陣列直接指定給另一個陣列,或是直接比較兩個陣列是否相同,例如:
int arr1[5];
int arr2[5];
...
arr1 = arr2; // 錯誤!不能直接指定陣列給另一個陣列
...
if(arr1 == arr2) { // 錯誤!不能直接比較兩個陣列是否相同
    ...
}

如果要將陣列指定給另一個陣列,您只能循序一個一個元素進行複製,例如:
int arr1[5];
int arr2[5];
...
int i;
for(i = 0; i < 5; i++) {
    arr1[i] = arr2[i];
}

同樣的,如果想比較兩個陣列元素內容是否相同,也要用一個個元素進行比對。