掌握C语言中各种运算符及其表达式的应用是必不可少的。
本章致力于使读者了解表达式的概念,掌握运算符及相关表达式的使用方法其中包括赋值运算符、算术运算符、关系运算符、逻辑运算符、位逻辑运算符、逗号运算符和复合赋值运算符,并且通过实例进行相应的练习,及时对其加深印象。
通过阅读本章,您可以:
了解表达式的使用
掌握赋值运算符
掌握算术运算符
掌握关系运算符
掌握逻辑和位逻辑运算符
掌握逗号运算符的使用方式
4.1 表达式
表达式是C语言的主体。在C语言中,表达式由操作符和操作数组成。最简单的表达式可以只含有一个操作数。根据表达式所含操作符的个数,可以把表达式分为简单表达式和复杂表达式两种,简单表达式是只含有一个操作符的表达式,而复杂表达式是包含两个或两个以上操作符的表达式。下面通过几个表达式进行观察:
5+5
iNumber+9
iBase+(iPay*iDay)
表达式本身什么事情也不做,只是返回结果值。在程序不对返回的结果值进行任何操作的情况下返回的结果值不起任何作用,也就是忽略返回的值。
表达式产生的作用主要有以下两种情况:
放在赋值语句的右侧(下面要讲解)。
放在函数的参数中(将在“函数”一章中进行讲解)。
表达式返回的结果值是有类型的。表达式隐含的数据类型取决于组成表达式的变量和常量的类型。
说明:每个表达式的返回值都具有逻辑特性。如果返回值是非零的,那么该表达式返回真值,否则返回假值。通过这个特点,可以将表达式放在用于控制程序流程的语句中,这样就构建了条件表达式。
例 4.1 掌握表达式的使用
4.2 赋值运算符与赋值表达式
4.2.1 变量赋初值
例 4.2 为变量赋初值
4.2.2 自动类型转换
数值类型有很多种,如字符型、整型、长整型和实型等,因为这些类型的变量、长度和符号特性都不同,所以取值范围也不同。混合使用这些类型时会出现什么情况呢?第3章已经对此有所介绍。C语言中使用一些特定的转换规则。根据这些转换规则,数值类型变量可以混合使用。如果把比较短的数值类型变量的值赋给比较长的数值类型变量,那么比较短的数值类型变量中的值会升级表示为比较长的数值类型,数据信息不会丢失。但是,如果把较长的数值类型变量的值赋给比较短的数值类型变量,那么数据就会降低级别表示,并且当数据大小超过比较短的数值类型的可表示范围时,就会发生数据截断。
有些编译器遇到这种情况时就会发出警告信息,例如:
float i=10.1f;
int j=i;
此时编译器会发出警告,如图4.3所示
4.2.3 强制类型转换
通过自动类型转换的介绍得知,如果数据类型不同,就可以根据不同情况自动进行类型转换,但此时编译器会提示警告信息。
这时如果使用强制类型转换告知编译器,就不会出现警告。
强制类型转换的一般形式为:
(类型名)(表达式)
例如在上述不同变量类型转换时使用强制类型转换的方法:
float i=10.1f;
int j=(int)i; //进行强制类型转换
在代码中可以看到在变量前使用包含要转换类型的括号,这样就对变量进行了强制类型转换。
例 4.3 显示强制类型转换的结果
通过不同类型变量之间的赋值,将赋值操作后的结果进行输出,观察类型转换后的结果。
#include <stdio.h>
int main ()
{
char cChar; //定义字符型变量
short int iShort; //定义短整型变量
int iInt; //定义整型变量
float fFloat=70000; //定义单精度浮点型
cChar=(char)fFloat; //强制转换赋值
iShort=(short)fFloat;
iInt=(int)fFloat;
printf("The char is:%c\n",cChar); //输出字符变量值
printf("The iShort is:%ld\n",iShort); //输出短整型变量值
printf("The int is:%d\n",iShort); //输出整型变量值
printf("The float is:%ld\n",fFloat); //输出单精度浮点型变量值
}
上述程序中定义了一个单精度浮点型变量,然后通过强制转换将其赋给不同类型的变量。因为是由高的级别向低的级别转换,所以可能会出现数据的丢失。在使用强制转换时要注意此问题。运行程序,显示效果如图 4.4 所示。
4.3 算术运算符与算术表达式
C语言中有2个单目算术运算符、5个双目算术运算符。在双目运算符中,乘法、除法和取模运算符比加法和减法运算符的优先级高。单目正和单目负运算符的优先级最高。下面详细进行介绍。
4.3.1 算术运算符
算术运算符包括
2个单目运算符(正和负),
5个双目运算符,即乘法、除法、取模、加法和减法
具体符号和对应的功能如下所示。
在上述算术运算符中,取模运算符“%”用于计算两个整数相除得到的余数,并且取模运算符的两侧均为整数,如 7%4的结果是 3。
说明:其中的单目正运算符是冗余的,也就是为了与单目运算符构成一对而存在的。单目运算符不会改变任何数值,如不会将一个负值表达式改为正。
说明:运算符“-”作为减法运算符,此时为双目运算符,如5-3.“_”也可作负值运算符,此时为单目运算,如-5等。
4.3.2 算术表达式
在表达式中使用算术运算符,则将表达式称为算术表达式。下面是一些算术表达式的例子,其中使用的运算符就是表 4.1中所列出的算术运算符:
Number=(3+5)/Rate;
Height=Top-Bottom+1;
Area=Height*Width;
需要说明的是,两个整数相除的结果为整数,如7/4的结果为1,舍去的是小数部分。但是,如果其中的一个数是负数时会出现什么情况呢?此时机器会采取“向零取整”的方法,即为-1,取整后向 0靠拢。
如果用+、-、、/运算的两个数中有一个为实数,那么结果是 double 型,这是因为所有实数都按 double 型进行运算。
例 4.4 使用算术表达式计算摄氏温度
通过在表达式中使用上面介绍的算术运算符,完成计算摄氏温度,把用户的华氏温度换算为摄氏温度,然后显示出来。
#include <stdio.h>
int main()
{
int iCelsius,iFahrenheit; //声明两个变量
printf(“Please enter temperature : \n”); //提示输入温度值
scanf(“%d”,&iFahrenheit); //在键盘上输入华氏温度
iCdlsius=5(iFahrenheit-32)/9; //通过算术表达式进行计算,并将结果赋值
printf("Temperature is : \n"); //显示提示信息
printf("%d",iCelsius); //显示摄氏温度
printf("degress Celsius\n"); //显示提示信息
return 0; //程序结束
}
(1)在主函数 main 中声明两个整型变量,iCelsius 表示摄氏温度,iFahrenheit 表示华氏温度。
(2)使用 printf函数显示提示信息。之后使用 scanf函数获得在键盘上输入的数据,其中%d 是格式字符,用来表示输入有符号的十进制整数,这里输入80。
(3)利用算术表达式,将获得的华氏温度转换成摄氏温度。最后将转换的结果进行输出,可以看到 80 是用户输入的华氏温度,而26是计算后输出的摄氏温度。运行程序,显示效果如图 4.5 所示。
4.3.3 优先级与结合性
C语言中规定了各种运算符的优先级和结合性,首先来看一下有关算术运算符的优先级。
1.算术运算符的优先级
在表达式求值时,先按照运算符的优先级别高低次序执行,算术运算符中、乘、除,%的优先级别高于+,-,的级别。例如,如果在表达式中同时出现*和+,那么先运算乘法:
在表达式中,因为乘比+的优先级高,所以先进行y乘z的运算,最后加上x
在表达式中常会出现这样的情况,例如要进行a+b再将结果与c相乘,将表达式写为 a+b*c.可是因为乘的优先级高于+,这样的话就会先执行乘法运算,显然不是期望得到的结果,这时应该怎么办呢?此时可以使用括号“()”将级别提高先进行运算,就可以得到预期的结果了,例如解决上式的方法是(a+b)*c,括号可以使其中的表达式先进行运算的原因在于,括号在运算符中的优先级别是最高的。
2.算术运算度的结合性
当算术运算符的优先级相同时,结合方向为“自左向右”。例如:
a-b+c
因为减法和加法的优先级是相同的,所以b先与减号相结合,执行a-b的操作,然后执行加c的操作。这样的操作过程就称为“自左向右的结合性”,在后面的介绍中还可以看到“自右向左的结合性”’。本章小结处将会给出有关运算符的优先级和结合性的表格,读者可以进行参照。
例4.5 算术运算符的优先级和结合性
通过不同运算符的优先级和结合性,使用printf函数显示最终的计算结果,根据结果体会优先级和结合性的概念。
4.3.4 自增、自减运算符
在C语言中还有两个特殊的运算符,即自增运算符“++”和自减运算符“- -”自增运算符和自减运算符对变量的操作分别是增加1和减少1。
自增运算符和自减运算符可以放在变量的前面或者后面,放在变量前面称为前缀,放在后面称为后缀,使用的一般方法如下:
在上面这些例子中,运算符的前后位置不重要,因为所得到的结果是一样的,自减就是减1,自增
就是加1。
说明:在表达式内部,作为运算的一部分,两者的用法可能有所不同。如果运算符放在变量前面,那么变量在参加表达式运算之前完成自增或者自减运算;如果运算符放在变量后面,那么变量的自增或者自减运算在变量参加了表达式运算之后完成。
例 4.6比较自增、自减运算符前缀与后缀的不同
4.4 关系运算符与关系表达式
在数学中,经常会比较两个数的大小。在C语言中,关系运算符的作用就是判断两个操作数的大小关系。
4.4.1 关系运算符
关系运算符包括大于、大于等于、小于、小于等于、等于和不等于,如表 4.2 所示
说明:符号“>=”(大于等于)与“<=”(小于等于)的意思分别是大于或等于、小于或等于。
4.4.2 关系表达式
关系运算符用于对两个表达式的值进行比较,返回一个真值或者假值。返回真值还是假值取决于表达式中的值和所用的运算符。其中真值为 1,假值为 0,真值表示指定的关系成立,假值则表示指定的关系不正确。例如:
关系运算符通常用来构造条件表达式,用在程序流程控制语句中,如if语句是用于判断条件而执行语句块,在其中使用关系表达式作为判断条件,如果关系表达式返回的是真值则执行下面的语句块,如果为假值就不去执行。代码如下:
if(Count<10)
{
… //判断条件为真,执行代码
}
其中,if(iCount<10)就是判断iCount 小于 10这个关系是否成立,如果成立则为真,如果不成立则为假。
4.4.3 优先级与结合性
关系运算符的结合性都是自左向右的。使用关系运算符时常常会判断两个表达式的关系,但是由于运算符存在着优先级的问题,因此如果不小心处理则会出现错误。如要进行这样的判断操作:先对一个变量进行赋值,然后判断这个赋值的变量是否不等于一个常数,代码如下:
if(Number=NewNum!=10)
{
…
}
因为“!=”运算符比“=”的优先级要高,所以 NewNum!-0的判断操作会在赋值之前实现,变量Number 得到的就是关系表达式的真值或者假值,这样并不会按照之前的意愿执行。前文曾经介绍过括号运算符,其优先级具有最高性,因此使用括号来表示要优先计算的表达式,例如:
if((Number=NewNum)!=10)
{
…
}
这种写法比较清楚,不会产生混淆,没有人会对代码的含义产生误解。由于这种写法格式比较精
确简洁,因此被多数程序员所接受。
例 4.7 关系运算符的使用
定义两个变量表示两个学科的分数,使用if语句判断两个学科的分数大小,通过 prin输出函数显示信息,得到比较的结果。
为了可以在键盘上得到两个学科的分数,定义变量 iChinese 和iEnglish。然后利用 if语句进行判断,在判断条件中使用了关系表达式,判断分数是否使得表达式成立。如果成立则返回真值,如果不成立则返回假值。最后根据真值和假值选择执行语句。运行程序,显示效果如图 4.8 所示。
4.5 逻辑运算符与逻辑表达式
逻辑运算符根据表达式的真或者假属性返回真值或假值。在C语言中,表达式的值非零,那么其值为真。非零的值用于逻辑运算,则等价于1;假值总是为0。
4.5.1 逻辑运算符
逻辑运算符有 3种,如表 4.3 所示。
表 4.3 中的逻辑与运算符“&&”和逻辑或运算符“||”都是双目运算符,
4.5.2 逻辑表达式
4.5.3 优先级与结合性
“&&”和“"”是双目运算符,它们要求有两个操作数,结合方向自左至右;“!”是单目运算符要求有一个操作数,结合方向自左向右。
逻辑运算符的优先级从高到低依次为单目逻辑非运算符“!”、逻辑与运算符“&&”和逻辑或运算符“||”
例 4.8 逻辑运算符的应用
使用逻辑运算符构造表达式,通过输出函数显示表达式的结果,根据结果分析表达式中逻辑运算符的计算过程。
4.6 位逻辑运算符与位逻辑表达式
位运算是C语言中比较有特色的内容。位逻辑运算符可实现位的设置、清零、取反和取补操作。
利用位运算可以实现只有部分汇编语言才能实现的功能。
4.6.1 位逻辑运算符
位逻辑运算符包括位逻辑与、位逻辑或、位逻辑非、取补,如表4.4 所示。
表 4.4中除了最后一个运算符是单目运算符外,其他都是双目运算符,这些运算符只能用于整型表达式。位逻辑运算符通常用于对整型变量进行位的设置、清零和取反,以及对某些选定的位进行检测。
4.6.2 位逻辑表达式
在程序中,位逻辑运算符一般被程序员用作开关标志。较低层次的硬件设备驱动程序,经常需要对输入/输出设备进行位操作。
如下位逻辑与运算符的典型应用,对某个语句的位设置进行检查:
if(Filed&BITMASK)
语句的含义是if语句对后面括号中的表达式进行检测。如果表达式返回的是真值,则执行下面的语句块,否则跳过该语句块不执行。其中运算符用来对 BITMASK 变量的位进行检测,判断其是否与
Field 变量的位有相吻合之处。
**
4.7 逗号运算符与逗号表达式
**
在C语言中,可以用逗号将多个表达式分隔开来。其中,用逗号分隔的表达式被分别计算,并且整个表达式的值是最后一个表达式的值。
逗号表达式称为顺序求值运算符。逗号表达式的一般形式如下:
表达式1,表达式2,表达式3,表达式n
逗号表达式的求解过程是:先求解表达式1,再求解表达式2,一直求解到表达式n。整个逗号表达式的值是表达式n的值。
观察下面使用逗号运算符的代码:
Value=2+5;1+2,5+7;
上面语句中 Value 所得到的值为7,而非 12。整个逗号表达式的值不应该是最后一个表达式的值吗?为什么不等于12呢?答案在于优先级的问题,由于赋值运算符的优先级比逗号运算符的优先级高。因此先执行赋值的运算。如果要先执行逗号运算,则可以使用括号运算符,代码如下:
Value=(2+5;1+2,5+7);
还用括号之后,Value的值为12.
例 4.9 用逗号运算符分隔的表达式
通过逗号运算符将其他运算符结合在一起形成表达式,再将表达式的最终结果赋值给变量。由显示变量的值,分析逗号运算符的计算过程。
(1)在程序代码的开始处,声明变量时就使用了逗号运算符分隔声明变量。前文已经对此有所
介绍。
(2)将前面使用逗号分隔声明的变量进行赋值。在逗号表达式中,赋值的变量进行各自的计算,变量 iResult 得到表达式的结果。这里需要注意的是,通过输出可以看到iResult 的值为 10,从前面的讲解知道因为逗号表达式没有使用括号运算符,所以esult 得到第一个表达式的值。在第一个表达式中,iValue1 变量进行的是后缀自加操作,于是iResult 先得到 iValuel 的值,iValue1 再进行自加操作。
(3)在第二个表达式中,由于使用了括号运算符,因此iResult,变量得到的是第3个表达式iValue3+4 的值,iResult 变量赋值为 30。
**
4.8 复合赋值运算符
**
复合赋值运算符是C语言中独有的,实际这种操作是一种缩写形式,可使得变量操作的描述方式更为简洁。例如在程序中为一个变量赋值:
Value=Value+3;
这个语句是对一个变量进行赋值操作,值为这个变量本身与一个整数常量3相加的结果值。使用复合赋值运算符可以实现同样的操作。例如上面的语句可以改写成:
Value+=3;
这种描述更为简洁。关于上面两种实现相同操作的语句,赋值运算符和复合赋值运算符的区别在于:
为了简化程序,使程序精练。
区 为了提高编译效率。对于简单赋值运算符,如 Func=Func+1中,表达式 Func 计算两次;对于复合赋值运算符,如 Func+=1中,表达式 Func 仅计算一次。一般来说,这种区别对于程序的运行没有太大的影响,但是如果表达式中存在某个函数的返回值,那么函数被调用两次。
例 4.10 使用复合赋值运算符简化赋值运算
**
4.9 小结
**
本章介绍了程序的各种运算符与表达式。首先介绍了表达式的概念,帮助读者了解后续章节所需要的准备知识。然后分别介绍了赋值运算符、算术运算符、关系运算符、逻辑运算符、位逻辑运算符和逗号运算符。最后讲解了如何使用复合运算符简化程序的编写。同时为了方便读者,这里按照优先级从小到大的排列顺序列出了C语言中运算符的优先级和结合性,如表 4.5 所示。