一,示例
文章的开头让我们来先看关于c语言二维数组及相关指针的几句话。
假设a是一个整型的二维数组名,用<==>代表等价符号。
1,a可以代表这个二维数组的首行首地址,a+i代表序号为i的行的首地址,例如,a+i 和 &a[i]的含义是一样的。
2,c语言规定了数组名代表数组的首元素地址。例如,a[i]代表第i行的数组名,它代表&a[i][0]。
3,a[0] +i <==> &a[0][i] <==> *(a+0) +i
4,a[i] <==> *(a+i)
5,*(*(a+0)+1) <==> a[0][1] <==>*( *a+1)
6,&a[0] <==> &*a <==> a
以上六句话都是从谭浩强的《c程序设计》教材中摘录下来的。如果你不能完全看懂以上六句话,那就说明这篇文章是非常值得你一看+收藏的。
二,你需要先掌握的规则
1,整个数组的地址与数组的首元素地址的值相同,但是含义不一样。
例如:假设a是一个二维数组名,那么a[i]是一个一维数组名。
如果p是a[i]的地址,那么p+1就跳过了整个a[i]数组而指向下一数组,它就是a[i+1]的地址。例如,
将a+i赋值给p,那么p+1<==> &a[i+1]
如果p是a[i]的首元素地址,那么p+1就是a[i][1]的地址。例如,将a[i][0]的地址赋值给p,那么,p+1 <==> &a[i][1]
2,&*a <==> a
对于这个,你可以简记为:&是取址运算,*有取值的功能,它们两个的功能刚好相反,因此就相当于“抵消”了。
三,正文部分
接下来通过一系列实例来带你理解c语言与数组相关的指针运算
假设a是一个二维数组名。
1,a+i <==> &a[i]
首先a是二维数组名,它可以代表数组首元素地址。二维数组都是由一维数组组成的,所以二维数组a的首元素就是一维数组a[0],a就是a[0]的地址,假设为p(p是行指针)。a+i相当于p+i,也就是p跳过i个一维数组后的地址,也就是a[i]的地址,也即&a[i]。
2,*(*(a+i)+j) <==> a[i][j] <==> *(a[i]+j)
首先,由正文第1点可知,a+i <==> &a[i]
所以,上述连等式的第一项可以化为*(*&a[i] +j) ==>*(a[i] + j)(恰好等于连等式的第三项)
将a[i]赋值给p,那么p就是列指针,那么a[i]+j 相当于p+j, 也即&a[i][j]
所以原式 ==>*&a[i][j] ==>a[i][j]。
3,*(a+1)和*a+1和*(p+1)与*p+1
如果a是二维数组,那么a+1就是&a[1],*(a+1)就是a[1]。
*a就是a[0],也就是&a[0][0],那么*a+1就是&a[0][0]+1,也就是&a[0][1]。
如果p是一维数组名,该数组={1,1,0,1}。那么*(p+1)就是*&p[1],也就是p[1],也就是1。
*p+1就是*&p[0]+1,也就是p[0]+1,也就是1+1,也就是2。
4,*a和*a[0]
*a就是*&a[0],也即a[0]。
*a[0]就是*&a[0][0],也即a[0][0]。
5,&a[0][0]与&a[0]
&a[0][0]是数组a[0]的首元素地址,&a[0]是整个数组a[0]的地址。它们的值相同但是含义不同。
四,附录
附录:关于指针变量及其值的类型的理解、相关术语辨析
设有如下语句:
int *p,a=0;
int **p2;
p=&a;
p2=&p;
1,指针变量的值,也就是指针变量本身,比如上述的一级指针p,它的值(内容)就是a的地址,写作&a,这个值的类型是int*,因为在第三行将a的地址取出来赋给了p。而指针p2的值就是p的地址,写作&p,这个值的类型是int**。
2,指针地址的值,指针地址的值就是指针的地址。上述代码中,a的地址就是p的值,p的地址就是p2的值。
3,指针指向的值。上述代码中,指针p指向的值就是*p,也就是a,类型为int。指针变量p2指向的值就是*p2,也就是p,类型为int*。
参考资料:谭浩强的《c程序设计》第四版