第8章 陣列

2020-08-12 22:54:07

陣列名的值是一個指針常數。
只有在兩種場合下,陣列名並不用指針常數來表示,就是當陣列名作爲sizeof操作符或單目操作符&的運算元時。sizeof返回整個陣列的長度,而不是指向陣列的指針的長度。取一個數組名的地址所產生的是一個指向陣列的指針,而不是一個指向某個指針常數的值的指針。
你不能使用賦值符把一個數組的所有元素複製到另一個數組。你必須使用一個回圈,每次複製一個元素。

一個神奇而不使用的例子:

2[array] // 其等價於 *(array+2)

**如果可以互換使用指針表達式和下標表示式,假定兩種方法都是正確的,下標絕不會比指針更有效率,但指針有時會比下標更有效率。**但程式的效率主要取決於你所編寫的程式碼。和使用下標一樣,使用指針也很容易寫出品質低劣的程式碼。事實上,這個可能性或許更大。不要爲了效率上的細微差別而犧牲可讀性,這點非常重要。

**當宣告陣列參數時,呼叫函數實際傳遞的是一個指針,所以函數的形參實際上是個指針。但爲了使程式設計師新手更容易上手,編譯器也接受陣列行的函數形參。但哪個更加準確呢?答案是指針。**因爲實參實際上是個指針,而不是陣列。同樣,表達式sizeof string的值是指向字元的指針的長度,而不是陣列的長度。單目操作符&返回一個指向陣列的指針,而不是指向陣列第1個元素的指針的指針。
如果函數需要知道陣列的長度,它必須作爲一個顯式的參數傳遞給函數。

指針和陣列並不相等,陣列的屬性和指針的屬性大相徑庭。當我們宣告一個數組時,它同時也分配了一些記憶體空間,用於容納陣列元素。但是,當我們宣告一個指針時,它只分配了用於容納指針本身的空間。

陣列的初始化,例如:

int vector[5] = {10, 20, 30, 40, 50};

當陣列的初始化區域性於一個函數(或程式碼塊)時,你應該仔細考慮一下,在程式的執行流每次進入該函數(或程式碼塊)時,每次都對陣列進行重新初始化是不是值得。如果答案是否定的,你就把陣列宣告爲static,這樣陣列的初始化只需在程式開始前執行一次。

不完整的初始化,例如:

int vector[5] = {1, 5};

編譯器只知道初始值不夠,所以只允許省略最後幾個初始值,將其設定爲0。
如果宣告中並未給出陣列的長度,編譯器就把陣列的長度設定爲剛好能夠容納所有的初始值的長度。

C語言標準提供了一種快速方法用於初始化字元陣列,例如:

char message[] = "Hello";

儘管它看上去像是一個字串常數,但實際上並不是。
例如:

char message1[] = "Hello";
char *message2 = "Hello";

這兩個初始化看上去很像,但它們具有不同的含義。前者初始化一個字元陣列的元素,而後者則是一個真正的字串常數。這個指針變數被初始化爲指向這個字串常數的儲存位置。

如果某個陣列的維數不止1個,它就被稱爲多維陣列。例如:

int matrix[6][10];

可以把它看作是一個包含6個元素的向量,每個元素本身又包含10個整型元素。
在C語言中,多維陣列的元素儲存順序按照最右邊的下標率先變化的原則,稱爲行主序。
matrix這個名字的值是一個指向它第1個元素的指針,所以matrix是一個指向一個包含10個整型元素的陣列的指針。

指向陣列的指針,例如:

int vector[10];
int *vp = vector;
int matrix[3][10];
int (*mp)[10] = matrix;

如果你打算在指針上執行任何指針運算,應該避免這種型別的宣告:

int (*p)[] = matrix;

當某個整數與這種型別的指針執行指針運算時,它的值將根據空陣列的長度進行調整(也就是說,與零相乘),這很可能不是你所設想的。

作爲函數參數的多維陣列,例如:

int matrix[3][10];
void func1(int (*mat)[10])
void func2(int mat[][10])

上述兩種宣告都正確。但

void func3(int **mat)

這種宣告方法是不正確的。

多維陣列的初始化,例如:

int matrix[2][3] = {1, 2, 3, 4}; // 編譯正確的不完全初始化

在多維陣列中,只有第1維才能 纔能根據初始化列表預設地提供。剩餘的幾個維必須顯式地寫出,這樣編譯器就能推斷出每個子陣列維數的長度。

指針陣列,例如:

int *api[10];

下標參照的優先順序高於間接存取,所以在這個表達式中,首先執行下標參照。因此,api是某種型別的陣列。在取得一個數組元素之後,隨即執行的是間接存取操作。這個表達式不再有其他操作符,所以它的結果是一個整型值。

在實際使用中,一般使用指針陣列的方式而不是字元矩陣來表示字串陣列,但略微對其進行修改:

char const *keyword[] = {
	"do",
	"for",
	"if",
	"register",
	"return",
	"switch",
	"while",
	NULL
}

在表的末尾增加一個NULL指針,這個NULL指針使函數在搜尋這個表時能夠檢測到表的結束,而無需預先知道表的長度,如下:

for (kwp=keyword_table; *kwp != NULL; kwp++)