`
michael-java
  • 浏览: 18190 次
  • 性别: Icon_minigender_1
  • 来自: 合肥
最近访客 更多访客>>
社区版块
存档分类
最新评论

第四章 [ ]运算符的本质

阅读更多

 

数组是存在于人们头脑中的一个逻辑概念,而编译器其实并不知道有数组这个东西,它所知道的,只是[]运算符,当遇到[]运算符的时候,编译器只是简单地把它转换为类似*(*(a+i)+j)这样的等价表达式,之所以是这种表达式,如前几章所述,是因为C语言的数组实现本质上是数组的嵌套。

        由于这种等价关系的存在,会产生一些古零精怪的表达式,例如:

10[a]

这个表达式初看上去让人摸不着头脑,它是什么呢?如上所述,编译器会把它转换为*(10+a),把a和10调换一下,就是*(a+10)了,这个就是a[10]。

[]运算符之前还可以是一个表达式,例如:(10+20)[a]。

严格来讲,以上两个表达式是非法的,因为C89对于数组的引用(注意不是数组定义)规定:带下标的数组引用后缀表达式由一个后缀表达式后跟一个括在方括号中的表达式组成。方括号前的后缀表达式的类型必须为“指向T类型的指针”,其中T为某种类型;方括号中表达式的类型必须为整型。这个规定说明,进行数组引用的时候,[]运算符的左边并非必须为数组名,而可以是一个表达式,但这个表达式的类型必须为“指向某类型的指针”。显然10跟(10+20)连地址都不是,因此实际上他们是非法的,编译器在这里并没有严格遵守标准的规定。但如果是:

int a[10], *p = a;

(p+1)[2]这样就是合法的,因为p+1的结果仍然是一个指针。

要注意的是,虽然后缀表达式是一个“指向某类型的指针”,但不要被这里所说的指针一词搞混了,上面的规定不能反过来使用。还是以上面的例子为例,我们可以p[i]这样使用p,这是符合上述规定的,但并不能因为指针p能够以p[i]这种形式使用就认为p是一个数组,这就错误了,不能反过来应用上述规则。

        最后说一下编译器对&*的优化,对于数组int a[10],如果对其中一个元素取地址,例如&a[1],这条表达式等价于&*(a+1),编译器并不会先计算*再运算&,而是对&*两个运算符进行优化,把它们同时去掉,因为两者的作用是相反的,最后得到计算的是a+1表达式。

分享到:
评论

相关推荐

    简明 Python 教程 中文版

    第4章 基本概念 第5章 运算符与表达式 第6章 控制流 第7章 函数 第8章 模块 第9章 数据结构 第10章 解决问题——编写一个Python脚本 第11章 面向对象的编程 第12章 输入/输出 第13章 异常 第14章 Python标准库 第15...

    C#本质论(第3版)

    第4章 方法和参数 4.1 方法的调用 4.1.1 命名空间 4.1.2 类型名称 4.1.3 作用域 4.1.4 方法名称 4.1.5 参数 4.1.6 方法返回值 4.1.7 语句与方法调用的比较 4.2 方法的声明 4.2.1 参数声明 4.2.2 方法...

    Visual.Basic.2008编程参考手册.pdf

    第4章 Windows Form Designer 第5章 WPF设计器 第6章 Visual Basic代码编辑器 第7章 调试 第Ⅱ部分 开始学习 第8章 选择Windows窗体控件 第9章 使用Windows窗体控件 第10章 Windows窗体 第11章 选择WPF控件 第12章 ...

    Linux C程序设计大全

    第4章 C语言中的指针与字符串 4.1 sizeof运算符 4.1.1 sizeof运算符的应用——得到内置类型的大小 4.1.2 sizeof运算符的应用——得到复合类型的大小 4.2 指针的应用 4.2.1 指针与别名陷阱 4.2.2 数组的指针 4.2.3 ...

    《程序设计大学教程试读》PDF版

    543.4.3 循环结构 603.5 本章小结 663.6 本章习题 67第4章 过程与函数 714.1 过程与函数的编写 714.1.1 过程 714.1.2 函数 724.1.3 指示字* 734.1.4 程序型类型* 754.2 参数 784.2.1 参数类型 794.2.2 无类型参数* ...

    编写可维护的javascript(英文)

    第4章 变量、函数和运算符 4.1 变量声明 4.2 函数声明 4.3 函数调用间隔 4.4 立即调用的函数 4.5 严格模式 4.6 相等 4.6.1 eval() 4.6.2 原始包装类型 第二部分 编程实践 第5章 UI层的松耦合 5.1 什么是...

    编写可维护的JavaScript(中文)

    第4章 变量、函数和运算符 4.1 变量声明 4.2 函数声明 4.3 函数调用间隔 4.4 立即调用的函数 4.5 严格模式 4.6 相等 4.6.1 eval() 4.6.2 原始包装类型 第二部分 编程实践 第5章 UI层的松耦合 5.1 什么是...

    面向对象技术与UML课件及源代码-by 南邮-陈杨

    第4章实验指导1 第5章类、对象和成员 第6章封装 第7章继承和多态 第8章实验指导2 第9章异常处理 第10章Java常用API 第11章Java IO操作 第12章多线程开发 第13章反射技术 第14章实验指导3 下篇UML ...

    ADO.NET本质论.pdf

    第4章 dataset类:关系数据的集合 4.1 dataset 4.1.1 dataset作为驻留内存的数据库 4.1.2 dataset的用途 4.2 dataset对象模型 4.2.1 datacolumn,datarow和data table 4.2.2 data table及其用法 ...

    JAVA基础课程讲义

    第四章 异常机制 95 导引问题 95 异常(Exception)的概念 96 异常分类 96 Error 97 Error和Exception的区别 97 Exception 97 异常的处理办法之一,捕获异常 99 try块 99 catch 99 finally 100 try, catch,finally ,...

    Android 3D游戏开发技术宝典-OpenGL ES 2.0 (吴亚峰) 源代码

    第4章 着色语言shading language 105 4.1 着色语言概述 105 4.2 着色语言基础 106 4.2.1 数据类型概述 106 4.2.2 数据类型的基本使用 110 4.2.3 运算符 112 4.2.4 类型转换 114 4.2.5 限定符...

    Visual C++ 2010入门经典(第5版)--源代码及课后练习答案

    第4章 数组、字符串和指针 139 4.1 处理多个相同类型的数据值 139 4.1.1 数组 140 4.1.2 声明数组 140 4.1.3 初始化数组 143 4.1.4 字符数组和字符串处理 144 4.1.5 多维数组 147 4.2 间接数据访问 150 ...

    Java开发技术大全 电子版

    第4章继承与多态145 4.1继承的基本原理145 4.2子类对父类的继承146 4.3属性隐藏和方法的覆盖148 4.3.1属性的隐藏148 4.3.2方法的覆盖151 4.4构造方法的继承154 4.5super的使用156 4.5.1用super引用父类的...

    Visual Basic 6编程技术大全 中译本扫描版带书签 2/2

    第4章变量与过程100 4.1变量的作用域和生存期100 4.1.1全局变量100 4.1.2模块级的变量101 4.1.3动态局部变量102 4.1.4静态局部变量102 4.2内置数据类型概述103 4.2.1整型数据类型103 4.2.2长整型数据类型104 4.2.3...

    Visual Basic 6编程技术大全 中译本扫描版带书签 1/2

    第4章变量与过程100 4.1变量的作用域和生存期100 4.1.1全局变量100 4.1.2模块级的变量101 4.1.3动态局部变量102 4.1.4静态局部变量102 4.2内置数据类型概述103 4.2.1整型数据类型103 4.2.2长整型数据类型104 4.2.3...

Global site tag (gtag.js) - Google Analytics