陣列包含給定型別的一些物件,並將這些物件依次儲存在連續的記憶體空間中。每個獨立的物件被稱為
陣列的元素(element)。
元素的型別可以是任何物件型別,但函數型別或不完整型別不能作為陣列元素。
陣列本身也是一個物件,其型別由它的元素型別延伸而來。更具體地說,
陣列的型別由元素的型別和數量所決定。
如果一個陣列的元素是 T 型別,那麼該陣列就稱為“T 陣列”。例如,如果元素型別為 int,那麼該陣列的型別就是“int 陣列”。然而,int 陣列型別是不完整的型別,除非指定了陣列元素的數量。如果一個 int 陣列有 16 個元素,那麼它就是一個完整的物件型別,即“16 個 int 元素陣列”。
陣列的定義決定了陣列名稱、元素型別以及元素個數。沒有顯式初始化操作的陣列定義,其語法如下:
型別 名稱[元素數量];
元素數量在方括號([])之間,它必須是大於 0 的整數表示式。範例:
char buffer[4*512];
這一行程式碼定義了一個名為 buffer 的陣列,它包含 2048 個 char 型別元素。
可以利用 sizeof 運算子獲取物件所占記憶體空間的大小。陣列在記憶體中的空間大小總是等於一個元素的空間大小乘以陣列中元素的個數。因此,上述例子中的 buffer 陣列,表示式 sizeof(buffer)會產生 2048*sizeof(char)的值。換句話說,buffer 陣列佔用 2048 個記憶體位元組,因為 sizeof(char)等於 1。
在陣列定義中,可以將元素數量指定為一個常數表示式,或者在特定情況下,指定為涉及變數的表示式。採用這兩種方式定義的陣列分別被稱為
固定長度陣列(fixed-length)和
長度可變(variable-length)陣列。
固定長度陣列
固定長度陣列可以具有任意儲存類別:可以將它們定義在所有函數的外面或語句塊的裡面,並且可以使用或不使用儲存類修飾符 static。唯一的限制是陣列不能作為函數引數。一個傳入函數的陣列引數需要被轉換為指向陣列第一個元素的指標。
下面 4 種陣列定義方式都是合法的:
int a[10]; // a有外部連結
static int b[10]; // b有靜態儲存週期和檔案作用域
void func()
{
static int c[10]; // c有靜態儲存週期和塊作用域
int d[10]; // d有動態儲存週期
/* ... */
}
長度可變陣列
如果一個陣列具有動態儲存週期(也就是說,如果在語句塊內定義陣列,並且沒有 static 修飾符),那麼 C99 也允許把非常數表示式作為元素數量來定義該陣列。這樣的陣列被稱為長度可變陣列(variable-length array)。
而且,
長度可變陣列的名稱必須是普通的識別符號。長度可變陣列不能作為結構或聯合的成員。在下面的範例中,只有 vla 陣列的定義是合法的:
void func( int n )
{
int vla[2*n]; // 合法:儲存週期為動態的
static int e[n]; // 非法:長度可變陣列不可有靜態儲存週期
struct S { int f[n]; }; // 非法:f不是一個普通識別符號
/* ... */
}
與其他動態變數一樣,每次程式流進入包含長度可變陣列定義的語句塊時,都會重新建立這個長度可變陣列。因此,在每次範例化時,陣列都可以有不同的長度。然而,一旦被建立,即便是長度可變陣列,在它的當前儲存週期內也不能改變陣列長度。
動態物件被儲存在棧中,當程式流離開物件所在的語句塊時,動態物件的空間就會被釋放。因此,只有對小的、臨時的陣列,定義長度可變陣列才比較合理。
如想動態地建立大型陣列,通常應該使用標準函數 malloc()和 calloc()來顯式地分配記憶體空間。
這種陣列的儲存週期會持續到程式結束,也可以呼叫函數 free()來主動地釋放被占用的記憶體空間。