多维数组指针&指向分数组的指针&指针运算

引言

在学习了一维数组指针之后,我们可能会对多维数组指针和指向分数组的指针产生疑惑,下面我将以二维数组为例,简单地为大家解释一下该内容。

正文

首先我们定义一个二维数组a[3][4]

int a[3][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};

二维数组本质上也是一维数组,在物理存储上它仍是线性排列,只不过在逻辑上是具有空间概念的,我们来运行下列代码来验证我们的想法。

	int a[3][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};
	int i,j;
	printf("sizeof(int)=%zu\n",sizeof(int));
	for(i=0;i<3;i++)
	for(j=0;j<4;j++)
	printf("a[%d][%d]的地址是:%p\n",i,j,&a[i][j]);
	

运行结果:

sizeof(int)=4
a[0][0]的地址是:000000000062FDE0
a[0][1]的地址是:000000000062FDE4
a[0][2]的地址是:000000000062FDE8
a[0][3]的地址是:000000000062FDEC
a[1][0]的地址是:000000000062FDF0
a[1][1]的地址是:000000000062FDF4
a[1][2]的地址是:000000000062FDF8
a[1][3]的地址是:000000000062FDFC
a[2][0]的地址是:000000000062FE00
a[2][1]的地址是:000000000062FE04
a[2][2]的地址是:000000000062FE08
a[2][3]的地址是:000000000062FE0C

也就是:

a[0][0]a[0][1]a[0][2]a[0][3]a[1][0]a[1][1]a[1][2]a[1][3]a[2][0]a[2][1]a[2][2]a[2][3]
123456789101112

了解二维数组的物理存储后我们了解一下对应的指针,技巧和方法如下:

Key

1. 数组名是指向0号分量的指针常量,基类型大小为0号分量的大小
例如:
a是指向0号分数组的指针常量,它的基类型大小是整个0号分数组的长度,即sizeof(int)*4。

a[0]是指向0号分数组中0号元素的指针常量,它的基类型大小是sizeof(int)

需要注意的是,a[0[0]不是一个数组名,它就是一个数组元素,也就是说,a[0][0]就是1

2. 简单公式替换:解引用运算符[ ]相当于*( + )
例如:
a[0] ~ *(a+0) ~ *a
a[0][0] ~ *(*(a+0)+0)

3.其他理解方式

行指针a纵向移动i到达到a+i,然后解引用得到*(a+i),即a[i]——列指针,然后列指针a[i]横向移动j步到达(a[i]+j)),最后解引用得到*(a[i]+j),即a[i][j];

对应的指针运算

利用该条规则,我们也能够很好的解释指针运算,例如:
a+1 ~ a[1]

a[0]+1 ~ a[0][1]

那么&a+1是什么呢?

答案是:它是指向整个数组a后面那个位置,基类型大小为整个数组大小的指针
可以这么理解:*运算符是解引用,它往里解一层,而&运算符是往外跳一层。
据此:
&a[0] ~ a
&a[0][0] ~ a[0]
上面提到过,a是指向0号分数组的指针常量,往外跳一层就是指向整个数组的指针,我们可以认为有一个实际上不存在的指向整个数组a,基类型为整个数组a大小的指针,而&(往外跳一层)a就是它。

最后我们用代码来验证上述内容:

	int a[3][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};
	int i,j;
	printf("sizeof(int)=%zu\n",sizeof(int));
	printf("a:%p  sizeof(*a)= %d\n",a,sizeof(*a));
	printf("a[0]:%p  sizeof(*a[0])= %d\n",a,sizeof(*a[0]));
	printf("a[0][0]:%d\n",a[0][0]);
	printf("a[0]:%p ~ *(a+0):%p ~ *a:%p\n",a[0],*(a+0),*a);
	printf("a[0][0]: %d ~ *(*(a+0)+0): %d\n",a[0][0],*(*(a+0)+0));
	printf("a+1: %p ~ a[1]: %p\n",a+1,a[1]);
	printf("a[0]+1: %d ~ a[0][1]: %d\n",a[0]+1,a[0][1]);
	printf("&a+1: %p\n",&a+1);
	printf("&a[0]: %p ~ a: %p\n",&a[0],a);
	printf("&a[0][0]: %p ~ a[0]: %p\n",&a[0][0],a[0]);

运行结果:

sizeof(int)=4
a:000000000062FDF0  sizeof(*a)= 16
a[0]000000000062FDF0  sizeof(*a[0])= 4
a[0][0]1
a[0]:000000000062FDF0 ~ *(a+0):000000000062FDF0 ~ *a:000000000062FDF0
a[0][0]: 1 ~ *(*(a+0)+0): 1
a+1: 000000000062FE00 ~ a[1]: 000000000062FE00
a[0]+1: 6487540 ~ a[0][1]: 2
&a+1: 000000000062FE20
&a[0]: 000000000062FDF0 ~ a: 000000000062FDF0
&a[0][0]: 000000000062FDF0 ~ a[0]: 000000000062FDF0

应用

在这里插入图片描述

后记

参考文章:二维数组的指针
参考书籍:《C语言程序设计(第二版)》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值