你必须知道的495个C语言问题,学习体会三
本文是 本系列的第三篇,本文主要对C语言的表达式做个小结
先从两个坑爹的表达式说起:i++ 与++i
上大学的时候,学长告诉我,这两个表达式,意义是一样的,后来老师纠正说,还是有区别的,于是让我们记住以下观点:i++是先使用i的值,再对i进行+1操作,而后者则刚好相反,先将i+1,再使用i的值。一直都是这么记得,笔试也没错过,也就信了老师了。更合理的解释是:++i在存储的值上增加1 并向使用它的表达式“返回”新的、增加后的值,而i++对i增加1,但返回的是原来的、未增加的i的值。
但是,据本书所解释的: i++ 或者i--在输出其旧值才会执行运算,但这里的“之后”的含义和准确定义常常被误解,无法保证自增或者自减会在放弃变量原值之后和对表达式的其他部分进行计算之前立即进行,只能保证变量的更新会在表达式“完成”之前的某个时刻进行。
回到学长的观点,以下语句的有区别么?
for (int i = 0;i<5;i++)
for (int i = 0;i<5;++i)
从达到的目的上看,确实没有区别。都实现了i的递增加1 ,但是linux之父 linus告诉我们,后者比前者的运行效率更高,因为后者没有产生中间量,在很多次的运行中,这种差异还是有的,于是,我相信了,以后在我所有的循环自加的语句中都使用++i的形式。这在C++中 ,区别就更加明显了,不信可以重构下++ 操作符,如果你也懂C++的话。
现在思考以下表达式:
a[i] = i++;
a[i] = ++i;
这种计算依赖于计算机编译器,在我的x86_64-w64-mingw32-gcc编译下,二者遵循老师的运算逻辑,但是,这样的代码是应该避免的,毕竟,我们并不怕多一个中间变量。
是的,凡是与表达式相关的不清晰的表达,都可以用增加中间变量来解决。
a[i] = i++;=====> j = i;a[i] = j; i++;
a[i] = ++i;=====> j = i+1;a[i] = j;i++;
表达式 自身的 运算以及 运算符的优先级问题 本身不应该成为问题,这样的问题 最好还是留在笔试题目中,我们在实际编码中,更关心代码的清晰度和易读性,因此,不建议乱用高级的表达式来达到 简单化代码的目的,实在要用,可以多用括号表达。
于是,有以下建议可以避免未定义的求值顺序问题:
1.确保一个表达式最多只修改一个对象:一个简单变量、一个数组成员或者一个指针指向的位置,“修改”是指=操作符的简单赋值,+=、-=或者*=操作符的复合赋值或者++ --操作符的前后缀形式
2.如果一个对象在一个表达式 中出现一次以上 而且在表达式中被修改,则要确保该对象的所有读访问都被用于计算它的最终值,这条规则允许表达式i=i+1 ——尽管i出现两次而且也被修改了,但对i的旧值是用于计算i的新值
3.如果想要破坏第一条规则,就要确保修改的对象互不相同。表达式c = *p++是合法的,因为修改的两个对象c和p互不相同,
4.如果在两次修改或者修改和访问之间置入定义的序列点操作符,则可以破坏第一条规则和第二条规则,这个表达式(通常在一个while循环中看到,用来读入一行的内容)是合法的,因为 第二次访问变量c出现在&&引入的序列点之后。
(c = getchar()) != EOF && c != '\n'
其他知识
- && 与|| 的短路规则,
- 左值 与 右值 ,可赋值变量
你必须知道的495个C语言问题,学习体会三的更多相关文章
- 你必须知道的495个C语言问题,学习体会一
C语言作为一门古老的语言,其灵活性和容易出错都让人 又爱又恨,书籍<你必须知道的495个C语言问题>,使用问答的形式,告诉读者 C语言使用的各个方面的知识,包括一些冷知识等.以下,我要摘录 ...
- C语言学习书籍推荐《你必须知道的495个C语言问题》
萨米特 (Steve summit) (作者), 孙云 (译者), 朱群英 (译者) 下载地址:点我 <你必须知道的495个C语言问题>以问答的形式组织内容,讨论了学习或使用C语言的过程中 ...
- 《你必须知道的495个C语言问题》知识笔记及补充
1. extern在函数声明中是什么意思? 它能够用作一种格式上的提示表明函数的定义可能在还有一个源文件里.但在 extern int f(); 和 int f(); 之间并没有实质的差别. 补充:e ...
- 你必须知道的495个C语言问题,学习体会四
本文,我们来学习下指针,这是个梦魇啊.无数次折磨着C语言学习者,无数次的内存泄露,无数次的访问失败,无数次的越界溢出, 这些错误造就的仅仅是一个 跟随者,真正的优秀者必须要正视语言的局限,同时在最大限 ...
- 你必须知道的495个C语言问题,学习体会二
这是本主题的第二篇文章,主要就结构体,枚举.联合体做一些解释 1.结构体 现代C语言编程 结构化的基石,diy时代的最好代言人,是面向对象编程中类的老祖宗. 我们很容易定义一个结构体,比如学生: st ...
- 你必须知道的495个c语言问题(笔记)
1.1我该如何决定使用哪种整数类型? 用到较大的数用long:空间很重要(例如有很大的数组或很多的结构)用short:此外用int. win32: int 32bit 4byte char 8b ...
- 《你必须知道的495个C语言问题》读书笔记之第11-14章:ANSI C标准、库函数、浮点数
一.ANSI C标准 1. ANSI向C语言预处理器引入了几项新的功能,包括“字符串化”操作符(#).“符号粘贴”操作符(##).#pragma指令. 2. Q:char a[3] = "a ...
- 《你必须知道的495个C语言问题》读书笔记之第8-10章:字符串、布尔类型和预处理器
一.字符和字符串 1. Q:为什么strcat(string, '!')不行? A:strcat()用于拼接字符串,所以应该写成strcat(string, "!")." ...
- 《你必须知道的495个C语言问题》读书笔记之第4-7章:指针
1. Q:为什么我不能对void *指针进行算术运算? A:因为编译器不知道所值对象的大小,而指针的算法运算总是基于所指对象的大小的. 2. Q:C语言可以“按引用传参”吗? A:不可以.严格来说,C ...
随机推荐
- linux(6/17)--文件打包上传和下载
tar命令 命令功能 用来压缩和解压文件 命令格式 tar[必要参数][选择参数][文件] tar打包工具 -f ##指定生成包的名字,建议 -f单独写成一个参数 --delete filename ...
- pxe-kickstart批量部署文档
#PXE安装: yum install syslinux xinetd tftp-server httpd -y yum install dhcp -y yum install system-conf ...
- Oracle 事务处理
事务的四大特性 1.原子性(Atomicity) 事务的原子性是指事务中包含的所有操作要么都做,要么都不做,保证数据库是一致的. 2.一致性(Consistency) 一致性是指数据库在事务操作前和事 ...
- JS中函数之外不能写return
JS中return有时会遇到这种情况,具体表现为:google浏览器等浏览器可以继续执行,IE浏览器不能执行return,并且google浏览器:执行时会显示SyntaxError: Illegal ...
- sql server 数据库复制实现数据同步常见问题(不定期更新)
sql server2008数据库复制实现数据同步常见问题 在原作者基础上追加 sql server2008数据库复制实现数据同步常见问题 23.发布 'xx' 的并发快照不可用,因为该快照尚未完全生 ...
- MongoDB快速入门(十二) -- 索引
MongoDB 索引 索引支持的解析度的查询效率.如果没有索引,MongoDB必须扫描每一个文档的集合,要选择那些文档相匹配的查询语句.这种扫描的效率非常低,会要求 mongod 做大数据量的处理. ...
- java中泛型的一个小问题
最近做项目,由于java语法不是非常的熟悉,编写代码过程中不难遇到一些问题: 代码里写了一条这种语句: Map<String, List<String>> configFile ...
- Kubernetes学习整理
修改镜像仓库 官方提供的时google源,显然是无法使用的.这里需要改成国内的源 cat <<EOF > /etc/yum.repos.d/kubernetes.repo [kube ...
- angularjs分页组件
这是我第一次写博客,激动,首先,我也是个菜鸟,分享一下自己写的服务器端分页的代码,自己一步一步写的,其中也有参考别人的代码.技术比较渣,先这样了. // ====== 2019-1-3 ======/ ...
- 配置mybatis-config.xml出现过很诡异的现象
1 首先得保证包的导入正确 2 然后如果把mybatis-config.xml放在src的某个文件夹下,最后能够build path 3 之后一直报 Archive for required libr ...