C语言数组指针解析

本小白学艺不精,偶然碰到一个数组指针的报错,百思不得其解,最终自认为是搞懂了。想把自己发现错误,解决错误,研究错误的历程记录下来,如果能帮到大家更好了。

第一次发博客记录一下,如有错误希望路过的佬们指点一下。

文末自己画的图是重点!!!

#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 指向的地址偏移 iint 的大小。这就是为什么你可以使用 arr[i] 来访问动态分配的数组元素。

重点:

int (*p)[3] = &a说明p存放的地址指向的内存中存放的是数组,偏移也会按照整个数组的字节偏移,这也就是为什么sizeof(a)=12。如果int (*p)[3] = a,a代表首元素地址,该数组默认首元素是默认int,所以报错类型不匹配。

下面自己做了个图,帮助理解:

如果想到什么相关知识点我会继续补充的,谢谢大家能看到这,欢迎评论指导。

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值