陣列
為什麼我們需要陣列?
陣列提供了一種將物件組織成具有其自身重要性的聚合的方法。例如,C 字串是字元陣列(char
s),字串如 Hello World!
。具有作為一個單獨的字元不固有的聚合的含義。類似地,陣列通常用於表示數學向量和矩陣,以及多種型別的列表。此外,如果沒有某種方法對元素進行分組,則需要單獨處理每個元素,例如通過單獨的變數。它不僅不實用,而且不容易適應不同長度的集合。
在大多數上下文中,陣列被隱式轉換為指標。
除了作為 sizeof
運算子,_Alignof
運算子(C2011)或一元 &
(取址)運算子的運算元出現,或者作為用於初始化(其他)陣列的字串文字時,陣列被隱式轉換為指向其第一個元素的指標。這種隱式轉換與陣列下標運算子([]
)的定義緊密耦合:表示式 arr[idx]
被定義為等同於*(arr + idx)
。此外,由於指標算術是可交換的,*(arr + idx)
也相當於*(idx + arr)
,而*(idx + arr)
又相當於 toidx[arr]
。只要 idx
或 arr
是一個指標(或一個衰減到指標的陣列),另一個是整數,所有這些表示式都是有效的並且計算得到相同的值。
作為一個特例,觀察 &(arr[0])
相當於 &*(arr + 0)
,這簡化為 arr
。所有這些表示式在最後衰落到指標的任何地方都是可以互換的。這再次簡單地表達了一個陣列衰減到指向其第一個元素的指標。
相反,如果取址運算子應用於 T[N]
型別的陣列( 即 &arr
),那麼結果的型別為 T (*)[N]
並指向整個陣列。這與至少針對指標算術的指向第一陣列元素的指標不同,指標算術是根據指向型別的大小來定義的。
函式引數不是陣列。
void foo(int a[], int n);
void foo(int *a, int n);
雖然 foo
的第一個宣告對引數 a
使用類似陣列的語法,但這種語法用於宣告一個函式引數,宣告該引數作為指向陣列元素型別的指標。因此,foo()
的第二個簽名在語義上與第一個簽名相同。這對應於陣列值到指標的衰減,它們作為函式呼叫的引數出現,這樣如果變數和函式引數宣告為具有相同的陣列型別,那麼該變數的值適合在函式呼叫中使用,因為與引數關聯的引數。