刚刚开始看一本书。《C陷阱与缺陷》,相信学习C语言的大家都对这本书有耳闻。今天看到了里面的贪心法则。也即在读到一个字符后,尽可能多的读入更多的字符,直到读入的字符组成的字符串已经不可能再组成一个有意义的符号为止。下面举例是  a---b。

然后就想起之前每次遇到这种问题都觉得没什么意思,自己写代码基本从来不这样干,写复杂的语句就加小括号。但是偏偏一些人还就问这些问题。今天就专门来钻研探讨一下这一系列相关的问题。

首先,a++和++a都是对变量a的值作自增运算然后将新的值赋给a。

但是当出现在表达式中时,这两种表述就有一点区别。

a++是将a的值先用在表达式里进行运算,运算完成之后再对a进行自加操作。

++a是先对a进行自加操作,然后用新的a的值在表达式中进行计算。

简单的看一下验证代码和结果如下

 #include<stdio.h>
int main()
{
int a , b;
int c; a = b = ; c = a++;
printf("c = %d\n" , c); c = ++b;
printf("c = %d\n" , c);
return ;
} >>>c = 0
>>>c = 1

那么结合贪心法则。a+++b就应该是(a++)+b。事实证明确实如此。

 #include<stdio.h>
int main()
{
int a , b;
int c; a = b = ;
c = a+++b;
printf("c = %d\n" , c); a = b = ;
c = (a++)+b;
printf("c = %d\n" , c); a = b = ;
c = a+(++b);
printf("c = %d\n" , c); return ;
} >>>c = 0
>>>c = 0
>>>c = 1

那么 a+++++b呢?应该是 ((a++)++)+b。

尝试一下。 代码改成 c = ((a++)++)+b;  报错了。

错误信息是  error: lvalue required as increment operand。也就是说自增运算符需要左值。

那么。什么是左值?左(left)的原意是指可以放在赋值符号“=”的左边,但其实也表示能作为&和++等操作符的操作数。

相对应的还有右值。简单的说,就是放在赋值符号“=”的右边的那个东西。

深入一点说。首先,右值的英文叫R-value,其中的R指的是Read,表示可读。一切常数、字符和字符串都是右值。

左值的英文叫L-value,其中的L指的是Location,表示可寻址。

我们知道,在写程序定义一个变量时,计算机会在内存申请一块区域用于存放这个变量的值。

比如说,你写一条语句 int a = 1;

那么首先,这是一个声明。声明了a是一个int型变量。然后是定义,定义的时候内存会申请空间。

类比现实世界。你需要一个箱子来装东西。那先要根据你要装的东西的大小形状等特点选择一个最合适的箱子。这个就是声明。也就是前面的 int 起的作用。int 保证了a这个变量里面存的值应该有哪些特点。

现实世界,你不会用纸箱去装水,因为会漏。也不会用小盒子去装大电视,因为装不下。写程序也是这样,你已经声明了变量的类型之后,你就应该用这个变量装合适的值。

实际上,真正的声明相当于只给了你一个箱子的模型,但是这个时候这个箱子还没有。它只是告诉了你这个箱子应该有哪些特点(形状,大小等等)。

在定义的时候,它就会根据前面的这个模型真正给你一个真实存在的箱子。而你的语句中的a,就相当于给了这个箱子一个名字。从此,你可以通过这个名字找到这个箱子。就好像能喊你的名字找到你一样。

语句最后这个1,说明你把“1”这个值,装到了这个箱子里。

那么现在。a这个箱子就是左值,它可以用来装东西。a箱子里面的东西(变量a的值)就是一个右值,它可以出现在赋值符号(=)右边。

了解了左值和右值之后,我们再来看自增运算符。

a++。它会先返回a的值进行计算(右值),然后对a(左值)进行自增。

++a。它先自增然后返回变量a(左值)。

注意,自增运算符只能作用于左值。也即变量。不能作用于右值。例如 1++ 这样的是不被允许的。

再看这个问题a+++++b。也就是 ((a++)++)+b。

a++返回了一个右值,右值不能再进行自增操作。所以报错。

那么++a+++b呢?根据贪心法则。应该是((++a)++)+b。也就是先算++a

因为++a返回的是一个左值,可以进行自增运算。所以这个表达式貌似正确。

然而。好吧。又报错了。报错信息依然是。error: lvalue required as increment operand。也就是说自增运算符需要左值。

WTF?   ++a是返回的左值啊?  没毛病啊?

通过用代码验证证明这个表达式的计算顺序是这样的。(++(a++))+b

注意:根据小时候的数学知识,表达式应该从最里面的括号开始运算,这里也就是第一步先算 a++

然后我考虑是不是优先级的问题。找了一波优先级表。发现自增运算,不论a++还是++a优先级都是2。

想了半天加瞎找。发现了一个东西。叫做结合性。同一优先级的运算符,运算方向由结合性决定。

结合性只用于表达式中出现两个以上相同优先级的操作符的情况,用于消除歧义。事实上你会注意到所有优先级相同的操作符,它们的结合性也相同。

我看了一下,优先级为2,13,14,的运算符结合方向是从右到左。也就是先用右边的运算符计算。其余优先级(优先级总共15)的运算符均为从左到右,也就是我们正常数学上的运算方向。

这样,就解释了上面 ++a+++b 问题。因为它会先执行a++,返回一个右值,然后执行自增操作。右值的自增操作报错。

(运算符优先级和结合性的表格网上能找到,这里不给出)

最后,需要声明一个问题。小括号不会改变自增操作中变量自增和变量值应用的顺序。

如 b = (a++);

它依然会先把a的值赋给b然后执行自加,不会因为你加了小括号就先自加再赋值。

C语言左值,运算符的优先级以及结合性探讨的更多相关文章

  1. [转]说说C语言运算符的“优先级”与“结合性”

    补充自己的一点理解: 1.关于++i 与 i++的区别. ++i 和 i++如果是单独使用的语句,即二者后面均加上分号,或者其他单独使用的语句,没有任何区别.例如: for(i=0;i<100; ...

  2. 说说C语言运算符的“优先级”与“结合性”

    论坛和博客上常常看到关于C语言中运算符的迷惑,甚至是错误的解读.这样的迷惑或解读大都发生在表达式中存在着较为复杂的副作用时.但从本质上看,仍然是概念理解上的偏差.本文试图通过对三个典型表达式的分析,集 ...

  3. [c语言]运算符的优先级与结合性

    c语言中运算符的优先级和结合性常常被人混淆一谈,本文目的在于简单谈谈两者的区别.本文举几个简单的例子说明,这些运算符也特别常用. 首先要明白的是:优先级决定表达式中各种不同的运算符起作用的优先次序:而 ...

  4. C语言的运算符的优先级与结合性+ASCII表

    [0]README 0.1) 内容来源于 C程序设计语言, 旨在整理出C语言的运算符的优先级与结合性, 如下图所示(哥子 记了大半年都没有记住,也是醉了,每次都要去翻): Alert)以下内容转自:h ...

  5. swift:高级运算符(位运算符、溢出运算符、优先级和结合性、运算符重载函数)

    swift:高级运算符 http://www.cocoachina.com/ios/20140612/8794.html 除了基本操作符中所讲的运算符,Swift还有许多复杂的高级运算符,包括了C语和 ...

  6. C语言语法之运算符及优先级

    注:该内容整理自以下链接. http://blog.csdn.net/huangblog/article/details/8271791 表:C语言运算符及优先级 优先级 运算符 名称或含义 使用形式 ...

  7. C语言运算符的优先级与结合性

    结合性:左结合是从左到右依次执行,右结合是从右到左依次执行. 优先级 运算符 名称或作用 运算类型 结合方向 特点 1 () [] -> . 小括号运算符 下标运算符 指向结构成员运算符 结构成 ...

  8. C语言 左值、右值

    左值就是在赋值中可以放在赋值操作符两边的值 右值则是只可以放在赋值操作符右边的值 ++i是直接给i变量加1,然后返回i本身,因为i是变量,所以可以被赋值,因此是左值表达式i++现产生一个临时变量,记录 ...

  9. Java基本语法-----java运算符的优先级与结合性

    这是本人以前的上学期间java 运算符这块知识的总结的,截图存到了word里,大家将就看下吧(不会用Markdown的表格 不然就在写一遍了 T T). [正在看本人博客的这位童鞋,我看你气度不凡,谈 ...

随机推荐

  1. Easyui设置动态表格,动态导出数据实例,附Dome

    最近碰到一个需求,需要提供一个弹出页面选择列表页面需要显示的列,页面确认之后需要修改列表页面显示的表格,导出的数据也需要同步变化. 下面直接上代码 1.设置需要显示的列columus为全局对象,用于子 ...

  2. 数列[专杀Splay版]

    时间限制: 3 Sec  内存限制: 128 MB提交: 49  解决: 7 题目描述 输入一个数列,你需要进行如下操作:  1. 把编号为I的数值改为K  2. 输出从小到大排序后第k个数 输入 输 ...

  3. css清除浮动float

    css清除浮动float 1.分析HTML代码 <div class="outer"> <div class="div1">1</ ...

  4. 【LeetCode】66. Plus One

    题目: Given a non-negative number represented as an array of digits, plus one to the number. The digit ...

  5. Jenkins+Ant+TestNG+Testlink自动化构建集成(完整版)

    这段时间折腾自动化测试,之前都是在Eclipse工程里面手工执行自动化测试脚本,调用Testlink API执行测试用例,目前搭建Jenkins自动化构建测试的方式,实现持续构建,执行自动化测试. 硬 ...

  6. 处理input标签的border-radius

    给input设置border-radius效果时一定要先设置border属性,否则会出现左上部有阴影的效果.

  7. English - Titanium Bike

    The silver-gold triathlon bike was sitting in Kris's dining room next to the door. It had no kicksta ...

  8. 服务器 设置 将 Tomcat 注册 到系统服务 及使用方法

    将TOMCAT注册成系统服务的好处,就是方便维护,在服务器重启的时候,系统会自动启动系统服务,而不必手动操作,这就为我们在项目维护时省下不少麻烦. 在项目维护期间有很多客户只要一有问题,就电话招呼,而 ...

  9. JavaWeb 后端 <一> 之 Tomcat服务器 - Http协议 学习笔记

    1.Web开发概述 1.1服务器上的资源分类: a.静态资源:指web页面中供人们浏览的数据始终是不变.html css js 图片 多媒体 b.动态资源:指web页面中供人们浏览的数据是由程序产生的 ...

  10. nodejs 实践:express 最佳实践 (一)

    express 最佳实践 (一) 最近,一直在使用 nodejs 做项目,对 nodejs 开发可以说深有体会. 先说说 nodejs 在业务中的脚色,, 在 web同构 方面, nodejs 的优势 ...