本小白学艺不精,偶然碰到一个数组指针的报错,百思不得其解,最终自认为是搞懂了。想把自己发现错误,解决错误,研究错误的历程记录下来,如果能帮到大家更好了。
第一次发博客记录一下,如有错误希望路过的佬们指点一下。
文末自己画的图是重点!!!
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int a[3] = {10,4,6};
int (*p)[3] = a;
printf("%p",p);
return 0;
}
报错如下:
0x7ffd8c5c9b0cmain.c: In function ‘main’:
main.c:8:19: warning: initialization of ‘int (*)[3]’ from incompatible pointer type ‘int *’ [-Wincompatible-pointer-types]
8 | int (*p)[3] = a;
| ^
发现指针类型不兼容,网上简单搜索了一下,发现了正确的写法,如下:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int a[3] = {10,4,6};
//int *p = a;
int (*p)[3] = &a;
printf("%p",p);
return 0;
}
输出为
0x7ffccbe54a4c
可是这是为什么呢,按理来说数组名可以被解释为指向数组第一个元素的指针,而(*p)[3]就是指针变量,加不加&都一样的呀。
我们接下来做一个知识回顾,后面解释报错的原因。
int main(void)
{
int a[3] = {10,4,6};
int *p = a;
//int (*p)[3] = &a;
printf("p:%p\n",p);
printf("&p:%p\n",&p);
printf("&p[0]:%p\n",&p[0]);
printf("%d\n",sizeof(p));
printf("%d\n",sizeof(&p));
printf("%d\n",sizeof(*p));
return 0;
}
输出如下:
p:0x7ffecfba9e04
&p:0x7ffecfba9df8
&p[0]:0x7ffecfba9e04
8
8
4
&p是指针变量所在的地址,不用多说肯定和其他两个不一样。p和&p[0]一样,sizeof(p)和sizeof(*p)分别等于8和4,sizeof(p)=8可以理解为64位操作系统上的指针占8个字节,sizeof(*p)中的*p是解引用,也就是a[0]的值,是一个int变量,占4个字节。
“数组名可以被解释为指向数组第一个元素的指针”是因为编译器会自动进行隐式的指针类型转换。也就是说错误写法int (*p)[3] = a中的a此时代表第一个元素地址的指针,指针是有类型的,a[0]是10,a就是指向int型整数10的指针。
再看int (*p)[3] = a;报的错initialization of ‘int (*)[3]’ from incompatible pointer type ‘int *’ ,类型不兼容,那么(*p)[3]肯定不是指向int型整数的指针。
分析一下int (*p)[3],由于[]优先级比*高,而我们需要的是指针,所以在前面加括号得到(*p)这个指针,后面的[3]代表有三个元素的数组,(*p)[3]代表是数组指针,int (*p)[3]代表是整型的数组指针,指向一个整型数组,而a指向int型整数,所以报错。
那为什么int (*p)[3] = &a;就不报错呢?
int a[3] = {10,4,6};表示a是整型数组,&a就是指向整型数组的地址,因此可以赋值给int (*p)[3]。
这就是int (*p)[3] = &a不会报错而int (*p)[3] = a报错的原因。
---------------------------------------------------------------------------------------
int main(void)
{
int a[3] = {10,4,6};
//int *p = a;
int (*p)[3] = &a;
printf("%p\n ",p);
printf("%p\n ",*p);
printf("%p\n ",a);
printf("%d ",sizeof(p));
printf("%d ",sizeof(*p));
printf("%d ",sizeof(a));
return 0;
}
--------以下是输出----------
0x7ffd8bfce43c
0x7ffd8bfce43c
0x7ffd8bfce43c
8 12 12
p整个数组的地址,指向a[0],我以为printf("%p\n ",*p);的结果会是a[0]=10,结果还是地址。
*p代表解引用,引用是p(也就是指向的地址),解引用就是把地址内的内容解析出来。
如果是int *p = a;那么p指向的首元素的地址,解析就是数组首元素。
在C++中,数组名是指向数组第一个元素的指针。数组元素可以通过下标运算符 []
访问,这是因为在使用数组下标时,编译器会将其解释为指针加偏移量的形式。所以,arr[i]
实际上是 *(arr + i)
的缩写,表示指针 arr
指向的地址偏移 i
个 int
的大小。这就是为什么你可以使用 arr[i]
来访问动态分配的数组元素。
重点:
int (*p)[3] = &a说明p存放的地址指向的内存中存放的是数组,偏移也会按照整个数组的字节偏移,这也就是为什么sizeof(a)=12。如果int (*p)[3] = a,a代表首元素地址,该数组默认首元素是默认int,所以报错类型不匹配。
下面自己做了个图,帮助理解:
如果想到什么相关知识点我会继续补充的,谢谢大家能看到这,欢迎评论指导。