7. 指向數組的指針與多維數組

指針可以指向復合類型,上一節講了指向指針的指針,這一節學習指向數組的指針。以下定義一個指向數組的指針,該數組有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]取的也是同一個元素,而且paa用起來更靈活,數組名不支持賦值、自增等運算,而指針可以支持,pa++使pa跳過二維數組的一行(40個位元組),指向a[1]的首地址。

習題

1、定義以下變數:

char a[4][3][2] = {{{'a', 'b'}, {'c', 'd'}, {'e', 'f'}},
		   {{'g', 'h'}, {'i', 'j'}, {'k', 'l'}},
		   {{'m', 'n'}, {'o', 'p'}, {'q', 'r'}},
		   {{'s', 't'}, {'u', 'v'}, {'w', 'x'}}};

char (*pa)[2] = &a[1][0];
char (*ppa)[3][2] = &a[1];

要想通過pappa訪問數組a中的'r'元素,分別應該怎麼寫?