在上一篇文章中,我们了解了数组与指针的基本原理、内存使用情况,顺便扩展了二维数组与指针数组的知识点,但对于高级指针的使用仅仅只说明其与一级指针的相似情况,这篇文章便是讲解高级指针的具体原理。
(上篇文章)C/C++中指针、数组、二维数组与指针数组的理解与原理_都是说说而已的博客-CSDN博客
我们承接上篇文章的指针数组开始。在上篇文章中我们说过,指针数组实际上是一个由指针组成的数组,表面上是个一维数组,但由于每个数组元素是指针,它可以指向一个数组,因此本质上是个二维数组,验证代码:
char* A[2] = {"hello","world"};
for (int i = 0; i <= 1; i++)
{
for (int j = 0; j <= 4; j++)
{
printf("%c", A[i][j]);
}
printf(" ");
}
既然指针数组本质上是个二维数组,那么数组名A自然就是个二级指针了,那我们可以用一个二级指针指向指针数组吗?代码验证:
char* A[2] = {"hello","world"};
char** p;
p = A;
for (int i = 0; i <= 1; i++)
{
for (int j = 0; j <= 4; j++)
{
printf("%c", p[i][j]);
}
printf(" ");
}
编译通过,运行没错误,说明是可以的,因此当我们要传递指针数组参数时,函数中形参的定义形式为:int** p,即某种类型(取决于指针数组中指针的类型)的二级指针。
接下来我们来看二维数组,既然指针数组可以用二级指针指向,那么二维数组也应当可以,我们来验证一下:
int A[3][3] = {{0,1,2},{3,4,5},{6,7,8}};
int** p;
p = A;
for (int i = 0; i <= 2; i++)
{
for (int j = 0; j <= 2; j++)
{
printf("%d", p[i][j]);
}
}
然而连编译都没有通过,编译器报了这样一个错误:
错误(活动) E0513 不能将 "int (*)[3]" 类型的值分配到 "int **" 类型的实体
这是怎么回事?同是二级指针为什么指针数组可以,二维数组就不行?我们暂时不管错误提示,先来想想其中的缘由。事实上要想p = A编译通过,首先要保证p与A应该是同类型的,就像int类型变量给int类型变量赋值。我们来看一维数组的情况,一维数组名是个一级指针,它的加一操作是指向下一个数组元素(*(A+1)等价于A[1] ),而一级指针的加一操作也是指向下一个元素,当我们用一级指针指向一维数组后,它们的加一操作是等效的。那么二维数组与二级指针也是这样吗?二维数组名的加一是指向下一个一维数组,也即下一行(*(A+1)等价于A[1] ),但二级指针加一是指向下一个指针,很明显,这两者是不等价的,而二级指针的加一操作却与指针数组名加一操作等价,我们来看图解:
可以看到,二级指针p+1等效于指针数组的A+1,而不等效二维数组的A+1。那么为什么p+1是保存的地址值+8呢?这是因为在x64条件下,指针占8个字节(64位地址)。
如果二级指针不能指向二维数组,那么该用什么指针呢?错误信息的提示是“int (*)[3]”,这就是我们要说的数组指针了。故名思意就是指向数组的指针,其中的[3]就是定义指向的数组的元素个数,数组指针的加一操作就是指向下一个数组(加一的实质是地址加上类型字节长*数组长),这跟二维数组名的加一操作是等效的。代码验证:
int A[3][3] = {{0,1,2},{3,4,5},{6,7,8}};
int (*p)[3];
p = A;
for (int i = 0; i <= 2; i++)
{
for (int j = 0; j <= 2; j++)
{
printf("%d", p[i][j]);
}
}
现在我们可以了解到,二维数组名虽然是个二维指针,但它本质上是个数组指针。因此对于二维数组的参数传递,我们的形参形式为int (*p)[3](其中的类型为二维数组中元素的类型,[3]为二维数组中一维数组的长度),这也就是为什么形参用int p[][3]形式时可以省略二维数组的行,其本质就是数组指针。
在弄懂了二维数组与二级指针的关系后,三级指针与三维数组的不同点也就很好理解了,对于一个三维数组,其数组名是个三级指针,但本质是个二维数组指针,数组名加一表示指向下一个二维数组,定义形式为int (*p)[3][3](int为三维数组元素类型,[3][3]为三维数组中二维数组的元素个数,即行和列)。对于二维指针数组,其数组名是个三级指针,但本质上是个数组指针,指向的指针数组中的元素的类型为指针,数组名加一表示指向下一个指针数组,定义形式为int* (*p)[3](int*为数组中指针的类型,[3]为指针数组的长度)。具体的测试就靠你们自己完成了。