多维数组用星号“*”索引的探索与通俗理解

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;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值