0 前言
最近为了备考二级C语言,开始了考前抱佛脚,学到二维数组索引的时候,自己一头雾水,为什么*(p+1)明明带着取值运算符,但竟然还是个地址?经过一番思索,自认为有点开窍,于是写下了人生中第一篇博客:对多维数组用星号“*”索引的通俗理解!第一次练手,如果有误,还请各路高人指点迷津!
1 一维数组
我们先从一维数组说起:
~~~对于一维数组p[]
p是指第0个元素的地址,所以*p自然就是第0个元素的值;
p+1是指第1个元素的地址,所以*(p+1)即为第1个元素的值;
...
依此类推,*(p+i)对于一维数组来说,就是第i个元素的值;
嗯,目前为止很正常,一次取值,就是值。
2 二维数组
~~而对于二维数组p[][n]
p是指第0行元素p[0]的地址(注意是第0行!!!),此时*p的意义已经发生了变化:不再是第0个元素的值。此时如果输出*p,你会惊奇地发现,这竟然还是个地址!说好的星号是取值运算符呢?取出的值呢?而且,如果此时再输出p的值,你会发现,这俩是相等的!那是不是说星号对于多维数组就不起作用了呢?咳咳咳!当然,不是啦!我们先继续往下探索。p+1是指第1行元素p[1]的地址(注意是第1行!!!),所以*(p+1)的值,是不是也和p+1一样呢?经过验证,果然如此!稍加推理,(p+i)怕不是要等于*(p+i)了!
但是,相等只是自己表面上看上去的结果,实际如果写到if语句的条件里面,还是会给出warning的,当然,这仅仅是因为类型不匹配!
二维数组验证加推理已经出现了这些疑惑,而如果上网搜索,网上的索引用的都是两个星号,例如**p;*(*p+1);但是,按照对取值运算符“*”的理解,这根本就是对值取值啊!不行了不行了,太难了,弃坑弃坑!
欸!先别着急,这么点困难就弃坑,也太那啥了吧!其实,我们可以用更加通俗的事情来类比,去理解这件事情!
3 深入分析
数组本身是一个存放值的容器,要想索引里面的值,必须唯一确定。那么问题来了,用数组索引时,直接p[i][j]就可以轻松搞定,但如果想用取值运算符,我们可以利用的只有数组的名称以及阿拉伯数字,所以应该通过平移来确定!想想数学中,我们是如何确定一个点的?一维的点,直接在数轴上用一个值来表示,二维的点就需要两个值,分别是X轴上的值和Y轴上的值;三维的点需要三个值,分别是XYZ三个轴上的值;而n维的点,则开始用向量来表示:{a,b,c,d,e...},这些数字分布在各个轴上,我们先确定要找哪个轴,接下来才确定轴上要找的是哪个值——类比过去,我们先要通过一次取值运算选择一个“轴”,再通过加减运算选择“轴”上的某个值,因为默认的p,其实是p+0;而最开始的p,其实已经选择了所谓的“X轴”,不必重复选,只需要选择值就好;所以**p其实是*(*(p+0)+0);*(*p+1)其实是*(*(p+0)+1);这样写程序虽然不会报错,但看起来还是不够简洁,不够舒服,所以最终应该采用**p和*(*p+1)的惯用写法!(好吧,我承认全篇废话,就这段话是核心……)
所以,我们之前的理解“两个取值运算符就是对值取值”并不正确,而应该是:取值运算符"*",代表维度切换,加法运算才是真正在确定值!有n个维度,就应该需要n-1个“*”去切换维度,即取出上一个维度的某个值所在的那个空间,而最后的那个“*”,才是用来取出唯一确定了的那个位置的元素!这样一来,写法就简单了,对于n维数组,先写n个 "*(" ,然后写p,最后将每个下标写成 “+i)” 的格式,0省略即可!
所以,在多维数组中,p和*p的输出,表面上是一样的,但其实二者所在的维度已经发生了变化,只不过p是指向第0维空间的起始位置,*p指向第0维的第0号元素的位置,二者指向同一个地方,输出的地址当然是一致的!
4 后记
最后,附上C语言测试代码,方便理解,也方便大家在此基础上修改使用:
#include <stdio.h>
int main()
{
/******one-demensional array*****/
int p1[] = {1,2,3,4,5};
printf("p1 : %p\n",p1);
printf("*p1 : %d\n",*p1);
printf("p1+1 : %p\n",p1+1);
printf("*(p1+1):%d\n",*(p1+1));//一维数组一次取值就可以取出地址里面的值
/******two-demensional array*****/
int p2[3][3] = {1,2,3,4,5,6};
printf("p2 : %p\n",p2);
printf("*p2 : %p\n",*p2);
printf("p2+1 : %p\n",p2+1);//二维数组的名称指向的是第一行所有元素p2[0],所以p2+1指的是第二行所有元素p2[1]的地址;
printf("*(p2+1):%p\n",*(p2+1));//二维数组一次取值,还是地址!!不过已经定位到了第二行,是p[1][0]的地址 !!
printf("**(p2+1):%d\n",**(p2+1));//二次取值才是值
printf("*(*(p2+1)+2):%d\n",*(*(p2+1)+2));//二次取值才是值
if((int*)p2 == *p2)
printf("same!");
return 0;
}