刚刚开始看一本书。《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. R语言重要数据集分析研究——  数据集本身的分析技巧

    数据集本身的分析技巧           作者:王立敏           文章来源:网络 1.数据集 数据集,又称为资料集.数据集合或资料集合,是一种由数据所组成的集合. Data set(或dat ...

  2. Ecshop去掉模版中随机出现Ecshop版权的方法

    EC如果是免费用户用的话,模版里面会随机出现 powered by ecshop 的字样,看了一下原来是在COMMON.JS里面写的一段代码,删除掉就可以解决掉了,方法如下: 打开  js/commo ...

  3. gdb常用命令及使用gdb调试多进程多线程程序

    一.常用普通调试命令 1.简单介绍GDB 介绍: gdb是Linux环境下的代码调试⼯具.使⽤:需要在源代码⽣成的时候加上 -g 选项.开始使⽤: gdb binFile退出: ctrl + d 或 ...

  4. php下拉菜单选中值在选择之后保留并且显示

    <select id="select_platform" name="source" style="height:35px;"> ...

  5. [leetcode-625-Minimum Factorization]

    Given a positive integer a, find the smallest positive integer b whose multiplication of each digit ...

  6. 【Android Developers Training】 53. 打印HTML文档

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  7. [Paper Reading]--Exploiting Relevance Feedback in Knowledge Graph

    <Exploiting Relevance Feedback in Knowledge Graph> Publication: KDD 2015 Authors: Yu Su, Sheng ...

  8. oracle linux 7.3 下用dtrace 跟踪 mysql-community-server-5.6.20

    第一部分:oracle linux 7.3 dtrace 安装: http://public-yum.oracle.com/   内核升极到 [root@server1 SPECS]# uname - ...

  9. LCS 算法实现

    动态规划算法 #include <iostream> #include <string.h> #include <algorithm> #include <m ...

  10. 使用ajax提交form表单(转)

    前言 使用ajax请求数据,很多人都会,比如说: $.post(path,{data:data},function(data){ ... },"json"); 又或者是这样的aja ...