本帖最后由 neverBingo 于 2019-7-22 11:42 编辑
我想尝试一下回答这个问题。实际上,近期我也在学习C语言,对于其中的指针问题,也在痛苦地理解中。
小甲鱼在课程中,将“数组指针”和“指针数组”两个概念放在一起讲,避免大家混淆。但我在理解的过程中,发现“数组指针”和“指向数组的普通指针”两者更容易混淆。
一、“数组指针”和“指向数组的一般指针”
这两者都是指向数组的(这里是简要地说,更为精确的说法则不是这样),所有两者非常具有迷惑性。让我们来看看他们的定义:
- int a[3] = {1, 2, 3};
- int (*pa)[3] = &a; //数组指针
- int *pb = a; //指向数组的一般指针
复制代码
从上面内容看,他们都指向这个数组,使用的时候非常容易混淆。
特别当我们打印地址时:
- printf("pa -> %p\n", pa);
- printf("pb -> %p\n", pb);
复制代码
pa和pb打印出来的内容,是一样的,这就让我们更难区分他们。
二、他们到底指向的是什么?
从我最近的理解来看,两者从指向的内存的角度来看,还是存在比较大的差异的。
pa是数组指针,他指向的内存地址是从数组的首地址开始的连续3个int内存单元(就是12个字节)。
pb是普通指针,他指向的内存地址是从数组的首地址开始的连续1个int内存单元(就是4个字节)。
以上的差异可以从下面的语句看出来:
- printf("pa+1 -> %p\n", pa+1);
- printf("pb+1 -> %p\n", pb+1);
复制代码
当我们将指针向数组的尾巴方向移动1个位置时,pa移动的是12个字节,而pb移动的是1个字节。
这样的结果,反映了我前面的理解。
以这样的理解,来看待数组的定义。如果将前面的数组按照如下的方式定义,则更容易看出差异:
- int (*pa)[3] = &a;
- int *pb = &a[0];
复制代码
你看,数组定义的时候,都是对某一对象进行取址运算,数组指针是对数组进行取址,普通指针是对具体的存储内容进行取址。
三、回到楼主的问题上来
当我们要定义一个数组指针的时候,我们首先要明白,这个指针想指向谁?
以楼主的例子来说,数组array是一个二维数组,第一维包含两个对象,分别是两个数组;第二维前三个是一个数组,后三个又是一个数组,我们把这两个数组暂且称为第二维数组。
如果想指向整个二维数组,就应该定义为(*p)[2][3] = &array
如果想指向两个第二维数组中的第一个,就应该定义为(*p)[3] = &array[0];当然,你也可以指向第二个,(*p)[3] = &array[1]
当指向第一个时,由于array的首地址值恰好就是 &array[0],所以也写成(*p)[3] = array
那么,能不能将指针只指向第一维数组呢,就是能不能写成 (*p)[2] = &array呢?
楼主可以试一试,应该是不能的,因为如果不提供第二维数组中变量的个数,编译过程中无法计算出指针到底要指向多少内存单元。
以上就是我的一点浅见,仅供参考。