若有以下定义:
int a[3][4],i,j;
且0≤i<3、0≤j<4,则a数组元素可用以下五种表达式来引用:
(1)a[i][j]
(2) * (a[i]+j)
(3)*(*=(* (a+i)+j)
(4)(*(a+i))[J]
(5)*(&a[0][0]+4*i+j)
在(2)的表达式半(a[i]+j)中,因为a[i]的基类型为int,j的位移量为2×j字节。
在(3)的表达式*(*(a+i)+j)中,a的基类型为4个元素的数组,i的位移量为4×2×
i字节;而*(a+i)的基类型为int,j的位移量仍为2×J字节。
在(4)中,*(a+i)外的一对圆括号不可少,若写成:*(a+i)[ j],因为运算符[]的优先级高于*号,表达式可转换成:*(*((a+i)+ j)),即为:*(*(a+i+ j)),这时i+J将使得位移量为4×2 X(i+J)个字节,显然这已不是元素a[i][j]的地址。*(*(a+i+j))等价于*(a[i+ j]),等价于a[i+J][0],引用的是数组元素a[i+ j][0],而不是a[i][ j],很可能早已超出数组定义的范围。
在(5)中,&a[0][0]+4术i+J代表了数组元素a[i][J]的地址,通过问址运算符*号,表达式*(&a[0][0]+5*i+ j)代表了数组元素a[i][ j]的存储单元。
若有以下定义:
int * P[3],a[3][2],i,j;
在这里,说明符*P[3]中,也遵照运算符的优先级,一对[]的优先级高于*号,因此P首先与[]结合,构成P[3],说明了P是一个数组名,系统将为它开辟3个连续的存储单元;在它前面的*号则说明了数组P是指针类型,它的每个元素都是基类型为int的指针。若满足条件:0≤i<3,则P[i]和a[i]的基类型相同,P[i]=a[i]是合法的赋值表达式。若有以下循环:
for(i=0;i<3;i++)P[i]=a[i];
在这里,等号右边的a[i]是常量,表示a数组每行的首地址,等号左边的P[i]是指针变量,循环执行的结果使P[0]、P[1]、P[2]分别指向a数组每行的开头。这时,数组P和数组a之间的关系如图9.6所示。
当P数组的每个元素已如图9.6所示指向a数组每行的开头时,财a数组元素a[i][j]的引用形式术(a[i]+j)和*(P[i]+ j)是完全等价的。由此可见,这时可以通过指针数组P来引用a数组元素,它们的等价形式如下:
(1)*(P[i]+j) /*与术(a[i]+j)对应*/
(2)*(*(P+i)+j) /*与*(*(a+i)+j)对应*/
(3)(*(P+i))[j] /*与(*(a+i))[j]对应*/
(4)P[i][j] /*与a[i][j]对应*/
不同的是:P[i]中的值是可变的,而a[i]中的值是不可变的。