指針可以指向復合類型,上一節講了指向指針的指針,這一節學習指向數組的指針。以下定義一個指向數組的指針,該數組有10個int
元素:
int (*a)[10];
和上一節指針數組的定義int *a[10];
相比,僅僅多了一個()
括號。如何記住和區分這兩種定義呢?我們可以認為[]
比*
有更高的優先順序,如果a
先和*
結合則表示a
是一個指針,如果a
先和[]
結合則表示a
是一個數組。int *a[10];
這個定義可以拆成兩句:
typedef int *t; t a[10];
t
代表int *
類型,a
則是由這種類型的元素組成的數組。int (*a)[10];
這個定義也可以拆成兩句:
typedef int t[10]; t *a;
t
代表由10個int
組成的數組類型,a
則是指向這種類型的指針。
現在看指向數組的指針如何使用:
int a[10]; int (*pa)[10] = &a;
a
是一個數組,在&a
這個表達式中,數組名做左值,取整個數組的首地址賦給指針pa
。注意,&a[0]
表示數組a
的首元素的首地址,而&a
表示數組a
的首地址,顯然這兩個地址的數值相同,但這兩個表達式的類型是兩種不同的指針類型,前者的類型是int *
,而後者的類型是int (*)[10]
。*pa
就表示pa
所指向的數組a
,所以取數組的a[0]
元素可以用表達式(*pa)[0]
。注意到*pa
可以寫成pa[0]
,所以(*pa)[0]
這個表達式也可以改寫成pa[0][0]
,pa
就像一個二維數組的名字,它表示什麼含義呢?下面把pa
和二維數組放在一起做個分析。
int a[5][10];
和int (*pa)[10];
之間的關係同樣類似於int a[10];
和int *pa;
之間的關係:a
是由一種元素組成的數組,pa
則是指向這種元素的指針。所以,如果pa
指向a
的首元素:
int a[5][10]; int (*pa)[10] = &a[0];
則pa[0]
和a[0]
取的是同一個元素,唯一比原來複雜的地方在於這個元素是由10個int
組成的數組,而不是基本類型。這樣,我們可以把pa
當成二維數組名來使用,pa[1][2]
和a[1][2]
取的也是同一個元素,而且pa
比a
用起來更靈活,數組名不支持賦值、自增等運算,而指針可以支持,pa++
使pa
跳過二維數組的一行(40個位元組),指向a[1]
的首地址。