1.2.4 运算符的结合性
我们说过,如果需要的话,每个表达式都可以计算出一个值。表达式n<= 100可以计算出一个值,如果变量n的值的确小于等于100,则该表达式的值为1,否则为0;表达式sum + n也可以计算出一个值,这个值是变量sum和变量n的值相加的结果。
即使是一个赋值表达式,例如表达式n = 1,也可以计算出一个值,该表达式的值是变量n被赋值之后的新值。因为这个原因,我们可以写出这样的表达式语句:
sum = n = 0;
首先我要说明的是,这个语句里的表达式sum = n = 0没有一点问题,是个合法的表达式。棘手的是,这里只有两个运算符,还一模一样,原先的优先级规则不管用了,你不知道中间的n到底是哪个=的操作数。
如果运算符的优先级不同,还能分出个高下先后,如果优先级相同,这就得定出个章程来。最好的办法就是按顺序轮流挑选操作数。比如,可以先从最左边的运算符来,由它先挑操作数,然后依次是右边的运算符,这称为“从左往右结合”;或者,也可以反过来,先让最右边的运算符来挑操作数,然后依次是左边的运算符,这称为“从右往左结合”。
这样安排,大家都服气,C语言就是这么干的。那么,到底是从左往右结合呢,还是从右往左结合?这还不一定。在C语言里,有些运算符是从左往右结合的,而有的则是从右往左结合的,这称为运算符的结合性。
运算符=是从右往左结合的。所以,在刚才那个例子中,n和0是右边那个运算符=的操作数,左边那个运算符=的操作数则是sum和n = 0的值。
因此,这个表达式的计算过程是这样的:先计算表达式n = 0的值,这个值是变量n被赋值之后的新值;接着,这个值又被赋给变量sum。这个表达式语句执行结束后,变量sum和变量n的值相同,都是0。原则上,表达式sum = n = 0在整体上也要计算出一个值,但这个值没有什么用。
在C语言里,运算符的作用是对操作数进行计算和加工,所以,表达式的值也是运算符“运算”和“加工”的结果。从这个意义上说,表达式的值也被认为是运算符的值或者运算符的结果。例如表达式1 + 2的结果是3,我们就认为这个3是运算符+的结果,或者说是运算符+的值。再比如,表达式n = 1的值也是运算符=的结果;表达式n<= 100的值也是运算符<=的结果;表达式sum + n的值也是运算符+的结果;而表达式sum = sum + n呢,因为这是一个赋值表达式,故该表达式的值是运算符=的结果。
计算表达式的值,被称为表达式的值计算,简称值计算。C语言规定,操作数的值计算必须先于运算符的值计算。比如对于表达式n<= 100,因为运算符<=的操作数是n和100,所以是先计算操作数n的值,也就是先进行左值转换,然后才开始计算运算符<=的值。
再比如表达式sum = sum + n,因为它是一个赋值表达式,运算符=的操作数是sum和sum + n的值,所以必须先计算子表达式sum + n的值;而对于表达式sum + n来说,因为sum和n是运算符+的操作数,所以必须先要对sum和n进行左值转换,然后才开始计算运算符+的值。然而,子表达式sum和n的值谁先计算却没有规定。
每个运算符都有它的优先级和结合性,但是,任由它们自然结合可能会带来麻烦。比如在上学的时候,要计算5加上6乘以2的结果,列出的算式为5+6×2。但是,如果我们是希望先将5和6相加,结果再乘以2,怎么办呢?老师会教我们使用括号来改变计算顺序:(5+6)×2。
同样,如果我们希望C语言里的表达式能够打破运算符固有的优先级和结合性,也得使用括号。这里有个实际的例子,在我们现有的程序中,为了给变量n和sum赋值,使用了两条表达式语句:
n = 1; sum = 0;
但是,我们现在要用一条语句来完成这两条语句的工作,该怎么写呢?答案是将这两条语句替换为下面这条表达式语句:
n = (sum = 0) + 1;
用一对圆括号括住的表达式,连同这对圆括号一起,被称为括住的表达式。括住的表达式属于C语言里的基本表达式,而基本表达式是其他表达式的基本构件。用作表达式的标识符、常量等,都是基本表达式。例如,在表达式n =(sum = 0)+ 1里,n、sum、0、1和(sum = 0)都是基本表达式。
在这里,作为一个基本表达式,括住的表达式(sum = 0)要独立地进行计算,并得到一个值,这个值是运算符+的左操作数。显然,这条语句的意思是将常量0赋给变量sum,然后,用表达式sum = 0的值与常量1相加,结果再赋给左值n。当这条语句执行之后,变量sum的值为0,变量n的值为1。
截至目前,我们已经知道表达式有多种作用。比如,它可以指示一个变量,也可以计算出一个值。就表达式的作用而言,是将运算符施加于操作数并计算出结果。但是你也看到了,很多表达式不但会计算出一个值,还会改变变量的存储值(甚至改变文件的内容)。例如表达式n = 1就改变了变量n的存储值。
这样的效果更像表达式在值计算过程中的一个副产品、一个额外的结果,故称之为副作用。因此,我们说表达式可以指示一个变量,也可以计算出一个值,还可以发起一个副作用,这都是表达式的作用。
练习1.3
1.给定表达式a = b + c,请判断下面的说法是否正确:
(a)运算符+的结果也是表达式b + c的值。( )
(b)运算符=的值也是表达式a = b + c的值。( )
(c)运算符+的优先级比=高。( )
(d)这是一个赋值表达式。( )
(e)要计算运算符+的值,必须先计算操作数b和c的值。( )
(f)先计算b的值,再计算c的值,然后计算运算符+的值。( )
2.若n是一个int类型的变量,且其值为0,则以下( )是表达式;( )是语句;表达式n = 1 + n的值为( )。
A.n +
B.n + 1
C.n =
D.n;
E.n + n
3.表达式语句由( )和( )组成。
4.while语句由关键字( )、位于圆括号中的( )、作为循环体的( )组成。
A.分号
B.while
C.While
D.表达式
E.语句
5.若m是一个int类型的变量,则以下( )是语句。
A. m
B.m;
C.m + 1;
D.m = m + 1 + m;