c语言左值中有运算符,C语言左值,运算符的优先级以及结合性探讨

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

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

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

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

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

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

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

#include

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

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.关于++i 与 i++的区别. ++i 和 i++如果是单独使用的语句,即二者后面均加上分号,或者其他单独使用的语句,没有任何区别.例如: for(i=0;i<100; ...

说说C语言运算符的&OpenCurlyDoubleQuote;优先级”与&OpenCurlyDoubleQuote;结合性”

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

C语言的运算符的优先级与结合性&plus;ASCII表

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

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

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

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

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

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

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

C语言 左值、右值

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

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

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

【部分原创】标准C语言的优先级、结合性、求值顺序、未定义行为和非确定行为浅析

零. 优先级    在C++ Primer一书中,对于运算符的优先级是这样描述的:     Precedence specifies how the operands are grouped. It ...

随机推荐

c&num;中匿名函数lamb表达式

c#中匿名函数lamb表达式 实例一:(其实,这样都是些语法糖) using System; using System.Collections.Generic; using System.Linq; ...

Spring的IoC应用

IoC(Inversion of Control,控制反转) Spring的IoC应用是其框架的最大的特点,通过依赖注入可以大大降低代码之间的耦合度,从而实现代码和功能之间的分离.在代码中可以不直接和 ...

HTML5几种常见的错误写法

本文介绍了HTML5常见的6种错误写法,包括:1.不要使用section作为div的替代品 2.只在需要的时候使用header和hgroup 3.不要把所有列表式的链接放在nav里 4.figure元 ...

读懂IL代码(二)

上一篇提到了最基本的IL代码,应该是比较通俗易懂的,所以有了上一篇的基础之后,这篇便要深入一点点的来讲述了. 首先我必须再来说一些重要的概念: Evaluation Stack(评估栈):这是由.NE ...

模拟美萍加密狗--Rockey2虚拟狗&lpar;三&rpar;

几经挣扎,我最终还是选择了虚拟设备的方法来模拟Rockey2加密狗.HID.DLL劫持+API劫持的办法技术上虽然简单些,但太繁琐了,不仅要转发大量的函数,还要Hook好几个API,向我这么懒的人可干 ...

bundle export fail

C:\eclipse\eclipse.exe -vmargs -Dfile.encoding=utf8

python 常用代码

获取标签名 h1 class 是h1usersoup.find(name="h1", attrs={"class":"h1user"});获 ...

hdu1305Immediate Decodability&lpar;字典树)

这题看是否 这题能A是侥幸,解决的办法是先存一下输入的字符串,进行排序. Problem Description An encoding of a set of symbols is said to ...

王立平--include在Android中的应用

一个布局中包括还有一个布局 1.在layout下定义activity_other.xml布局 2.代码中的包括例如以下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值