数组指针和指针数组
注: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])=8,sizeof(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]是一个指针,所以大小按指针的计算方法。
思路图:
完!以上纯属个人理解。如有错误请在评论区指出,我会给予修改谢谢。