2.3 运算符和表达式
在前面的例子程序中已经多次用到基本的运算。运算符是表示某种操作的符号,操作的对象叫操作数,用运算符把操作数连接起来形成一个有意义的式子叫表达式。C语言为了加强对数据的表达、处理和操作能力,提供了大量的运算符和丰富的表达式类型,其中最常用的是算术运算符和赋值运算符。
2.3.1 算术运算符与算术表达式
算术运算符分为一元算术运算符和二元算术运算符两类,一元算术运算符只需要一个操作数,放在运算符的后面,二元算术运算符需要两个操作数,操作数写在运算符两边。
1.C语言提供的算术运算符
C语言提供了如下算术运算符:
+(正号、加法运算符)
–(负号、减法运算符)
*(乘法运算符)
/(除法运算符)
%(求余运算符)
两个整数相除结果还是整数,如8/3结果为2。如果参加运算的两个数中有一个是实型,则结果为double型。
求余运算符要求%两侧都是整型数据,表达式x%y的结果为两数相除后的余数,如果x能被y整除,则结果为零。求余运算符不能应用到float型或double型。
2.算术表达式的计算
用算术运算符把常量、变量、函数等运算对象连接起来,称为算术表达式,如a+b*c-2+‘a’是一个合法的算术表达式,表达式的结果为一个算术值。运算符都有优先级和结合性,因此在求表达式的值时,要按照优先级的高低依次计算,如果一个运算量两侧运算符优先级相同,则按规定的结合方向进行。
算术运算符的优先级与代数中相同,即先乘除,后加减,结合性是从左到右,如当表达式中有多个加法或减法,则按从左到右的顺序求值。算术运算符的优先级见表2-3。
编写程序时,应能将代数表达式用正确的算术表达式表示出来。例如:
1)求三个数的算术平均值:
这里必须使用括号改变运算的次序,如果不使用括号,根据运算符的优先级a + b + c/3的计算结果为a+b+。
2)根据三角形三边计算三角形面积:
表达式中使用开平方根函数sqrt(),使用函数时后面必须使用一对括号,把所有参数括进去,括号可以嵌套,但要保证配对正确。
3)根据半径计算圆的周长:
代数表达式:s=2πr
算术表达式:s=23.14159r
表达式中使用了常量π,但是π不是C/C++字符集中的字符,因此用3.141 59表示。
2.3.2 赋值运算符与赋值表达式
C语言中“=”就是赋值运算符,它的作用是将一个数据赋给一个变量。
1.简单的赋值运算符
简单赋值就是把一个表达式的值赋给一个变量,格式为:
变量名 = 表达式
例如:
i = 1 /*将数值1赋给变量i*/
count = count + 1 /*计算count+1的值并赋给变量count*/
sum = i1 + i2 /*计算i1+i2的值并赋给变量sum*/
2.复合的赋值运算符
算术运算符与“=”结合在一起,形成复合的赋值运算符。例如:
i += 2等价于i = i + 2
a %= 3等价于a = a % 3
a * = b + 5等价于a = a *(b + 5)
对于复杂表达式,例如:
yyval[yypv[p1+p2] + yypv[p3+p4]] += 2
使用复合的赋值运算符简化了程序,使程序很容易理解,因为读者不必检查两个长表达式是否一致。赋值运算符也有利于编译,产生高质量的目标程序。
3.赋值表达式的计算
对赋值表达式求解的过程是:将赋值运算符右侧的表达式的值赋给左侧的变量。赋值表达式的值就是被赋值的变量的值。例如“x = 3”这个赋值表达式的值为3,而变量x的值也是3。
赋值运算符按照“自右向左”的结合顺序,如赋值表达式“a = b = 8”的计算顺序是:
1)首先计算“b = 8”的值,它的值等于8。
2)再计算“a = 8”,即a的值等于8,整个赋值表达式的值也等于8。
又比如,如果a的初值为6,赋值表达式“a += a-= a *= a”的求解步骤为:
1)先进行“a = a”的运算,它相当于a=aa=6*6=36。
2)再进行“a -= 36”的运算,它相当于a=a-36=36-36=0。
3)最后进行“a += 0” 运算,它相当于a=a+0=0+0=0。
2.3.3 数据类型的转换
当运算符两侧操作数的数据类型不同时,它们会按照提升规则自动进行类型转换,使二者具有同一类型,然后再进行运算。转换的规则见图2-2。
图2-2中横向向左的箭头表示必定的转换,如字符型(char)数据和短整型(short)必定先转换成整型(int),单精度浮点型(float)必定先转换为双精度浮点型(double),以提高运算精度。
图2-2中纵向的箭头表示当运算符两侧操作数的数据类型不同时自动转换的方向。数据总是由低级别向高级别转换,例如,一个int型数据与一个double型数据进行运算,则先将int型直接转换为double型,然后在两个同类型(double)数据之间进行运算;如果一个int型与一个long型数据进行运算,则将int型转换为long型再进行运算。
在进行赋值运算时也发生类型转换,右侧的值转换为左侧的值。例如,x为float型,i为int型,当进行x=i和i=x赋值操作时会引起类型转换。转换是按如下规则进行的:
1)char型转换为int型时没有变化。
2)long型转换为short型或char型时,截掉多余的高位信息。
3)float、double型转换为int型时,小数部分会被截掉。
在任何表达式中都可以强制类型转换。其形式为:
(类型名)表达式
例如,库函数sqrt()需要一个double型的参数,如果n是一个整型数,我们可以使用sqrt((double)n) 把n的值转换为double型。注意,在强制类型转换时,得到了一个所需类型的中间变量,原来变量n的类型并未发生变化。例如,有程序片段:
float x; int i;
x = 3.6;
i = (int)x;
printf("x=%f,i=%d\n", x , i);
运行结果如下:
x=3.600000, i=3
x的类型仍为float型,值仍等于3.6。
总之,在程序设计中,表达式的应用应注意两点,首先是考虑如何将代数式表示成正确的表达式,其次是考虑运算符的优先级、结合性及参与运算的数据类型的逐步转换问题。