C语言数组的一些问题

来源:互联网 发布:河南青峰网络 编辑:程序博客网 时间:2024/06/05 02:04

我们都知道,数组名可以当成一个指针,同样的函数名也可以当成一个函数指针,指向函数的入口地址。现在有一个问题,数组名这个指针指向的是什么呢?如果对数组名再取地址,得到的又是什么呢?

我们来验证这两个问题。

输入以下代码:

#include "stdio.h"int main(){int a[3]={1,2,3};//int(*p)[3]=a;printf("%d,%d,%d,%d,%d\n",*a,a,&a,&a[0],sizeof(a));printf("%d,%d,%d\n",*(a+1),a+1,&a+1);    return 1;}

可以得到运行结果是:


可以发现,a和&a还有&a[0]所代表的地址是一样的。但是当我们去计算a+1所代表的地址和&a+1所代表的地址的时候。就会发现,他们所产生的地址增量是不一样的。a=1产生的地址增量是4个字节,也就是一个int型元素的字节。而&a+1所产生的地址增量是12,是整个数组的字节大小。由此可见,a是指向数组的第一个元素,其意义跟&a[0]是一样的,而&a指向的是一整个数组。所以可以这么说,a是一个指向整型的指针,而&a是一个指向整型数组型指针。

继续将上述代码扩展:

#include "stdio.h"int main(){int a[3]={1,2,3};int*p1=a;int(*p2)[3]=&a;printf("%d,%d,%d,%d,%d\n",*a,a,&a,&a[0],sizeof(a));printf("%d,%d,%d\n",*(a+1),a+1,&a+1);printf("%d,%d,%d,%d\n",*p1,p1,p1+1,*(p1+1));printf("%d,%d,%d,%d,%d,%d\n",*p2,p2,p2+1,*(p2+1),**p2,**(p2+1));    return 1;}

需要注意的是,我们将p1定义成一个指向整型的指针,而刚好a也是一个指向整型的指针,因为上面已经说过,a指的是数组的第一个元素的地址,所以它是指向整型元素的。所以可以进行int*p1=a;这样的赋值。而int(*p2)[3]这个指针因为是一个指向3维数组的指针,所以不能进行int(*p2)[3]=a;这样的赋值,因为它们的类型是不匹配的。p2是指向数组的指针,而a是指向整型元素(数组的第一个元素)的指针。所以只能用int(*p2)[3]=&a;这样的赋值方式才是正确的。因为&a正是一个指向数组的指针。

我们的运算结果如下。


可以发现,p1+1的字节移动了4个,而p2+1的字节移动了12个。p1+1指向了数组第二个元素2.而p2+1的地址则偏移了12个字节。因为p2是指向数组的指针。所以p2和*p2代表的值是一样的,因为p2指向整个数组的首地址,而*p2正好指向数组的首元素的地址,这两个地址在数值上是一样的。同样*(p2+1)和p2+1在数组上也是一样的。**p2即时首元素的值,但是**(p2+1)所指向的东西是不确定了,因为它已经调到了下一个数组了,而这个数组可能是不存在的。


我们再将程序进行改进。

#include "stdio.h"int main(){char a[3]={'a','b','c'};int*p1=a;int(*p2)[3]=&a;printf("%d,%d,%d,%d,%d\n",*a,a,&a,&a[0],sizeof(a));printf("%d,%d,%d\n",*(a+1),a+1,&a+1);printf("%d,%d,%d,%d\n",*p1,p1,p1+1,*(p1+1));printf("%d,%d,%d,%d,%d,%d\n",*p2,p2,p2+1,*(p2+1),**p2,**(p2+1));    return 1;}

运行结果如下:


可以发现,当把a数组定义为字符数组以后,a和&a的偏移量分别变为1和3了。但是我们却用一个int*型和一个int(*)[3]型的指针分别指向a和&a。这样直接导致了*p1和**p2是一个不确定的值。所以我们最好不要用这种类型转换。当我们把指针改为char型,则会显示出正确的答案。

此处为什么无法打印出*p1和*p2的值呢?

这是一个问题。

0 0