【C语言】多维数组与指针探索——n维数组向n-1维数组指针退化

前言

C语言的多维数组和指针的语法十分复杂,一直以来为人诟病,是C语言使用者的噩梦。通常情况下我们会采取一些方式规避多维数组。但是“明知山有虎,偏向虎山行”,我将会深入探究多维数组和指针的关系。
(这块内容我看了很多资料,但是我认为相当一部分讲的都有问题,这篇文章主要谈我的理解,用词可能不规范,如果有问题,希望指正。)

多维数组数据类型

为了不失普遍性,我们以三维数组

int A[2][3][4];

为例探究一下各种转换的数据类型。

数组名类型和隐式转换

首先要明确的一点是:

数组不是指针,但是数组能转换成指针,或者说退化成指针

A的数据类型是int[2][3][4],是“顶天立地”的数组类型,并非指针。
然而,匪夷所思的是
A+1的数据类型是int(*)[3][4],退化成了指针。对此我的理解是:数组为了能与1进行+运算,发生了隐式类型转换,即A和1都“偷偷地”变成了指针(C语言特色)。而对于数组向指针的隐式转换就是降一维的指针。这也解释了
A[0]的数据类型是int[3][4],因为A[0]等价于*(A+0)。

数组名取*和&的数据类型

数组名是个很奇怪的存在,既能取*也能取&。
*A的数据类型是int[3][4],也就是说*A完全等价于*(A+0),即A[0]。
&A的数据类型是int(*)[2][3][4],就是指向数组的指针。
烧脑的来了:
&*A的数据类型是int(*)[3][4]
*&A的数据类型是int[2][3][4],完全等价于A。
&和*互为逆运算,放在一起作用应该抵消,应该像*&A一样等价于A,那么&*A为什么不是A?就像之前所讲对数组名取*隐含了隐式类型转换,即&*(int(*)[3][4])A。
也就是说:

A的类型本身是int[2][3][4],但同时也匹配int(*)[3][4](当要对A解引用时)。

总结

表达式数据类型
Aint[2][3][4]
A+0int(*)[3][4]
A[0]int[3][4]
*Aint[3][4]
&Aint(*)[2][3][4]
&*Aint(*)[3][4]
*&Aint[2][3][4]

多维数组与函数

多维数组做函数参数

void test(int a[n][3][4]);
void test(int a[][3][4]);
void test(int (*a)[3][4]);

这3个都能匹配int[n][3][4]和int(*)[3][4],其中n是任意正整数。这也再次证明了当对数组名解引用时会变成低一维的指针,因此最高维的长度也变得不重要了。

返回多维数组指针

需要明确一点:

数组不能作函数返回值,只能返回数组指针

int (*test(void))[3][4];

这个函数的返回值匹配int (*)[3][4],表面上返回的是一个二维数组指针,但我们之前分析过三维数组名和二维数组指针的关系。

int (*a)[3][4] = test();
int tem = a[0][0][0];

我们可以看到二维数组指针也可以进行三次取下标操作,这个取下标的过程对于多重指针来说是不断“摘星”,对数组就是不停地由n维数组向(n-1)维数组隐式降维。

结论

综上,我们可以得出结论:

n维数组能够退化成n-1维数组指针

让我们回忆最开始学数组时,一维数组似乎是可以和指针混淆使用的。其实一维数组只是多维数组的一个特例,其中的道理是一维数组退化成零维数组指针,而零维数组指针不存在,只能是指针了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苏打豆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值