当前位置: 首页 > news >正文

二维数组与语法糖

距离上一篇稿子大约又有一周多的时间了。在这一周多的时间里,我还是蛮感动的,因为有好多人还一直惦记着这个专栏~有一位头像贼眼熟的小姐姐还特意在我的CSDN博客下留言;前几天厂长还在粉丝群里@我,在催更的同时还问我可不可以再开一个C++专栏,我看到的时候已经很晚了,所以就没有在群里回复~

我力争把自己懂得,也给大家讲明白,当我看到越来越多的人鼓励我,就越发坚定地把C语言更完。不喜欢这个专栏也没关系,可以留言 DISS 我嘛~毕竟……我都觉得上面的话有点太自恋了[手动笑哭]……

言归正传,今天我们的主角还是指针,但是这回可能会有点甜哦,因为今天将给大家介绍C语言指针中的语法糖。

1
二维数组

我们知道 C 语言没有真正意义上的二维数组。二维数组的实现,只是简单地通过“线性扩展”的方式进行。如图所示,int b[4][5]; 就是定义 4 个元素,每个元素都是一个包含 5 个整型变量的一维数组。它在内存中依然是以线性的形式存储。

640?wx_fmt=png

2
关于数组的三个问题

假设我们定义了二维数组array[4][5],为了方便理解,使用如下的形式进行表述

640?wx_fmt=png

  • array 表示的是什么?

显然同一维数组一样, array 是整个二维数组的首地址;在一维数组中,数组名是数组中第一个元素的地址,但是在二维数组中,数组名是第一行元素的地址。其实这个也很好理解,可以将整个二维数组当作是一个一维数组,那么一维数组中的每一个元素就是 array 中的一行。下面将通过代码的形式进行验证

640?wx_fmt=png

我们初始化了一个全为 0 的数组,首先打印出了整型在内存中的大小,之后打印出 array 的地址,和 array 的下一个位置的地址。如果 array 指向的是数组中的第一行,那么 array 将指向数组中的第二行,array 与 array 之间差就是 5*sizeof(int),也就是指针 array 的步长为 5 。执行上述代码可以得到如下的结果

640?wx_fmt=png

整型在内存中的大小为 4 ,而 array + 1 与 array 的差正好是 20(0x16)。所以很明显,array 确实是数组中第一行元素的指针。

  •  *(array+1)表示的是什么?

*(array+1) 称为 (array+1) 的解引用,也就是之前所讲的取值。我们可以从两个角度对他进行理解。首先从解引用的角度,从上面的分析可以知道,array 是数组中第一行元素的指针,也就是说 array 的地址是数组的首地址,步长是数组中每一行元素的总长度。因此 array + 1 所表示的数组的第二行的指针,对它进行解引用,实际上就是对 array +1所在的地址取值,很显然就是数组中第二行的第一个元素。

但是一个更好的角度是从语法糖的角度进行考虑。语法糖(Syntactic sugar)是由 Peter J. Landin(和图灵一样的天才人物,是他最先发现了 Lambda 演算,由此而创立了函数式编程)创造的一个词语,它意指那些没有给计算机语言添加新功能,而只是对人类来说更“甜蜜”的语法。语法糖往往给程序员提供了更实用的编码方式,有益于更好的编码风格,更易读。不过其并没有给语言添加什么新东西。

在 C 语言里用 a[n] 表示 *(a+n),用 a[n][m] 表示 *(*(a+n)+m),这就是语法糖的应用,因为在内部,编译器会自动将 a[n] 转换为 *(a+n) 的形式实现。同样我们之前学习过的 for 循环也是 while 循环的一种语法糖。

因此 *(array+1) == array[1] ,而 array[1] 又可以看作是二维数组中第二行元素所组成的子数组的名字,也就是数组中第二行第一个元素的地址。我们可以通过实验的方式的进行验证

640?wx_fmt=png

在上面的代码中,首先初始化了一个数组,数组中的元素是各不相同的,之后打印输出 *(array+1) 以及对应的语法糖 array[1],然后打印出数组中 array[1][0] 的地址,最后打印出对 array+1 的双重解引用,如果 *(array+1) 是 array[1](即数组中第二行中第一个元素的地址),那么 **(array+1) 将表示第二行第一元素的值。执行代码的到如下的结果

640?wx_fmt=png


  •  * (*(array+1)+3)表示什么?

根据刚刚所讲的语法糖,*(array+1)+3 可以表示为下面的形式

640?wx_fmt=png

由于 *(array+1) 是第二行第一个元素的地址,所以 *(array+1)+3 是第二行第四个元素的地址,那么很明显 * ( *(array+1)+3) 表示第二行第四个元素的值。

这样我们就得到了一个结论,在 C 语言的数组中,下标索引的形式都可以转化为使用指针间接索引的形式,并且他们之间是完全等价的,如下图所示

640?wx_fmt=png

3
数组指针和二维数组

在二维数组的初始化中讲到数组可以使用如下的方式进行定义

640?wx_fmt=png

我们也知道定义一个数组指针是这样的

640?wx_fmt=png

那么问题来了,请问如何解释下边语句

640?wx_fmt=png

很明显,根据刚刚所讲的内容,array 是数组第一行元素的指针,所以 p 是指向一个有两个元素数组的指针,数组中的每个元素是 array 数组中的一行。

我们可以通过下面的代码进行验证

640?wx_fmt=png

如果 p 是指向一个有两个元素数组的指针(数组中的每个元素是 array 数组中的一行),那么 **(p+1) 将表示数组中第二行第一个元素的值,根据语法糖可知 **(array+1) 表示的也是数组中第二行第一个元素的值。执行上面的代码可以获得如下的实验结果

640?wx_fmt=png

很明显刚刚的解释是正确的。

今天的内容就到这里啦~下期再见~~~

4
参考

[1]  “小甲鱼” 视频课程《带你学C带你飞》【第一季】P24

——//——

让知识成为信仰  让优秀成为习惯

往期精彩回顾
带你学C带你飞
互联网不再吃香?
公众号征稿,50-150元/篇

640?点击 阅读原文,关注我的CSDN

相关文章:

  • 几个很重要的建议
  • 苹果与高通大战,iPhone XS要成绝版?
  • 非985/211院校毕业的程序员怎么了?
  • 今天,我23岁了
  • 网易云音乐为什么这么懂你?
  • 你想去阿里吗?
  • Word 的一些神操作,你都会了吗?
  • 小米为什么要“抛弃”红米?
  • 乐视彻底凉凉了吗?
  • 我就是这样拿到阿里巴巴offer的
  • 多闪:我真没有和微信杠,我只是想“颠覆”微信
  • 出身和运气都好就牛逼了吗?
  • 罗振宇拒发年终奖还发长文,借口十分有趣!
  • 百度又“死”了?
  • 高晓松清华谈5G,这些行业将要被颠覆
  • android 一些 utils
  • iOS小技巧之UIImagePickerController实现头像选择
  • storm drpc实例
  • TCP拥塞控制
  • vue从入门到进阶:计算属性computed与侦听器watch(三)
  • 从@property说起(二)当我们写下@property (nonatomic, weak) id obj时,我们究竟写了什么...
  • 如何将自己的网站分享到QQ空间,微信,微博等等
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 赢得Docker挑战最佳实践
  • 由插件封装引出的一丢丢思考
  • JavaScript 新语法详解:Class 的私有属性与私有方法 ...
  • PostgreSQL 快速给指定表每个字段创建索引 - 1
  • Spring Batch JSON 支持
  • ​直流电和交流电有什么区别为什么这个时候又要变成直流电呢?交流转换到直流(整流器)直流变交流(逆变器)​
  • #NOIP 2014# day.1 T3 飞扬的小鸟 bird
  • $.ajax,axios,fetch三种ajax请求的区别
  • (01)ORB-SLAM2源码无死角解析-(66) BA优化(g2o)→闭环线程:Optimizer::GlobalBundleAdjustemnt→全局优化
  • (27)4.8 习题课
  • (PWM呼吸灯)合泰开发板HT66F2390-----点灯大师
  • (第一天)包装对象、作用域、创建对象
  • (十三)Flask之特殊装饰器详解
  • (十三)Java springcloud B2B2C o2o多用户商城 springcloud架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)...
  • (四)linux文件内容查看
  • *++p:p先自+,然后*p,最终为3 ++*p:先*p,即arr[0]=1,然后再++,最终为2 *p++:值为arr[0],即1,该语句执行完毕后,p指向arr[1]
  • .Net CF下精确的计时器
  • .NET Core 控制台程序读 appsettings.json 、注依赖、配日志、设 IOptions
  • .NET Core、DNX、DNU、DNVM、MVC6学习资料
  • .NET Micro Framework 4.2 beta 源码探析
  • .net web项目 调用webService
  • .NET的微型Web框架 Nancy
  • .net中的Queue和Stack
  • .Net转Java自学之路—基础巩固篇十三(集合)
  • :=
  • @Bean注解详解
  • @EventListener注解使用说明
  • @Service注解让spring找到你的Service bean
  • [ NOI 2001 ] 食物链
  • [ vulhub漏洞复现篇 ] ThinkPHP 5.0.23-Rce
  • [ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例
  • []sim300 GPRS数据收发程序