指向数组的指针和指针指针有什么区别?

我是编程和学习数组指针的新手。 我现在有点困惑。 看看下面的程序:

#include  int fun(); int main() { int num[3][3]={23,32,478,55,0,56,25,13, 80}; printf("%d\n",*(*(num+0)+1)); fun(num); printf("%d\n", *(*(num+0)+1)); *(*(num+0)+0)=23; printf("%d\n",*(*(num+0))); return 0; } int fun(*p) // Compilation error { *(p+0)=0; return 0; } 

这是我老师的笔记中写的程序。 在main()函数中,在printf()函数中,dereference运算符被使用了两次,因为num是指向数组的指针,因此第一次取消引用运算符将​​指向int ,然后第二个将给出指针所在的值指向。

我的问题是,当我将数组名称作为参数传递给函数fun()为什么使用*p ; 为什么不**p作为num是指向数组的指针?

第二件事为什么*(p+0)用于改变数组的第0个元素的值; 为什么不*(*(p+0)+0)=0因为main()函数*(*(num+0)+0)用于改变第0个元素的值?

整件事对我来说很困惑,但无论如何我必须要理解它。 我已经搜索了这个,发现指向数组的指针和指向指针之间有区别,但我无法理解。

诀窍是数组指针衰减 :当你提到数组的名称时,它会在几乎所有上下文中衰变为指向其第一个元素的指针。 那就是num只是一个由三个整数组成的三个数组的数组(type = int [3][3] )。

让我们分析表达式*(*(num + 1) + 2)

当您在表达式*(num + 1)提及num时,它会衰减为指向其第一个元素的指针,该元素是一个包含三个整数的数组(type = int (*)[3] )。 在此指针上执行指针运算,并将指针指向的任何大小添加到指针的值。 在这种情况下,它是三个整数数组的大小(在许多机器上是12个字节)。 取消引用指针后,你会得到一个int [3]类型。

但是,这种解除引用仅涉及类型,因为在解除引用操作之后,我们看到表达式*(/*expression of type int[3]*/ + 2) ,因此内部表达式衰减回指向第一个数组元素的指针。 此指针包含与从num + 1得到的指针相同的地址,但它具有不同的类型: int* 。 因此,对该指针的指针运算使指针前进两个整数(8个字节)。 因此表达式*(*(num + 1) + 2)产生偏移量为12 + 8 = 20字节的整数元素,这是数组中的第六个整数。


关于你关于fun()的调用的问题,这个调用实际上是被打破的,并且只有你的老师没有在fun()的前向声明中包含参数才有效。 代码

 int fun(int* arg); int main() { int num[3][3] = ...; ... fun(num); } 

由于指针类型错误,会产生编译时错误。 老师的代码“有效”,因为指向num第一个数组的指针与指向num第一个数组的第一个元素的指针相同,即他的代码相当于

 int fun(int* arg); int main() { int num[3][3] = ...; ... //both calls are equivalent fun(num[0]); fun(&num[0][0]); } 

这将编译没有错误。

此示例显示了一个矩阵,指向数组的第一个整数的指针和指向指针的指针

 #include int fun(int (*p)[3]); /* p is pointer to array of 3 ints */ int main() { /* matrix */ int num[3][3]={{23,32,478},{55,0,56},{25,13, 80}}; /* three pointers to first integer of array */ int *pnum[3] = {num[0], num[1], num[2]}; /* pointer to pointer */ int **ppnum = pnum; printf("%d\n", *(*(num+1)+2)); fun(num); printf("%d\n", *(*(num+1)+2)); pnum[1][2] = 2; printf("%d\n", *(*(num+1)+2)); ppnum[1][2] = 3; printf("%d\n", *(*(num+1)+2)); return 0; } int fun(int (*p)[3]) { p[1][2]=1; return 0; } 

你实际上并不需要任何指针来打印任何东西。

你的int num[3][3]实际上是一个由三个元素组成的数组,每个元素都是一个由三个整数组成的数组。 因此num[0][0] = 23num[1][1] = 0 ,依此类推。 因此,您可以说printf("%d", num[0][0])来打印数组的第一个元素。

指向变量的指针:

指针是变量,用于存储( 变量的 )地址。 每个人都知道。


数组指针:

数组是一个变量,它具有相同对象组的起始点(地址)。

指针是一个存储数组起始点(地址)的变量。

例如:

 int iArray[3]; 

iArray是一个变量,其地址值为三个整数,并且内存是静态分配的。 以下语法以典型的编程语言提供。

 // iArray[0] = *(iArray+0); // iArray[1] = *(iArray+1); // iArray[2] = *(iArray+2); 

在上面,iArray是一个变量,通过它我们可以使用上面提到的任何语法访问三个整数变量。

*(+ iArray 0); //这里iArray + 0是第一个对象的地址。 *是取消引用*(iArray + 1); //这里iArray + 1是第二个对象的地址。 *是取消引用

这么简单,有什么可以混淆的。


以下行是为了您的理解

 int iArray1[3]; int iArray2[3][3]; int *ipArray = 0; ipArray = iArray1; // correct ipArray = iArray2[0]; // correct ipArray = iArray2[2]; // correct int **ippArray = iArray2; // wrong 

根据上面的最后一行,编译器不会将其作为有效赋值。 所以没有使用** p。

由于分配内存的方式,指针关节不能应用于双数组。