关于指针的问题(高手进)

来源:百度知道 编辑:UC知道 时间:2024/09/24 14:20:10
我用的VC++6.0 但使用的是C编译器。
先给定一个数组:
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}

经试验发现,只有这样的定义指针:int (*p)[4];
才能这样赋值:p=a,(否则warning C4047: '=' : 'int ' differs in levels of indirection from 'int (*)[4]')
当然这句话其实是相当于p=a+0,也就是把p指向a的第0排这个数组(有4个元素)。
p+1相当于指针移到a[1]。

我的问题是:为什么p要有4个元素,明明一根指针就够用了啊。
p有4个元素,某次运行下面测试程序:

int *a1,*a2,*a3,*a0;
a0=p[0];a1=p[1];a3=p[3];a2=p[2];

得到以下结果:
a0==0x0012ff30
a1==0x0012ff40
a2==0x0012ff50
a3==0x0012ff60

我的a==0x0012ff30

我可以理解p[0]、p[1]、p[2]分别指向a的三个行
但p[4]指向的是a[3][4]的下个单元,(某次运行中该单元的值为1244976,显然不是什么我需要的数据)
而且我们用p也是这样用的:
x=*(*(p+1)+2);
表示x=a[1][2]
完全没用到p[1]、p[2]、p[3]
那么p[1]、p[2]、p[3]有什么用?

谢谢
“但p[4]指向的是a[3][4]的下个单元”写错了,应该是“但p[3]指向的是a[3][4]的下个单元”

楼主分析得完全正确。

指针和数组是C语言中理解起来特别麻烦的知识点。

曾在一本书中读到作者分析指针的规律(可能他是从编译器编译规则的角度得出这样的规律的,因此也许不是规律,只是编译规则)。
该规律是:向左看,遇到括号向右看,遇到括号或没有任何东西再向左看。
因此,int(*p)[4]被解释为:p的左边是*,p是个指针,*的左边是括号,需要向右看,右边是[4],说明p指向了一个具有4个数组元素的数组,[4]的右边没有东西,再向左看,int,说明p是一个指针,指向了具有4个数组元素的数组,该数组的每一个元素为int。

再整理一下就是,p是个指向具有4个int的数组的指针。说得再精确点是:p是个指向具有4个int的数组首地址的指针。

然后得出,*p不是一个int,*p仍然是一个地址,它是一个数组的首地址。

关于指针的换算,估计楼主应该完全掌握了,再整理一下:
int *p;
int a[4];
p = a;
//p[1]== a[1] == *(p + 1)

另外指针做加减法前后的地址差是由指针所指向的数据所决定的。

char a[2];
//sizeof(a) = sizeof(char) * 2 = 2

int i[2];
//sizeof(i) = sizeof(int) * 2 = 8

然后根据楼主给出的例子中一个最复杂的赋值语句做分析:
x=*(*(p+1)+2);
p指向了一个数组首地址(就是开始分析的那个p,这里就简单进行描述),p + 1将使p连续跳过4个int,指向其后的地址。跳过4个int是因为p指向的是个数组首地址。p + 1类似p++。p与p+1的地址差值为16个字节(4*sizeof(int)== sizeof(*p))因此*(p + 1) = a[1] = p[1]。
最后
*(p[1] + 2) = a[1][2] = *(*(p + 1) + 2);

不知道楼主是否理解了p[1]、p[2]、p[3]。