5.1 运算符概述
运算符是一种告诉编译器执行数学或逻辑操作的符号。在C语言中,运算符包括赋值运算符、算术运算符、关系运算符、逻辑运算符和位运算符等。
5.1.1 赋值运算符
赋值运算就是把数据赋给一个变量的过程。C语言中赋值运算符可以分为简单运算符和复合运算符。如表5-1列出了C语言所支持的赋值运算符。
表5-1 赋值运算符
注意:
(1)在书写赋值运算符时,两个符号之间一定不能有空格,否则将会出错。
(2)带有位逻辑的赋值运算符(<<=、>>=、&=、^=、|=),是按二进制的格式进行操作的。
在声明一个变量时,就可以为其赋一个初始值。变量赋值为常数的语法格式:
类型 变量名 = 常数;
例如:
int a = 3; char b = 4; float c = 5.0;
变量赋值为表达式的语法格式:
类型 变量名 = 表达式;
例如:
int a = 2+2; int b = a+2; char c = 3+3; char d = c+3;
注意:
(1)赋值的左操作数必须是一个变量,C语言中可以对变量进行连续赋值,这时赋值运算符是右关联的,这意味着从右向左运算符被分组。例如,形如a=b=c的表达式等价于a=(b=c)。
(2)如果赋值运算符两边的操作数类型不一致,如果存在隐式转换,系统会自动将赋值号右边的类型转换为左边的类型再赋值;如果不存在隐式转换,那就先要进行显式类型转换,否则程序会报错。
【例5-1】编写程序,定义int型变量a和c,使用常见赋值运算符对a进行相应的运算操作,然后将结果赋予c输出。(源代码\ch05\5-1)
运行上述程序,结果如图5-1所示。
图5-1 常见赋值运算符的使用
【代码解析】
本例演示了常见的赋值运算符的使用方法。代码中首先定义int型变量a和c,对a赋值15,然后进行一系列的赋值运算:首先“c=a”为最基本的赋值运算,注意“=”与数学中的含义“相等”是完全不一样的概念;“c+=a”可以表示为“c=c+a”,故而计算结果为30;“c-=a”可以表示为“c=c-a”,也就是计算30-15的值;“c*=a”可以表示为“c=c*a”,也就是计算15*15的值;“c/=a”可以表示为“c=c/a”,也就是计算225/15的值;“c%=a”可以表示为“c=c%a”,也就是计算200%15的值。这里需要注意如果要使用printf()函数输出“%”符号,需要写成“%%”的形式。
5.1.2 算术运算符
算术运算符是进行算数运算的运算符,根据算术运算符需要变量参与运算的个数可以分为一元运算符和二元运算符。
1.算术运算
如表5-2列出了C语言所支持的算术运算符,假设变量A的值为10,变量B的值为20。
表5-2 算术运算符
【例5-2】编写程序,定义int型变量a、b、c,并初始化a的值为10,b的值为20,对a和b进行+、-、*、/和%运算,将结果赋给c。(源代码\ch05\5-2)
运行上述程序,结果如图5-2所示。
图5-2 算数表达式
【代码解析】
本例详细地演示了多种算术表达式。程序中首先定义int型变量a、b、c,并初始化a和b的值,通过使用+、-、*、/、%运算符,对变量a与变量b进行了相应的运算操作,并将结果赋给c,打印c的值。这里需要注意如果要使用printf()函数输出“%”符号,需要写成“%%”的形式。
2.自增和自减运算
自增、自减运算符分为前缀和后缀。当++或--运算符置于变量的左边时,称为前置运算或前缀,表示先进行自增或自减运算,再使用变量的值。而当++或--运算符置于变量的右边时,称为后置运算或后缀,表示先使用变量的值,再自增或自减运算。前置后置运算方法,如表5-3所示。
表5-3 前置后置运算方法
提示
该运算只用于变量,不可用于常量和表达式。
【例5-3】编写程序,定义int型变量a和b,分别对a做前置运算和后置运算,将运算结果赋予b,分别输出a、b的值。(源代码\ch05\5-3)
运行上述程序,结果如图5-3所示。
图5-3 前置运算以及后置运算
【代码解析】
在本例中,b=a++先将a赋值给b,再对a进行自增运算。b=a--先将a赋值给b,再对a进行自减运算。b=++a先将a进行自增运算,再将a赋值给b。b=--a先将a进行自减运算,再将a赋值给b。
5.1.3 关系运算符
C语言中关系运算符的作用是判断两个操作数的大小。判断的结果要么是“真”,要么是“假”,也就是说关系表达式的返回值为“1”或者为“0”。“1”表示真,“0”表示假。如表5-4列出了C语言所支持的关系运算符,假设变量A的值为10,变量B的值为20。
表5-4 关系运算符
注意:
(1)关系运算符中的等于号==很容易与赋值号=混淆,一定要记住,=是赋值运算符,而==是关系运算符。
(2)符号“>=”(大于等于)与“<=”的意思分别是:大于或等于,小于或等于。
(3)在用大于小于运算符对值进行判断时,如果把判断符号左右两边的值进行调换,其判断的结果也会随之改变。
【例5-4】编写程序,定义两个变量a和b,用关系运算表达式通过if判断语句输出结果。(源代码\ch05\5-4)
提示
关系运算符一般常用于判断或循环语句中。
运行上述程序,结果如图5-4所示。
图5-4 常见关系运算符的使用
【代码解析】
本例详细地演示了多种关系表达式。程序中首先定义int型变量a和b,并初始化a与b的值,通过使用if判断语句,对变量a与变量b进行了相应的运算操作,并打印出来结果。
5.1.4 逻辑运算符
在C语言中,逻辑运算的结果只有“真”和“假”,“真”对应的值为1,“假”对应的值为0。表5-5列出了C语言所支持的逻辑运算符。假设变量A的值为1,B的值为0。
表5-5 逻辑运算符
C语言中的逻辑运算符是根据表达式真或假的属性来返回真值或假值。它们的优先级顺序为非,与,或。它们含义如下:
非(!):当操作数为真时,结果为假,并且它的优先级也是最高,因为它是一元运算符;
例如:
!(4>3)
表达式4>3为“真”,而表达式取反之后的结果为“假”。
与(&&):只有当两个操作数都为真时,结果才为真,否则为假。
例如:
6>5&&4>3
因为表达式6>5为“真”,表达式4>3也为“真”,所以与运算的结果为“真”。
或(||):只有当两个操作数都为假时,结果才为假,否则结果为真。
例如:
6>5||3>4
其中表达式6>5为“真”,表达式3>4为“假”,但是或运算只要有一个操作数为“真”即可,所以相或的结果为“真”。
【例5-5】编写程序,两变量a和b,用逻辑运算表达式通过if判断语句输出结果。(源代码\ch05\5-5)
运行上述程序,结果如图5-5所示。
图5-5 常见逻辑运算符的使用
【代码解析】
本例详细地演示了多种逻辑表达式。程序中首先定义int型变量a和b,并初始化a与b的值,通过比较变量,判断条件的返回值为真还是为假。
5.1.5 位逻辑运算符
任何信息在计算机中都是以二进制的形式保存。C语言中提供了&(与)、|(或)、^(异或)、~(取补)四种位逻辑运算符,对二进制数据精准操作。其中,取补运算符为一元运算符,而其他的位逻辑运算符都是二元运算符。为了方便掌握位逻辑运算符的使用,其运算结果可以用逻辑运算的“真值表”来表示,如表5-6所示。
表5-6 真值表
表5-7显示了C语言支持的位逻辑运算符。假设变量A的值为60,变量B的值为13,转换成二进制分别为“00111100”和“00001101”。
表5-7 位逻辑运算符
【例5-6】编写程序,定义无符号int型变量x、y并初始化为60和17;定义int型变量z并初始化为0。对x、y进行相关位运算操作,将结果赋予变量z并输出。(源代码\ch05\5-6)
运行上述程序,结果如图5-6所示。
图5-6 位逻辑运算符的使用
【代码解析】
本例定义了两个无符号int型变量x和y分别为60和17,将它们转换为二进制数为“0011 1100”和“0001 0001”,位运算就是对二进制数进行相应的运算,这里需要讲解一下取补运算,所谓取补就是“取反再转换为补码”,十进制的60,对其二进制“取反”即为“1100 0011”。而转换成补码为“0011 1101”,对应的十进制数为61,当最高位是“1”的时候取负,故~a结果为-61。
5.1.6 移位运算符
移位运算符是将数据看成二进制数,对其进行向左或向右移动若干位的运算。移位运算符分为左移和右移两种,均为二元运算符。第一运算对象是移位对象,第二个运算对象是所移的二进制位数。如表5-8列出了C语言所支持的移位运算符。
表5-8 移位运算符
【例5-7】编写程序,定义无符号int型变量a,并初始化为60,对a进行相关位运算操作,将结果赋予变量a并输出。(源代码\ch05\5-7)
运行上述程序,结果如图5-7所示。
图5-7 移位运算符的使用
【代码解析】
本例定义了两个无符号int型变量a并赋值60,将其转换为二进制数为“0011 1100”,移位运算就是对二进制数进行相应的运算。执行语句a>>3时,二进制码为“0000 0111”(十进制7);执行语句a<<3,二进制码为“0011 1000”(十进制56)。对于有符号数,在右移时,符号位将随同移动。当为正数时,最高位补0,而为负数时,符号位为1,最高位是补0或是补1取决于编译系统的规定。
5.1.7 条件运算符
C语言中提供了一个三元运算符“?:”,也将其称为条件运算符。条件运算符是先计算条件,然后进行判断。如果条件表达式的结果为“真”,计算表达式1的值,表达式1为整个条件表达式的值;否则,计算表达式2,表达式2为整个条件表达式的值,如表5-9所示。
表5-9 条件运算符
条件运算符的语法格式为:
条件表达式?表达式1:表达式2
例如,实现求出a和b中最大数的表达式。
if(a>b) max=a; else max=b;
可用条件运算表达式写为:
max=a>b?a:b //如a>b为真,则把a赋予max,否则把b赋予max
条件运算符的优先级高于赋值符,低于关系运算符和算术运算符。
例如:
(a>b)?a:b (等价于)a>b?a:b
条件运算符的结合性规则是自右向左,例如:
a>b?a:c<d?c:d (等价于)a>b?a:(c<d?c:d)
提示
在条件运算符中“?”与“:”是一对运算符,不可拆开使用。
【例5-8】编写程序,定义两个int型变量,通过输入端输入两数的值,再使用条件表达式比较它们的大小,将较大数输出。(源代码\ch05\5-8)
运行上述程序,结果如图5-8所示。
图5-8 条件运算符的使用
【代码解析】
本例演示如何通过条件表达式来判断并返回两数中较大者。首先在代码中定义两个int型变量a与b。然后通过scanf()函数,从输入端读入两个整数,接着在printf()函数中使用条件表达式,比较a与b两个数的大小,最后将较大数输出。
5.1.8 逗号运算符
在C语言中,逗号“,”也属于一种运算符,称为逗号运算符。逗号运算符的功能是将两个表达式连接起来成为一个表达式,这就是逗号表达式。
逗号表达式的语法格式为:
表达式1,表达式2
逗号表达式的运算方式为分别对两个表达式进行求解,然后以表达式2的计算结果作为整个逗号表达式的值。
逗号表达式的语法格式为:
(表达式1,表达式2)
逗号表达式的运算方式为分别对两个表达式进行求解,然后以表达式2的计算结果作为整个逗号表达式的值。
在逗号表达式中可以使用嵌套的语法格式,例如:
表达式1,(表达式2,表达式3…表达式n)
将上述逗号表达式展开可以得到:
表达式1,表达式2,表达式3…表达式n
提示
表达式n为整个逗号表达式的值。
并不是在所有出现逗号的地方都组成逗号表达式。在变量说明中,函数参数表中逗号只是用作各变量之间的间隔符。例如:
int x=3,y=4,z=7,a,b; //在定义变量时,逗号只是用作间隔符
【例5-9】编写程序,定义int型变量x、y、z、a、b。对x、y、z进行初始化,它们的值分别为3、4、7,然后计算逗号表达式a=(b=z-x,x+z,y*z),最后输出a、b的值。(源代码\ch05\5-9)
运行上述程序,结果如图5-9所示。
图5-9 逗号运算符的使用
【代码解析】
本例用于演示逗号表达式的计算,以及如何判断逗号表达式的计算结果。在代码中,首先定义了5个变量x、y、z、a、b,然后对x、y、z分别进行初始化,计算第一个逗号表达式的值,在此逗号表达式中“x+y”为表达式1,“x+z”为表达式2。所以计算完毕后表达式2的值作为逗号表达式的结果,并赋值给a。接着计算第二个逗号表达式的值,此逗号表达式中“b=z-x”为表达式1,“x+z”为表达式2,“y*z”为表达式3。所以计算完毕后表达式3的值作为逗号表达式的结果,并赋值给a。
5.1.9 类型转换运算符
类型转换有两种,一种是代码运算时不必用户指定,系统自动进行的类型转换;第二种是强制类型转换。当自动类型转换不能实现目的时,可以用强制类型转换使参加运算的两侧均为同一种类型,而强制类型转换是通过类型转换运算符来实现的。
其一般语法格式为:
(类型说明符)(表达式)
其功能是把表达式的运算结果强制转换成类型说明符所表示的类型。
例如:
(float)a; // 把a转换为实型 (int)(x+y); // 把x+y的结果转换为整型
注意:
(1)类型说明符和表达式都必须加括号(单个变量可以不加括号),如把(int)(x+y)写成(int)x+y就变成了把x转换成int型之后再与y相加了。
(2)无论是强制转换或是自动转换,都只是为了本次运算的需要而对变量的数据长度进行的临时性转换,而不改变数据说明时对该变量定义的类型。
(3)实型赋予整型,舍去小数部分。
(4)整型赋予实型,数值不变,但将以浮点形式存放,即增加小数部分(小数部分的值为0)。
(5)字符型赋予整型,由于字符型为一个字节,而整型为二个字节,故将字符的ASCII码值放到整型量的低八位中,高八位为0。整型赋予字符型,只把低八位赋予字符量。
【例5-10】编写程序,实现强制数据类型转换。(源代码\ch05\5-10)
#include <stdio.h> int main() { float PI=3.14159; // 定义实型变量PI printf("(int)PI=%d\n PI=%f\n",(int)PI,PI); // 输出使用类型转换运算符的值 return 0; }
运行上述程序,结果如图5-10所示。
图5-10 数据类型运算符的使用
【代码解析】
本例表明,PI虽强制转为int型,但只在运算中起作用,是临时的,而PI本身的类型并不改变。因此,(int)PI的值为3(删去了小数)而PI的值仍为3.14159。