(C)*p++和*++p区别
接下来,通过示例彻底理解自增运算符的两种用法(自减的用法与之类似,只不过是加1变成了减1)。
1、++i和i++的区别
如清单1(注意代码中的注释):
- #include <stdio.h>
- int main(void)
- {
- int a, b, i = 7;
- i++; //等价于i = i + 1;
- ++i; //等价于i = i + 1;
- a = i++; //等价于a = i; i = i + 1;
- b = ++i; //等价于i = i + 1; b = i;
- printf("a = %d, b = %d\n", a, b);
- return 0;
- }
<span style="font-family:SimHei;font-size:18px;">#include <stdio.h> int main(void)
{
int a, b, i = 7; i++; //等价于i = i + 1;
++i; //等价于i = i + 1; a = i++; //等价于a = i; i = i + 1;
b = ++i; //等价于i = i + 1; b = i; printf("a = %d, b = %d\n", a, b); return 0;
}
</span>
例子输出结果:
- a = 9, b = 11
<span style="font-family:SimHei;font-size:18px;">a = 9, b = 11
</span>
在例子中,第7和第8行的作用一样,仅仅是为变量i加1,这时i的值已经增加为9,接下来第10行变量a先获得i的值(即9),然后i加1,第11行变量i先再加1,然后把得到的值赋给b,所以b的值为11。
稍微复杂的例子,如清单2:
- #include <stdio.h>
- int main(void)
- {
- int a = 5;
- int *p = &a;
- int b = (*p)++; //等价于b = a++; 即b = a; a = a + 1;
- int c = ++(*p); //等价于c = ++a; 即a = a + 1; c = a;
- printf("b = %d, c = %d\n", b, c);
- printf("(*p)++ = %d, ++(*p) = %d\n", (*p)++, ++(*p));
- return 0;
- }
<span style="font-family:SimHei;font-size:18px;">#include <stdio.h> int main(void)
{
int a = 5; int *p = &a; int b = (*p)++; //等价于b = a++; 即b = a; a = a + 1; int c = ++(*p); //等价于c = ++a; 即a = a + 1; c = a; printf("b = %d, c = %d\n", b, c); printf("(*p)++ = %d, ++(*p) = %d\n", (*p)++, ++(*p)); return 0;
}
</span>
例子输出结果:
- b = 5, c = 7
- (*p)++ = 8, ++(*p) = 8
<span style="font-family:SimHei;font-size:18px;">b = 5, c = 7
(*p)++ = 8, ++(*p) = 8
</span>
在这个例子中,只不过是通过*p来间接地操作a,其他关于自增运算符的用法与清单1类似。第9行的*p一定要用小括号括起来,否则含义就不一样了。而第11行的++(*p)也可以写成++*p(用GCC验证过),那是因为对操作数p来说它只有一个运算符*在计算它,所以无关乎运算符优先级和结合性的问题。
值得注意的是,由于C语言没有指定函数各参数的求值顺序,所以第15行的代码是不可移植的,用不同的编译器可能会产生不同的结果(对于这个例子,GCC是先计算++(*p),后计算(*p)++,所以两者都等于8)。
知识点:
(1)、副作用
在对表达式求值的同时,修改了某些变量的值,其中修改值的行为在C语言中被叫作副作用,那是因为对C语言而言,计算的目的就是对表达式求值,如语句int a = 5,它的含义是先求值得到5,然后把5赋值给变量a,后一步的赋值就是此表达式的副作用。自增和自减运算符就是因为副作用而被使用,除了加1或减1之外,还给自身赋值。
(2)、运算符的优先级
在C语言中,把运算符的优先级分为15级,如下表,从上到下,依次为从最高优先级到最低优先级(为了方便记忆,将15级分成11类,并对每类进行了命名)。
|
初等运算符 |
包括小括号 ()、中括号 [] 、成员访问运算符 . 和 -> 。 |
|
一元运算符 |
包括自增++和自减--、正负号+ 和-、间接运算*和取址运算& 、类型转换(type)、 sizeof 、逻辑反! 、位取反~等。 |
|
算术运算符 |
包括两级,先乘除(*、/、%)后加减(+、-)。 |
|
位移运算符 |
包括左移 << 和右移 >> 。 |
|
关系运算符 |
包括小于 < 、小于等于 <= 、大于 > 、大于等于 >= 。 |
|
判等运算符 |
包括相等 == 和不相等 != 。 |
|
位逻辑运算符 |
分三级,依次为位与 &、位异或 ^ 和位或 | 。 |
|
逻辑运算符 |
分两级,依次为逻辑与 && 和逻辑或 || 。 |
|
条件运算符 |
? : |
|
赋值运算符 |
包括= 、+= 、-=、 *=、 /=、 %= 、&= 、^=、 |= 、<<= 、>>= 。 |
|
逗号运算符 |
, |
(3)、结合性
对于同一操作数,在具有两个相同优先级的操作符时决定先执行哪个操作符的问题就是由结合性决定的。
相同优先级的操作符具有同样的结合性。右结合性就是说表达式中最右边的操作最先执行,然后从右到左依次执行。在C语言中,具有右结合性的操作符只有相应的三类,分别为一元运算符、条件运算符和赋值运算符。
注意:C语言中的优先级和结合性都是针对同一操作数而言的。如表达式24/8*2,对于操作数8而言,/ 和*的优先级相同,所以再根据它们的左结合性可知,表达式是先计算24/8得到3,然后计算3*2得到6。
C语言并没有规定同一运算符相关的多个操作数的计算顺序(&&、|| 、? : 和 , 运算符除外),如式子a = 8 * 9 + 20 * 4,对操作数9和20而言,根据优先级就可判断先乘后加,但表达式中的两个*并不共享同一操作数,所以从左到右的结合性并不适用它,8 * 9 和20 * 4的计算顺序是不定的,到底先计算8 * 9还是20 * 4由编译器决定。
在上面例子中,8 * 9和20 * 4谁先执行都不影响最后结果的一致,但有些情况下就未必了,如“ b = 3; a = (b++) * (b++); ”这样的例子,对于不同的编译器最后a的值可能等于9,也可能等于12,甚至可能等于16。因此,在实际应用中不能出现这样的未确定性,根据自己的需要,可以把它改成类似“b = 3; c = b++; a = c * c;”这样的形式。
2、*p++和*++p的区别
举例,如清单3:
- #include <stdio.h>
- int main(void)
- {
- int arr[] = {1, 2, 3, 4};
- int *p = arr;
- int a = *p++; //等价于a = *(p++); 即a = *p; p = p + 1;
- int b = *++p; //等价于b = *(++p); 即p = p + 1; b = *p;
- printf("a = %d, b = %d\n", a, b);
- return 0;
- }
<span style="font-family:SimHei;font-size:18px;">#include <stdio.h> int main(void)
{
int arr[] = {1, 2, 3, 4};
int *p = arr; int a = *p++; //等价于a = *(p++); 即a = *p; p = p + 1; int b = *++p; //等价于b = *(++p); 即p = p + 1; b = *p; printf("a = %d, b = %d\n", a, b); return 0;
}
</span>
例子输出结果:
- a = 1, b = 3
<span style="font-family:SimHei;font-size:18px;">a = 1, b = 3
</span>
对于第8行的操作数p而言,*和++的优先级相同,但根据它们的右结合性可知,在这个表达式里可认为++的优先级高于*,即*p++等价于*(p++)。
而对于第10行的操作数p而言,它只有一个运算符++,所以先计算++p得出结果,然后间接运算。
(C)*p++和*++p区别的更多相关文章
- c#与java的区别
经常有人问这种问题,用了些时间java之后,发现这俩玩意除了一小部分壳子长的还有能稍微凑合上,基本上没什么相似之处,可以说也就是马甲层面上的相似吧,还是比较短的马甲... 一般C#多用于业务系统的开发 ...
- jquery和Js的区别和基础操作
jqery的语法和js的语法一样,算是把js升级了一下,这两种语法可以一起使用,只不过是用jqery更加方便 一个页面想要使用jqery的话,先要引入一下jqery包,jqery包从网上下一个就可以, ...
- 【原】nodejs全局安装和本地安装的区别
来微信支付有2年多了,从2年前的互联网模式转变为O2O模式,主要的场景是跟线下的商户去打交道,不像以往的互联网模式,有产品经理提需求,我们帮忙去解决问题. 转型后是这样的,团队成员更多需要去寻找业务的 ...
- 探究@property申明对象属性时copy与strong的区别
一.问题来源 一直没有搞清楚NSString.NSArray.NSDictionary--属性描述关键字copy和strong的区别,看别人的项目中属性定义有的用copy,有的用strong.自己在开 ...
- X86和X86_64和X64有什么区别?
x86是指intel的开发的一种32位指令集,从386开始时代开始的,一直沿用至今,是一种cisc指令集,所有intel早期的cpu,amd早期的cpu都支持这种指令集,ntel官方文档里面称为&qu ...
- Java中Comparable与Comparator的区别
相同 Comparable和Comparator都是用来实现对象的比较.排序 要想对象比较.排序,都需要实现Comparable或Comparator接口 Comparable和Comparator都 ...
- MySQL中interactive_timeout和wait_timeout的区别
在用mysql客户端对数据库进行操作时,打开终端窗口,如果一段时间没有操作,再次操作时,常常会报如下错误: ERROR (HY000): Lost connection to MySQL server ...
- 设置line-height:1.5和line-height:150%或者line-height:150px的区别
直接正题: 看一下line-height可能的值: 其实可以分为两类: (1)不带单位的(如line-height:1.5),这种是推荐使用的: (2)带单位的(如line-heigth:30px/1 ...
- C#中Length和Count的区别(个人观点)
这篇文章将会很短...短到比你的JJ还短,当然开玩笑了.网上有说过Length和count的区别,都是很含糊的,我没有发现有 文章说得比较透彻的,所以,虽然这篇文章很短,我还是希望能留在首页,听听大家 ...
- select、poll、epoll之间的区别总结
select.poll.epoll之间的区别总结 05/05. 2014 select,poll,epoll都是IO多路复用的机制.I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪 ...
随机推荐
- kubernetes---CentOS7安装kubernetes1.11.2图文完整版
转载请注明出处:kubernetes-CentOS7安装kubernetes1.11.2图文完整版 架构规划 k8s至少需要一个master和一个node才能组成一个可用集群. 本章我们搭建一个mas ...
- SLF4J 简单日志门面 介绍和使用
参考:http://singleant.iteye.com/blog/934593 http://liuzidong.iteye.com/blog/776072 介绍: 简单日记门面(s ...
- 小Z的袜子(bzoj 2038)
Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……具体来说,小Z把这N只袜 ...
- 计算系数(codevs 1137)
题目描述 Description 给定一个多项式(ax + by)^k,请求出多项式展开后x^n y^m项的系数. 输入描述 Input Description 共一行,包含 5 个整数,分别为a,b ...
- jQuery事件委托之Safari失效的解决办法--摘抄
什么是事件委托 事件委托是Jquery中一种事件绑定的方式,不同于常见的事件绑定方式将事件绑定在目标元素上,而是将事件绑定在父级元素上通过事件冒泡来执行绑定函数. //常见的事件绑定(Jquery) ...
- js-判断当前页面是否在微信浏览器中打开
方案一:推荐 var ua = navigator.userAgent.toLowerCase(); var isWinxin = ua.indexOf('micromessenger') != -1 ...
- 三种Model模式
目前项目中可能出现的三种Model模式,对于我们现在开发的一个项目,我觉得使用DDD的思想来设计模型比较清晰,使用DDD的思想把模型model分成了如下三种:ViewModel,它与页面相关,Doma ...
- Java中Arrays类与Math类
Arrays(数组工具类) Java中已经封装好的类,提供大量静态方法供用户对数组的使用. 导包:import java.util.Arrays 1.Arrays.toString(数组) //返回值 ...
- 使用Swagger生成Spring Boot REST客户端(支持Feign)(待实践)
如果项目上使用了Swagger做RESTful的文档,那么也可以通过Swagger提供的代码生成器生成客户端代码,同时支持Feign客户端. 但是经过测试,生成Feign代码和REST客户端有些臃肿. ...
- BS版代码生成器 简介
自用的代码生成器 核心:JdbcTemplate+freemarker 目前支持sqlserver和mysql 演示: 1.首界面 2.读数据库中的所有表 3.打开某数据库下的所有表.视图.存储过程 ...