1. 指派初始值(Designated Initializers)
指派初始值這個特性是 C99 增加的,它允許我們直接初始化數組中特定的元素。C99 以前,如果我們要初始化數組中的某個元素,如第三個元素,必須同時初始化它之前的元素。例如:
int iarr[10] = { 0, 0, 300 };
而 C99 中,我們可以這樣初始化特定的元素:
int iarr[10] = { [2] = 300 }; /* 指派初始化 iarr[2] 為 300 */
其餘的元素都會被初始化為 0 。下面我們來看一個小程式。
#include <stdio.h>
int main(void)
{
int iarr[5] = { 6, 3, [3] = 1, 5, [1] = 8};
printf("%d\n", iarr[0]);
printf("%d\n", iarr[1]);
printf("%d\n", iarr[2]);
printf("%d\n", iarr[3]);
printf("%d\n", iarr[4]);
return 0;
}
輸出為:
6
8
0
1
5
從中可以看出兩點:
A. 如果指派初始值後面還有值,則後面的值會被用於初始化後續的元素。上例中,
iarr[3] 被初始化為 1 ,它後續的元素 iarr[4] 被初始化為 5。
B. 如果初始化列表中多次出現對某元素的初始化,則以最後一次為準。上例中,
iarr[1] 先被初始化為 3,然後被 [1] = 8 指派初始化為 8。
2. 給數組元素賦值
我們可以利用下標給特定的元素賦值。例如:
int iarr[5];
iarr[0] = 100; /* 賦值給第一個元素 */
iarr[4] = 120; /* 賦值給第五個元素 */
iarr[2] = 180; /* 賦值給第三個元素 */
C 不允許直接使用數組對別的數組進行賦值,也不允許使用初始化列表對數組進行賦值。例如:
int iarr_1[5] = { 1, 2, 3, 4, 5 }; /* 正確 */
int iarr_2[5];
iarr_2 = iarr_1; /* 錯誤! */
iarr_2[5] = { 3, 4, 5, 6, 7 }; /* 錯誤! */
iarr_2[5] = iarr_1[5]; /* 越界! */
最後一個語句發生了越界!因為這兩個數組都只有 5 個元素,而使用下標 5 訪問的是第六個元素!
3. 數組界限(array bounds)
使用下標時,我們必須確保下標沒有越界。例如:
int iarr[46];
這個數組的下標範圍是 0 到 45,確保下標沒有超出這個範圍是我們的責任,因為編譯器不會對下標越界進行檢測!
C 標準沒有定義下標越界的後果,也就是說,當我們寫的程式中出現下標越界的問題,程式可能正常工作,也可能異常退出,還有可能出現其它奇怪的情況。
#include <stdio.h>
int main(void)
{
int var_1 = 20;
int arr[5];
int var_2 = 40;
printf("var_1: %d, var_2: %d\n", var_1, var_2);
arr[-1] = -1;
arr[5] = 5;
printf("%d %d\n", arr[-1], arr[5]);
printf("var_1: %d, var_2: %d\n", var_1, var_2);
return 0;
}
上述程式使用 Dev-C++ 4.9.9.2 編譯啟動並執行輸出為:
var_1: 20, var_2: 40
-1 5
var_1: 20, var_2: -1
可見,下標越界可能改變其它變數的值。這是因為 gcc(dev-c++ 使用的 C 編譯器)把 var_2 儲存於數組 arr 之前的記憶體空間,所以對 arr[-1] 賦值正好改變了 var_2 的值。不同的編譯器編譯運行該程式可能會有不同的輸出,也可能會異常退出。
C 語言的哲學是信任程式員,而且不檢測越界程式運行更快。程式編譯時間有些下標的值仍然是不可知的,所以如果要檢測下標越界的話,編譯器必須在產生的目標代碼中加入額外的代碼用於程式運行時檢測下標是否越界,這就會導致程式運行速度下降。故而,為了運行效率,C 不檢測下標是否越界。
4. 指定數組元素數目
C99 之前,聲明數組時,[] 中的值必須是大於零的整數常量。C99 中,聲明數組時,[] 中可以是變數。這就是所謂的變長數組(variable-length array,簡稱 VLA)。聲明 VLA 時,不能對其進行初始化。在後續的教程中,我會對 VLA 進行詳細講解。
int n = 99;
double dbl_1[4]; /* 正確 */
double dbl_2[8/2 + 4]; /* 正確 */
int iar_1[-5]; /* 錯![] 中的值必須大於 0 */
int iar_2[0]; /* 錯![] 中的值必須大於 0 */
int iar_3[9.2]; /* 錯![] 中的值必須是整數類型 */
char ch[n]; /* C99 之前不支援! */