关于C语言数组指针和指针数组的深入理解

数组指针和指针数组

注:64位机一个指针占8个字节
一、数组指针
数组指针是一个指向一维数组的指针

int (*p)[3];	//表示指向一个有3个int型元素的一维数组

问题1:
数组指针如何指向二维数组,猜测输出1的结果为多少?并且如果把int (*p)[3]中的3改成4是否可行。
问题2:
数组指针中的&p,p,*p是什么关系?观察输出2-4。
问题3
观察sizeof( p),sizeof(p[0]),sizeof(p[0][0])运行结果,为什么?

/*
*author:CXB-2019-12
*/

#include <stdio.h>
int main(){     
int a[3][3]={{1,2,3},{4,5,6},{7,8,9}};  //二维数组本质也是一维存储模式
int (*p)[3]=a;	//数组指针p指向二维数组 a       
 
    printf("sizeof(p)=%d,sizeof(*p)/sizeof(p[0])=%d,sizeof(p[0][0])=%d\n",(int)sizeof(p),(int)sizeof(p[0]),(int)sizeof(p[0][0]));
    
    printf("p[1][1]=%d\n",p[1][1]);	 //输出1
        
    printf(" p=%p, p+1=%p\n",p,p+1);     //输出2
    printf("*p=%p,*p+1=%p\n",*p,*p+1);	 //输出3         
    printf("&p=%p,&p+1=%p\n",&p,&p+1);	 //输出4
    
    return 0;
    }

运行结果:地址以16进制显示,自行转换

sizeof(p)=8,sizeof(*p)/sizeof(p[0])=12,sizeof(p[0][0])=4
p[1][1]=5
 p=000000000061FDF0, p+1=000000000061FE00
*p=000000000061FDF0,*p+1=000000000061FDF4
&p=000000000061FE18,&p+1=000000000061FE20

从运行结果看:
问题1:
输出1结果为5。
当3改为4时输出结果为6,但是会触发警告:指针兼容性问题。所以数组指针后面[ ]的值要与对应数组一致才能指向该数组,避免兼容性问题。

warning: incompatible pointer types assigning to 'int (*)[4]' from 'int [2][3]'

问题2:
p到 p+1增加了16个字节;p到p+1增加了4个字节;&p到&p+1增加了8个字节;
解释(配合下面的思路图理解):
*p到 *p+1增加的是数组里面一个元素的大小(int型=4个字节), *p是指向大小为4的数组的首地址,加1表示下移一个元素大小的地址。
p到 p+1增加的是4个数组元素大小的和,因为p指向的是 *p这个单元地址,这个单元总大小是一个含有4个元素数组(4X4B=16字节),p+1表示指向下一个单元地址。
&p到&p+1增加的8字节是p指针的大小,64位机一个指针占8个字节,&p+1表示指向下一个指针 ,间隔8字节。

注:输出5和6是一维数组与指针,同样涉及指针地址本身+1则+8字节处理,对于指针里面存的目标地址+1则按目标单元大小进行处理。
问题3
可以看到运行结果是sizeof§=8,sizeof(*p)/sizeof(p[0])=12,sizeof(p[0][0])=4
p[0][0]是4因为其是int类型元素;而p=8说明其是一个指针;*p=12则说明它是一个数组,一个含3个int类型(4字节)元素的数组。

补充: 如果你不理解则看图下面的指针与一维数组的程序
思路图
额
补充程序内容:

/*
*author:CXB-2019-12
*/

#include <stdio.h>
int main(){    
int a[4]={1,2,3,4};    
int *p=a;

   printf("sizeof(p)=%d,sizeof(a)=%d,sizeof(a[0])=%d\n",(int)sizeof(p),(int)sizeof(a),(int)sizeof(a[0]));
   printf("&p=%p,&p+1=%p\n",&p,&p+1);    
   printf(" p=%p, p+1=%p\n",p,p+1);    
   printf(" a=%p, a+1=%p\n",a,a+1);
   return 0;
   }

输出结果:

sizeof(p)=8,sizeof(a)=16,sizeof(a[0])=4
&p=000000000061FE10,&p+1=000000000061FE18
 p=000000000061FE00, p+1=000000000061FE04
 a=000000000061FE00, a+1=000000000061FE04

分析:
可以看到数组a的大小就是其元素个数X元素类型大小,而指针p仍是8。
往下看&p是存储指针p的地址,+1就是后移指针p的大小。
你会发现指针p指向数组a,所以p与a的地址递进方式是一样的,但是他们还是本质还是不同的,指针p只不过是存储了a的地址副本。

二、指针数组
指针数组是一个数组元素为指针的数组。

char *a[4];	

问题1:
看输出1结果,为什么?

问题2:
a和a[0]和a[0][0]各代表什么,他们关系是什么?

/*
*author:CXB-2019-12
*/

#include <stdio.h>

int main(){    
int * q;    
char * p;    
char *a[4]={"abc","vbcc","tom","t"};    //注意每个字符串末尾还有空字符'\0'
printf("sizeof(a[0])=%d,sizeof(a[1])=%d,sizeof(a)=%d,sizeof(a[0][0])=%d\n",(int)sizeof(a[0]),(int)sizeof(a[1])(int)sizeof(a),(int)sizeof(a[0][0]));  //输出1    
printf("   sizeof(P)=%d,sizeof(q)=%d\n",(int)sizeof(p),(int)sizeof(q)); //不同类型指针的大小是一致的    
printf("  a[0]=%p, a[1]=%p\n",a[0],a[1]);  //每个行数组元素的首地址    
printf("a[0]+1=%p\n",a[0]+1);    
printf("&a[0]=%p,&a[1]=%p\n",&a[0],&a[1]);//数组元素单元本身的地
printf("   &a=%p, &a+1=%p\n",&a,&a+1);       
printf("&a[0][0]=%p\n",&a[0][0]);

printf("  a=%p  &a=%p\n",a,&a);    
printf("a+1=%p &a+1%p\n",a+1,&a+1);        
return 0;
}

运行结果:

sizeof(a[0])=8,sizeof(a[1])=8sizeof(a)=32,sizeof(a[0][0])=1
   sizeof(P)=8,sizeof(q)=8
  a[0]=0000000000404000, a[1]=0000000000404004
a[0]+1=0000000000404001
&a[0]=000000000061FDE0,&a[1]=000000000061FDE8
   &a=000000000061FDE0, &a+1=000000000061FE00
&a[0][0]=0000000000404000
  a=000000000061FDE0  &a=000000000061FDE0
a+1=000000000061FDE8 &a+1000000000061FE00

问题一
结果sizeof(a[0])=8,sizeof(a[1])=8,sizeof(a)=32,sizeof(a[0][0])=1,说明a[0]、a[1]是char类型指针;a指向了a[0]-a[3]的这个指针数组,大小为=4X8=32B;而a[0][0]=1就是一个char类型字符所占空间一个字节。
问题二
a[0][0]都知道它代表字符’a’,从 a[0]=&a[0][0]结果看。说明二者都表示的是字符’a’的地址,由指针的定义可知a[0]存的的是a[0][0]元素的地址。类推到&a[0]=a,说明a存放的是a[0]指针的地址。
总结:a指向了一个存有4个char类型指针的数组,char类型指针又分别指向对应的char类型数据的数组。a是一个数组所以大小按数组元素个数X大小=结果来运算;而a[0]是一个指针,所以大小按指针的计算方法。
思路图:
在这里插入图片描述
完!以上纯属个人理解。如有错误请在评论区指出,我会给予修改谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值