Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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' 元素,分别应该怎么写?