资源预览内容
第1页 / 共53页
第2页 / 共53页
第3页 / 共53页
第4页 / 共53页
第5页 / 共53页
第6页 / 共53页
第7页 / 共53页
第8页 / 共53页
第9页 / 共53页
第10页 / 共53页
亲,该文档总共53页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
第3章 运算符与表达式运算符与表达式 运运算算符符(operator)也也称称为为操操作作符符,对对程程序序中中的的数数据据进进行行运运算。参与运算的数据称为操作数算。参与运算的数据称为操作数(operand)。 变变量量、字字面面常常量量等等通通过过运运算算符符组组合合成成表表达达式式,一一个个表表达达式式也能作为操作数来构成更复杂的表达式。也能作为操作数来构成更复杂的表达式。 表达式表达式(expression)是构成程序语句的基本要素。是构成程序语句的基本要素。3.1 基本运算符n n对于运算符,应注意以下几方面。(1) 运算符的功能和语义。 (2) 运算符的操作数。每个运算符对其操作数的个数、类型和值都有一定限制。(3) 运算符的优先级(precedence)。每个运算符都有确定的优先级。 (4) 运算符的结合性(associativity)。表3.1给出了C+中的主要运算符的功能、优先级、目数、结合性。表中按优先级从高到低分为16个级别。基本运算符基本运算符优先级优先级优先级优先级运算符运算符运算符运算符功能及说明功能及说明功能及说明功能及说明结合性结合性结合性结合性目数目数目数目数1 1( )( )改变运算优先级改变运算优先级改变运算优先级改变运算优先级左向右左向右左向右左向右双目双目双目双目:作用域解析、全局作用域解析、全局作用域解析、全局作用域解析、全局 数组下标数组下标数组下标数组下标. . 访问成员,由指针访问成员访问成员,由指针访问成员访问成员,由指针访问成员访问成员,由指针访问成员2 2+ -+ -后缀自增、自减运算后缀自增、自减运算后缀自增、自减运算后缀自增、自减运算单目单目单目单目new deletenew delete动态分配或释放内存动态分配或释放内存动态分配或释放内存动态分配或释放内存+ -+ -前缀自增、自减运算符前缀自增、自减运算符前缀自增、自减运算符前缀自增、自减运算符* *间接访问间接访问间接访问间接访问 dereferencedereference&取地址取地址取地址取地址 address-ofaddress-of+ -+ -正、负号正、负号正、负号正、负号! !逻辑非逻辑非逻辑非逻辑非按位取反按位取反按位取反按位取反sizeofsizeof取类型或变量的长度取类型或变量的长度取类型或变量的长度取类型或变量的长度( (typetype) )强制类型转换强制类型转换强制类型转换强制类型转换右向左右向左右向左右向左2*2*.* .* *由成员指针访问成员由成员指针访问成员由成员指针访问成员由成员指针访问成员左向右左向右左向右左向右双目双目双目双目Operator.doc优先级优先级优先级优先级运算符运算符运算符运算符功能及说明功能及说明功能及说明功能及说明结合性结合性结合性结合性目数目数目数目数3 3* * / %/ %乘、除、取余乘、除、取余乘、除、取余乘、除、取余左向右左向右左向右左向右双目双目双目双目4 4+ -+ -加、减加、减加、减加、减左向右左向右左向右左向右双目双目双目双目5 5左移位、右移位左移位、右移位左移位、右移位左移位、右移位左向右左向右左向右左向右双目双目双目双目6 6 = =小于、大于、小于等于、大小于、大于、小于等于、大小于、大于、小于等于、大小于、大于、小于等于、大于等于于等于于等于于等于左向右左向右左向右左向右双目双目双目双目7 7= != !=等于、不等于等于、不等于等于、不等于等于、不等于左向右左向右左向右左向右双目双目双目双目8 8&按位与按位与按位与按位与左向右左向右左向右左向右双目双目双目双目9 9按位异或按位异或按位异或按位异或左向右左向右左向右左向右双目双目双目双目1010| |按位或按位或按位或按位或左向右左向右左向右左向右双目双目双目双目1111&逻辑与逻辑与逻辑与逻辑与左向右左向右左向右左向右双目双目双目双目1212|逻辑或逻辑或逻辑或逻辑或左向右左向右左向右左向右双目双目双目双目1313? :? :条件运算条件运算条件运算条件运算右向左右向左右向左右向左三目三目三目三目1414= *= /= %= = *= /= %= += -=+= -= = &= |= =&= |= =赋值运算赋值运算赋值运算赋值运算右向左右向左右向左右向左双目双目双目双目1515, ,逗号运算逗号运算逗号运算逗号运算左向右左向右左向右左向右双目双目双目双目3.1.1 算术运算符 + 、- (正号、负号,单目运算)(正号、负号,单目运算) + 、 - 、 *、 / 、 %(双目运算)(双目运算) +、-、*、/ 按通常的算术规定。按通常的算术规定。注意:注意:对于除,若两个操作数都是整数,结果为整数(商部分)。对于除,若两个操作数都是整数,结果为整数(商部分)。1/2=0 5/2=2 %通常称为取模运算,两个操作数必须都是整型数,结果为余通常称为取模运算,两个操作数必须都是整型数,结果为余数,数,余数的符号与左边数的符号等同。余数的符号与左边数的符号等同。3%2=1 -3%2=-1 3%-2=1 -3%-2=-1 8%4=0 在算术运算中需要注意溢出问题。在算术运算中需要注意溢出问题。n两个整数做加法、减法或乘法运算时,即两个整数做加法、减法或乘法运算时,即便结果溢出也不是错误。便结果溢出也不是错误。 例如:例如:short s1 = 32765; s1 = s1 + 3;/结果是否结果是否超过超过short的最大值?的最大值? couts1endl;/ 输出输出-32768,而不是,而不是32768。实际上,。实际上,观察二进制数据,这两个值是一样的。观察二进制数据,这两个值是一样的。3.1.2 关系运算关系运算 、=、= =、!= = = 与与 = :注意:注意:a=5 赋值运算;赋值运算;a= =5;判断是否相等判断是否相等 a=x2 0ab+c 0a=2 1aA b=a+1c-a=aa=a 0aa 0b=a=2 1n n关系运算符的优先级为关系运算符的优先级为( (括弧中运算符的优先级相括弧中运算符的优先级相同同) ):(、=、=) b = c; / d = a b = c; /等价于等价于d = (a b) d = (a b) = c); d= c); d的值为的值为0 0 d = a = b c; / d = a = b c; /等价于等价于d = (a =( b d = (a =( b b b b) d = (a b) = c); d 5; b = a 5;n n由于浮点数在计算机内进行运算和存储时会产生误差,因此在比较两由于浮点数在计算机内进行运算和存储时会产生误差,因此在比较两个浮点数时,建议不要直接比较两数是否相等。例如,执行下面语句:个浮点数时,建议不要直接比较两数是否相等。例如,执行下面语句: double d1 = 3.3333, d2 = 4.4444; double d1 = 3.3333, d2 = 4.4444;if(d1 + d2 = 7.7777)if(d1 + d2 = 7.7777)coutcout相等相等endlendl; ;elseelsecoutcout不等不等endlendl; ;coutcoutd1 + d2d1 + d2endlendl; ; n n条件语句中用条件语句中用“ “=”=”来判断浮点数是否相等,结来判断浮点数是否相等,结果是不等,但果是不等,但d1+d2d1+d2输出结果却是输出结果却是7.77777.7777。两。两个实型数即便输出结果完全一样,其内部值也可个实型数即便输出结果完全一样,其内部值也可能不一样。判断两个实数是否相等的正确方法是:能不一样。判断两个实数是否相等的正确方法是:判断两个实数之差的绝对值是否小于一个给定的判断两个实数之差的绝对值是否小于一个给定的允许误差数,如判断允许误差数,如判断d1d1是否等于是否等于d2d2时,应改为:时,应改为: fabs(d1 - d2) = 1e-6 fabs(d1 - d2) = 1e-6 其中,其中,fabsfabs()()是计算绝对值的一个库函数,使用是计算绝对值的一个库函数,使用时要包含头文件时要包含头文件math.hmath.h。 3.1.3 3.1.3 逻辑运算符逻辑运算符n n对逻辑值进行运算的运算符就是逻辑运算符。对逻辑值进行运算的运算符就是逻辑运算符。C+C+语言语言提供了提供了3 3个逻辑运算符,用于表示操作数之间的逻辑关系,个逻辑运算符,用于表示操作数之间的逻辑关系,它们是它们是!(!(逻辑非逻辑非) )、&(&(逻辑与逻辑与) )、|(|(逻辑或逻辑或) )。逻辑运算。逻辑运算的结果仍然是逻辑值。的结果仍然是逻辑值。n n逻辑非逻辑非(!)(!)是单目运算符,它对操作数进行取反运算。当操是单目运算符,它对操作数进行取反运算。当操作数为非作数为非0(0(逻辑真逻辑真) )时,!运算后结果为时,!运算后结果为0(0(逻辑假逻辑假) )。反之,。反之,若操作数为若操作数为0(0(逻辑假逻辑假) ),! !运算后结果为运算后结果为1(1(逻辑真逻辑真) )。n n注意,所有非注意,所有非0 0的值在逻辑上都作为的值在逻辑上都作为“ “真真” ”。例如:。例如: coutcout!4 !4 endlendl; ;/输出输出0 0,假,假 coutcout!-4 !-4 endlendl; ;/输出输出0 0,假,假 coutcout!4.1!4.1endlendl; ;/输出输出0 0,假,假 coutcout!-4.1!-4.1 6) !(2 6) /结果为结果为1 1,真,真 7 3 & 10 6 7 3 & 10 6/结果为结果为1 1,真,真 5 2 | 4 8 5 2 | 4 8/结果为结果为1 1,真,真 4 & 5 6 4 & 5 6/结果为结果为1 1,真,真n n逻辑运算符的运算优先级为:逻辑运算符的运算优先级为:! ! 高于高于 & & 高于高于|。注意,!的优先级具有较高优先级,甚至高于算注意,!的优先级具有较高优先级,甚至高于算术运算符。而术运算符。而&和和|的优先级则比算术运算符和的优先级则比算术运算符和关系运算符低。关系运算符低。n n因因C+C+将逻辑值保存为整数值,这样使得逻辑值将逻辑值保存为整数值,这样使得逻辑值可参与所有的运算,而且逻辑运算符可作用于所可参与所有的运算,而且逻辑运算符可作用于所有类型的值,而没有语法错误提示。这是有类型的值,而没有语法错误提示。这是C/C+C/C+语法不严密之处。读者应注意避免。语法不严密之处。读者应注意避免。 例例3.1 3.1 逻辑运算符的例子。逻辑运算符的例子。include include /A /A 注意,不是注意,不是iostream.hiostream.husing namespace std;using namespace std;/B /B 导入命名空间导入命名空间stdstdvoid main(void)void main(void) intint a, b; a, b; boolbool res1, res2, res3, res4, res5; res1, res2, res3, res4, res5;a = 3; b = 5;a = 3; b = 5;res1 = a 3 & b = 5;res1 = a 3 & b = 5;res2 = a 3 | b = 5;res2 = a 3 | b = 5;res3 = ! (b = 5);res3 = ! (b = 5);res4 = ! (a = b);res4 = ! (a = b);res5 = a b & b b & b 6;cout boolalpha;cout boolalpha;/C /C cout res1= res1 t;cout res1= res1 t;cout res2= res2 t;cout res2= res2 t;cout res3= res3 t;cout res3= res3 t;cout res4= res4 t;cout res4= res4 t;cout res5= res5 endl;cout res5= res5 endl; 3.1.4 位运算符n n位运算是指对字节内部的二进制位进行移位或逻辑运算。n n位运算是通过位运算符来完成的。n n位运算的操作数必须是char、short、或int值,而且结果也是char、short或int值。n n除了按位求反是单目运算符,其余位运算都是双目运算符。n nC+提供了两类位运算:移位运算和按位逻辑运算。 1. 1. 移位运算符移位运算符n n移位运算符的格式为:移位运算符的格式为: operand n operand n operand n 将操作数将操作数operandoperand向右移动向右移动n n个二进制位,保持符个二进制位,保持符号不变。号不变。n n其中,其中,n n为整数。注意移位运算并不改变为整数。注意移位运算并不改变operandoperand本身的值。例如:本身的值。例如: short operand = 0x8, n = 3; short operand = 0x8, n = 3; short a = operand n; short a = operand n;/结果为结果为0x400x40n n操作数左移操作数左移n n个二进制位后,右边移出的空位用个二进制位后,右边移出的空位用0 0补齐。补齐。n n当左移时,对于带符号数,最高位表示符号,可能会因为低位的当左移时,对于带符号数,最高位表示符号,可能会因为低位的1 1或或0 0移到最高位,最终改变操作数的符号。如:移到最高位,最终改变操作数的符号。如: short s = 4567; short s = 4567; short result = s 3; short result = s 3; coutcout result ; / result ; /输出:输出:-29000-29000n n如果操作数是正数,而且左移没有导致改变符号,那么左移如果操作数是正数,而且左移没有导致改变符号,那么左移n n位,相位,相当于乘以当于乘以2n2n。n n我们知道,我们知道,intint型的数值范围是型的数值范围是-2-23131到到2 23131-1-1。下面代码利。下面代码利用左移位来得到用左移位来得到intint型的最小值和最大值。型的最小值和最大值。int min = 1 31;int min = 1 31;coutmin = minendl;coutmin = minendl;int max = (1 31) - 1;int max = (1 31) - 1;coutmax = maxendl;coutmax = max m;short b = operand m;结果为结果为0xf4b60xf4b6,即,即-2890-2890n n对于移位运算,注意以下几点:对于移位运算,注意以下几点:(1)(1)不要尝试对不要尝试对floatfloat或或doubledouble数据进行移位运算,编译会出数据进行移位运算,编译会出错。错。(2)(2)移动位数移动位数n n应不大于左操作数的位数,如应不大于左操作数的位数,如intint移位应不大移位应不大于于3232。如果。如果n n大于左操作数位数,实际移动位数要自动按大于左操作数位数,实际移动位数要自动按字长取模:字长取模:n%(sizeof(intn%(sizeof(int)。例如,。例如,i33i33就是就是i i左移左移1 1位。位。(3)(3)当移动位数当移动位数n n为负值,为负值,C C语言规范没有确定是什么结果。语言规范没有确定是什么结果。在在VC6VC6中,左移中,左移负值位数,结果总为负值位数,结果总为0 0。(4)(4)左移位左移位与与coutcout与与cincin可可能混淆,可用括号消除这些错误,例如能混淆,可用括号消除这些错误,例如coutcout(k3)(k3)。 n n按位逻辑运算符 按位逻辑运算有4个:求反、与&、或|、异或。n n(1)按位求反“”运算符是一个单目运算符,对操作数逐位取反,得到反码。若二进制位为0,则取反后为1;若二进制位为1,则取反后为0。例如: short int m = 0xc3 /结果为0xff3c 运算符具有比较高的优先级,高于一般的算术运算符。而其它按位逻辑运算符的优先级则比较低。(2)(2)按位逻辑与按位逻辑与“ “&”&”对两个操作数逐位进行运算。对两个操作数逐位进行运算。若对应位都为若对应位都为1 1,则该位结果为,则该位结果为1 1,否则为,否则为0 0。例。例如:如:0xc300000000110000110x6e00000000010xc300000000110000110x6e0000000001101110a0000000001000010101110a0000000001000010short short intint a=0xc3 & 0x6e a=0xc3 & 0x6e /结果为结果为0x420x42(3)(3)按位逻辑或按位逻辑或“ “|”|”对两个操作数逐位进行运算。对两个操作数逐位进行运算。若对应位都为若对应位都为0 0,则该位结果为,则该位结果为0 0,否则为,否则为1 1。例。例如:如: short short intint b = 0x12 | 0x3d b = 0x12 | 0x3d/结果为结果为0x3f0x3fn n(4)(4)按位逻辑异或按位逻辑异或“ “”也是对两个操作数逐位进也是对两个操作数逐位进行运算。异或运算的规则是,若对应位不同,则行运算。异或运算的规则是,若对应位不同,则该位结果为该位结果为1 1,否则为,否则为0 0。例如:。例如: short short intint c = 0x5a 0x26 c = 0x5a 0x26/结果为结果为0x7c0x7c 按位逻辑异或有一个特点,如果按位逻辑异或有一个特点,如果a b = ca b = c,那么,那么c b = ac b = a。b b将将a a转换为转换为c c,也能将,也能将c c再复原为再复原为a a。 显然,两个相等的值异或运算,结果为显然,两个相等的值异或运算,结果为0 0。不相。不相等的两个值异或运算结果不为等的两个值异或运算结果不为0 0。3.1.5 3.1.5 条件运算符条件运算符n nC+C+中唯一的三目运算符就是条件运算符,由两个符号中唯一的三目运算符就是条件运算符,由两个符号“ “?”?”和和“ “:”:”组成,要求有组成,要求有3 3个操作数,形式如下:个操作数,形式如下: ?:3 根据根据1为真或假,选择为真或假,选择2或或3作为运算作为运算结果。结果。(1) (1) 条件表达式的执行顺序为:先求解表达式条件表达式的执行顺序为:先求解表达式1 1,若值为非,若值为非0 0,表示条件,表示条件为真,则求解表达式为真,则求解表达式2 2,此时表达式,此时表达式2 2的值就作为整个条件表达式的结的值就作为整个条件表达式的结果;若表达式果;若表达式1 1的值为的值为0 0,表示条件为假,则求解表达式,表示条件为假,则求解表达式3 3,表达式,表达式3 3的值就是整个条件表达式的值。例如:的值就是整个条件表达式的值。例如: a b ? a : b a b ? a : b 结果是结果是a a和和b b的较大值。的较大值。(2)(2)通常情况下,表达式通常情况下,表达式1 1应该是一个关系表达式或逻辑表达式,表达式应该是一个关系表达式或逻辑表达式,表达式2 2和表达式和表达式3 3可以是常量、变量或表达式,而且应该是相同类型。例如可以是常量、变量或表达式,而且应该是相同类型。例如: x = y ? Y : N x = y ? Y : N (d = b*b-4*a*c) = 0 ? sqrt(d) : sqrt(-d) (d = b*b-4*a*c) = 0 ? sqrt(d) : sqrt(-d) /sqrt/sqrt是开平是开平方函数方函数 ch = ch = A & ch = A & ch = Z ? ch+a-A: ch; /大写字母转大写字母转小写小写(3) (3) 条件表达式的优先级比较低,仅高于赋值和逗号运算符。条件表达式的优先级比较低,仅高于赋值和逗号运算符。 (4) (4) 虽然虽然C+C+规范文档说明条件运算符的结合性为规范文档说明条件运算符的结合性为“ “从右向左从右向左” ”,但实,但实际上并非如此。际上并非如此。 #include #include void main(void)void main(void) intint i = 1, j = 2, k = 3; i = 1, j = 2, k = 3;coutcout The larger value of : / The larger value of : /求出求出i i和和j j中的最中的最大值大值 i and j is i and j is j ? i : j) j ? i : j) = j ? i : j) = j ? i : j); max = (i = j ? i : j) = j ? i : j); /A/Acoutcout The largest value of : / The largest value of : /求出求出i,ji,j和和k k中的最大值中的最大值 i , j and k i , j and k is max is max endlendl; ; 3.1.6 3.1.6 赋值运算符赋值运算符 赋值运算就是将一个表达式的值赋给一个变量。赋值运算就是将一个表达式的值赋给一个变量。 C+ C+语言提供了两类赋值运算符:基本赋值运算符和复合语言提供了两类赋值运算符:基本赋值运算符和复合赋值运算符。赋值运算符。 基本赋值运算符为基本赋值运算符为“ “=”=”,复合赋值运算符有多种形式:,复合赋值运算符有多种形式:+=+=、-=-=、* *=、/=/=、%=%=、=、&=&=、=、|=|=。 (1) (1) 赋值运算符都是双目运算符,从右向左进行。例如,赋值运算符都是双目运算符,从右向左进行。例如,sum1=sum2=0sum1=sum2=0相当于相当于sum1=(sum2=0)sum1=(sum2=0),先执行,先执行sum2=0sum2=0,后执行,后执行sum1=sum2sum1=sum2。(2) (2) 要求赋值运算符左操作数必须是左值,左值能存储值。要求赋值运算符左操作数必须是左值,左值能存储值。 例如:例如: x = 3 + 5 x = 3 + 5/正确,正确,x x是左值是左值 x - 3 = 5 x - 3 = 5/语法错误,语法错误,x-3x-3不是左值不是左值(3) (3) 复合赋值运算符是将算术运算或位运算与赋值复合赋值运算符是将算术运算或位运算与赋值相结合,同一个变量即参加运算,也是被赋值的相结合,同一个变量即参加运算,也是被赋值的变量,出现在赋值运算符的两边。复合赋值运算变量,出现在赋值运算符的两边。复合赋值运算符是一个整体,中间不能用空格隔开。例如:符是一个整体,中间不能用空格隔开。例如: a *= 6 a *= 6/相当于相当于a = a*6a = a*6 a %= 6 a %= 6/相当于相当于a = a%6a = a%6 a += 3 + 6 a += 3 + 6 /相当于相当于a = a+(3+6)a = a+(3+6)n n 初学者容易犯的一个错误就是混淆初学者容易犯的一个错误就是混淆“ “=”=”运算符运算符和和“ “=”=”运算符。分析下面代码:运算符。分析下面代码: intint a = 5, b = 3; a = 5, b = 3; intint d = a = b; d = a = b; /d/d的值为的值为0 03.1.7 3.1.7 逗号运算符逗号运算符逗号逗号“ “,” ,”既是标点符号既是标点符号( (用做分隔符用做分隔符) ),又是运算符。逗号运,又是运算符。逗号运算符用来将两个表达式连接起来,逗号表达式的一般表达算符用来将两个表达式连接起来,逗号表达式的一般表达形式为:形式为:,n逗号运算符是双目运算符,取其右边操作数的值作为整个表逗号运算符是双目运算符,取其右边操作数的值作为整个表逗号运算符是双目运算符,取其右边操作数的值作为整个表逗号运算符是双目运算符,取其右边操作数的值作为整个表达式的结果。逗号运算符的优先级最低。例如:达式的结果。逗号运算符的优先级最低。例如:达式的结果。逗号运算符的优先级最低。例如:达式的结果。逗号运算符的优先级最低。例如:intint i,j,ki,j,k; ;/作标点符号用作标点符号用funx(x,y,zfunx(x,y,z););/作标点符号用作标点符号用a+ba+b, , a+ca+c /逗号运算符逗号运算符1+4, 3.4+10, 3&4 1+4, 3.4+10, 3&4 /逗号运算符逗号运算符x = 3+6, x*3, x+6x = 3+6, x*3, x+6/第一个逗号运算结果为第一个逗号运算结果为2727,第二个逗号运算结果为,第二个逗号运算结果为1515x = (y=3, y+1) x = (y=3, y+1) /y/y的值为的值为3 3,x x的值为的值为4 4例例3-33-3逗号运算符的使用。逗号运算符的使用。#include #include void main(void)void main(void) int a=3, b=7, c=4, t, x; int a=3, b=7, c=4, t, x;t = (a+=1, b-=2, c+3);t = (a+=1, b-=2, c+3);x=3+6,x*3,x+6;x=3+6,x*3,x+6;cout a= a t;cout a= a t;cout b= t t;cout b= t t;cout c= c t;cout c= c t;cout t= t endl;cout t= t endl;cout x= x endl;cout x= x endl; x=(x=3+6,x*3),x+6; x=(x=3+6,x*3),x+6;cout x= x endl;cout x= x endl;x=(x=3+6,x*3,x+6);x=(x=3+6,x*3,x+6);cout x= x endl;cout x= x endl;x=(x=3+6,x=x*3,x+6);x=(x=3+6,x=x*3,x+6);cout x= x endl;cout x= x endl; 3.1.8 3.1.8 自增、自减运算符自增、自减运算符n n自增、自减运算就是对一个变量加自增、自减运算就是对一个变量加1 1或减或减1 1。自增。自增用用“ “+”+”运算符,而自减用运算符,而自减用“ “-”-”运算符,它们都运算符,它们都是单目运算符。运算符是单目运算符。运算符“ “+”+”和和“ “-”-”是一个整体,是一个整体,中间不能用空格隔开。中间不能用空格隔开。n n自增自增( (或自减或自减) )运算符要区分前缀和后缀两种形式。运算符要区分前缀和后缀两种形式。n n前缀形式,运算符放在操作数左边,例如前缀形式,运算符放在操作数左边,例如+count+count。先使操作数自增。先使操作数自增( (自减自减)1)1个单位后,个单位后,然后取其值作为运算结果。然后取其值作为运算结果。n n后缀形式,运算符放在操作数右边,例如后缀形式,运算符放在操作数右边,例如count+count+,先取操作数的值参与当前表达式的运,先取操作数的值参与当前表达式的运算,然后再使操作数自增算,然后再使操作数自增( (自减自减)1)1个单位。个单位。例如:例如:intint count = 15, digit = 16, number, amount; count = 15, digit = 16, number, amount;number = +count;number = +count;/ count/ count和和numbernumber都为都为1616amount = digit+;amount = digit+;/ amount/ amount的值为的值为1616,digitdigit的的值为值为1717n n自增、自减运算符要求操作数必须是左值,往往是一个变自增、自减运算符要求操作数必须是左值,往往是一个变量。前缀式的计算结果是操作数修改后的值,因此结果仍量。前缀式的计算结果是操作数修改后的值,因此结果仍然是一个左值;而后缀式的值是原先操作数的值,所以它然是一个左值;而后缀式的值是原先操作数的值,所以它不是左值。如:不是左值。如: intint amt=63, nut=96; amt=63, nut=96; + +amt; + +amt;/相当于相当于+(+amt)+(+amt),结果为,结果为6565 +nut-; +nut-; /相当于相当于+(nut-)+(nut-),nut-nut-不是左值,所以不是左值,所以语法错误语法错误 (+nut)-; (+nut)-;/+nut/+nut是左值,所以语法正确是左值,所以语法正确n n 自增、自减运算符具有较高的优先级,高于所有的算术自增、自减运算符具有较高的优先级,高于所有的算术运算符。运算符。例例3-43-4自增、自减运算符的使用。自增、自减运算符的使用。#include #include void main(void)void main(void)intint a = 2, b = 3; a = 2, b = 3;intint c, d, e; c, d, e;c = +a + b- ;c = +a + b- ;/c = 3 + 3/c = 3 + 3coutcouta=atb=btc=ca=atb=btc=cendendl l; ;d = + +a + +b;d = + +a + +b;/d = 5 + 3/d = 5 + 3coutcouta=atb=btd=da=atb=btd=denendldl; ;e = a+ - - -b;e = a+ - - -b;/e = 5 - 1/e = 5 - 1coutcouta=atb=bte=ea=atb=bte=eenendldl; ; 程序运行后,在屏幕上输出的结果为:程序运行后,在屏幕上输出的结果为:a=3 b=2 c=6a=3 b=2 c=6a=5 b=3 d=8a=5 b=3 d=8a=6 b=1 e=4a=6 b=1 e=4n n在上面这些运算符中,只有赋值运算符和自增自减运算符在上面这些运算符中,只有赋值运算符和自增自减运算符可以更改左值,常称为副作用可以更改左值,常称为副作用(side effect)(side effect)。应避免在同。应避免在同一个表达式中对同一个变量进行多次自增自减运算,否则一个表达式中对同一个变量进行多次自增自减运算,否则结果难以合理解释。例如:结果难以合理解释。例如: intint a = 2; a = 2; intint b = +a + +a; b = +a + +a; 最后最后b b的值为的值为8 8,a a为为4 4。实际上。实际上b = 4 + 4b = 4 + 4,而不是,而不是b = b = 3 + 43 + 4。n n再如再如: a = 2; int c = a+ + +a; a = 2; int c = a+ + +a; 最后最后c c的值为的值为6 6,a a为为4 4。实际上。实际上c = 3 + 3c = 3 + 3,而不是,而不是c = 2 c = 2 + 3+ 3。一个比较合理的解释是这里的。一个比较合理的解释是这里的+运算是从右向左计运算是从右向左计算的算的( (但这违背但这违背+的结合性,从左向右的结合性,从左向右) ),真正执行的是:,真正执行的是: intint c = +a + a+; c = +a + a+;n n注意,尽管后缀自增自减运算符具有比较高的优先级,也注意,尽管后缀自增自减运算符具有比较高的优先级,也不能先计算。例如:不能先计算。例如:intint a = 2; a = 2;intint b = 3 + (a+) b = 3 + (a+);/等同于等同于 b = 3 + a+b = 3 + a+ 此时变量此时变量b b的值是的值是3+23+2,而不是,而不是3+33+3。3.1.9 3.1.9 sizeofsizeof运算符运算符n n每种类型的变量都占用一定大小的存储单元。存每种类型的变量都占用一定大小的存储单元。存储单元的大小与变量类型、储单元的大小与变量类型、CPUCPU及操作系统有关。及操作系统有关。n nsizeofsizeof运算符用于测试某种数据类型或表达式的运算符用于测试某种数据类型或表达式的类型在内存中所占的字节数,它是一个一元运算类型在内存中所占的字节数,它是一个一元运算符。其语法格式为:符。其语法格式为: sizeofsizeof() ) 或或 sizeofsizeof()n n例如:例如: sizeofsizeof ( (intint) )/整数类型占整数类型占4 4个字节,结果为个字节,结果为4 4 sizeofsizeof (3+3.6) /3+3.6 (3+3.6) /3+3.6的结果为的结果为doubledouble实数,实数,结果为结果为8 83.1.10 3.1.10 typeidtypeid运算符运算符n n对于任何一个表达式,应该知道它的类型究竟是对于任何一个表达式,应该知道它的类型究竟是什么。例如:什么。例如: intint i = -2; i = -2; unsigned j = 3; unsigned j = 3; coutcouti*ji*jendlendl; ;/输出输出42949672904294967290n n表达式表达式i*ji*j的类型是什么?的类型是什么?C+C+提供了提供了typeidtypeid运算运算符符( (称为类型标识称为类型标识type identity)type identity),能获取一个表,能获取一个表达式在运行时刻的类型信息。该运算符要求包含达式在运行时刻的类型信息。该运算符要求包含一个文件一个文件,还要再调用一个函数,还要再调用一个函数namename()()。例3-6 typeid运算符的例子。#include #include void main()int i = -2;unsigned j = 3;couti*jendl;couttypeid(i*j).name() 0) 0) y = x;y = x;/如果如果x x大于大于0 0,y y取取x x的值的值 else y = -x; else y = -x;/如果如果x x不大于不大于0 0,y y取取-x-x的值,的值,最后最后y y是是x x的绝对值的绝对值n n注意,注意,“ “=”=”和和“ “=”=”含义完全不同,注意不要误写。含义完全不同,注意不要误写。试试比较下面两个程序段:比较下面两个程序段: if(x=168) if(x=168) /判断判断x x是否等于是否等于168168,条件可能,条件可能成立,也可能不成立成立,也可能不成立 if(x=168) if(x=168) /将值将值168168赋给赋给x x,计算结果为逻,计算结果为逻辑辑1 1,条件永远成立,条件永远成立3.2.5 3.2.5 逻辑表达式逻辑表达式n n由逻辑运算符和操作数构成的表达式称为逻辑表由逻辑运算符和操作数构成的表达式称为逻辑表达式。逻辑表达式的运算结果为逻辑值,一般用达式。逻辑表达式的运算结果为逻辑值,一般用来构造比较复杂的条件表达式。来构造比较复杂的条件表达式。n n逻辑表达式中往往包含多个关系表达式,要先计逻辑表达式中往往包含多个关系表达式,要先计算关系表达式的值,再计算逻辑表达式。算关系表达式的值,再计算逻辑表达式。但逻辑但逻辑与与(&)(&)和逻辑或和逻辑或(|)(|)运算符在运算时,从左向右运算符在运算时,从左向右计算,根据规则一旦能确定整个表达式的值时,计算,根据规则一旦能确定整个表达式的值时,就结束计算,后面的表达式就不再计算。就结束计算,后面的表达式就不再计算。(1) (1) 对于对于 & & 2逻辑表达式,逻辑表达式,先计算先计算1的值,若其值为逻辑真的值,若其值为逻辑真( (非非0)0),就再计算,就再计算2的的值,若其值为非值,若其值为非0 0,则结果为,则结果为1 1,否则为,否则为0 0。若若1的值为逻辑假的值为逻辑假( (值为值为0)0),就已经知道整个表达式为假,就,就已经知道整个表达式为假,就不再计算不再计算2的值,结束整个表达式的计算。的值,结束整个表达式的计算。 例如:例如: year % 4 = 0 & year % 100 != 0 year % 4 = 0 & year % 100 != 0 用用&来连接两个条件,前一个条件满足是后一个条件计算的前提。来连接两个条件,前一个条件满足是后一个条件计算的前提。(2) (2) 对于对于 | | 2逻辑表达式,逻辑表达式, 先计算先计算1的值,若其值为假,再计算的值,若其值为假,再计算2的值,并将的值,并将2的值作为整个表达式的值。的值作为整个表达式的值。 若若1的值为真,就已经知道整个表达式的值为真,就结束整的值为真,就已经知道整个表达式的值为真,就结束整个表达式计算。个表达式计算。 例如:例如: year % 400 = 0 | year % 4 = 0 & year % 100 != 0 year % 400 = 0 | year % 4 = 0 & year % 100 != 03.2.6 3.2.6 逗号表达式逗号表达式 由逗号运算符和操作数组成的表达式称为逗号表达式,就由逗号运算符和操作数组成的表达式称为逗号表达式,就是用逗号将多个表达式分隔起来,是用逗号将多个表达式分隔起来,从左向右逐个计算各个从左向右逐个计算各个表达式,并将最右边的表达式作为逗号表达式的值表达式,并将最右边的表达式作为逗号表达式的值。例如:。例如:intint p,w,x=8,y=10,z=12; p,w,x=8,y=10,z=12;w = (x+, y, z+3)-5;w = (x+, y, z+3)-5;/w/w的值为的值为(z+3)-5, (z+3)-5, 即即1010p = x+5, p = x+5, y+xy+x, z;, z;/p/p的值为的值为x+5x+5,即,即1515,z z的值的值1212作为逗号表达式的值作为逗号表达式的值如果逗号运算符的右操作数是一个左值,该逗号运算的结果如果逗号运算符的右操作数是一个左值,该逗号运算的结果也是左值。例如:也是左值。例如:(y+, z) = 2 (y+, z) = 2 /z/z是左值,是左值,(y+, z)(y+, z)的结果也是左值,的结果也是左值,z z的值被改为的值被改为2 23.2.7 3.2.7 表达式语句表达式语句 任何一个表达式后加上一个分号任何一个表达式后加上一个分号“ “;”;”就构成一条就构成一条表达式语句。表达式语句的一般格式为:表达式语句。表达式语句的一般格式为: ;n n注意,分号是构成语句的组成部分,而不是作为注意,分号是构成语句的组成部分,而不是作为语句之间的分隔符。例如语句之间的分隔符。例如: x = 20; x = 20; 3 * 8 - 9; 3 * 8 - 9; y = a + b * c; y = a + b * c; i = 0, j = 0; i = 0, j = 0; i+; i+;n n这些都是合法的表达式语句,第二个表达式语句这些都是合法的表达式语句,第二个表达式语句只做了算术运算,并没有保存结果,即没有副作只做了算术运算,并没有保存结果,即没有副作用,在程序中应消除这些没用的表达式语句。用,在程序中应消除这些没用的表达式语句。3.3 类型转换n n每个运算符的操作数的个数及类型都有特定限制。在一个表达式中,运算符的某个操作数如果不符合类型要求,就要对操作数进行类型转换。C+中的类型转换有3种:自动类型转换、赋值转换和强制类型转换。n n3.4.1 3.4.1 自动类型转换自动类型转换 自动类型转换自动类型转换( (也称隐式类型转换也称隐式类型转换) )指系统自动地指系统自动地将表达式中的操作数转换成所需类型的值,转换将表达式中的操作数转换成所需类型的值,转换顺序为由范围较小的类型向范围较大的类型转换。顺序为由范围较小的类型向范围较大的类型转换。n n规则规则规则规则1 1。两个不同类型的操作数进行运算时,先。两个不同类型的操作数进行运算时,先将较小范围的数值转换为另一个较大范围的数值,将较小范围的数值转换为另一个较大范围的数值,然后再进行计算。各种基本数据类型的数值范围然后再进行计算。各种基本数据类型的数值范围从小到大排列次序如下:从小到大排列次序如下: char, char, boolbool short short intint float float double double unsigned char unsigned char unsigned short unsigned short unsigned unsigned intint float float double doublen n例如定义两个变量例如定义两个变量a a和和f f:intint a = 100; float f = 32.2f; a = 100; float f = 32.2f; 则计算以下表达式:则计算以下表达式:a / fa / f 处理过程为:先将处理过程为:先将a a的值转换成的值转换成floatfloat型,然后再进行浮点数的除法运型,然后再进行浮点数的除法运算,结果为一个算,结果为一个floatfloat值值3.105593.10559。在这个过程中。在这个过程中a a变量的值不改变。变量的值不改变。 分析下面两行输出结果是否一样。分析下面两行输出结果是否一样。short s1 = 32765; short s1 = 32765; coutcouts1 + 3s1 + 3endlendl; ;s1 = s1 + 3;s1 = s1 + 3;/A/Acoutcouts1s1endlendl; ;n n 按规则按规则1 1可知,两个有符号的值之间进行算术运算,其结果是有符可知,两个有符号的值之间进行算术运算,其结果是有符号的。一个无符号的值与一个浮点数号的。一个无符号的值与一个浮点数( (如如float)float)进行算术运算,其结果是进行算术运算,其结果是浮点数浮点数( (如如float)float)。但两个无符号的值之间进行算术运算。但两个无符号的值之间进行算术运算( (两个值中没有两个值中没有unsigned unsigned intint) ),其结果是有符号的,其结果是有符号的intint。例如:例如:unsigned char c1 = 2; unsigned short s1 = 3;unsigned char c1 = 2; unsigned short s1 = 3;coutcout(c1 * s1)(c1 * s1)endlendl; ;/乘法,输出乘法,输出6 6coutcouttypeid(c1 * s1).name()typeid(c1 * s1).name()endlendl; ;/输出输出intintn n规则规则规则规则2 2 对于对于boolbool、charchar、shortshort、intint类型,任意两个值类型,任意两个值之间进行算术运算、位运算,其结果都是一个之间进行算术运算、位运算,其结果都是一个intint值。任值。任意两个值之间进行逻辑运算,其结果都是一个意两个值之间进行逻辑运算,其结果都是一个boolbool值。注值。注意规则意规则2 2是规则是规则1 1的一个例外。的一个例外。例如:例如:char c1 = -2;char c1 = -2;short s1 = 3;short s1 = 3;coutcout(c1 * s1)(c1 * s1)endlendl; ;/乘法,输出乘法,输出-6-6coutcouttypeid(c1 * s1).name()typeid(c1 * s1).name()endlendl; ;/输出输出intintcoutcout(c1 & s1)(c1 & s1)endlendl; ;/按位与,输出按位与,输出2 2coutcouttypeid(c1 & s1).name()typeid(c1 & s1).name()endlendl; ;/输出输出intintcoutcout(c1 & s1)(c1 & s1)endlendl; ; / /逻辑与,输出逻辑与,输出1 1,表示,表示truetruecoutcouttypeid(c1 & s1).name()typeid(c1 & s1).name()endlendl; ;/输出输出boolbooln n规则规则规则规则3 3。对于。对于boolbool、charchar、shortshort、intint类型,任一个类型值类型,任一个类型值( (无论是否无论是否带符号带符号) )与与unsigned unsigned intint之间进行算术运算,其结果都是之间进行算术运算,其结果都是unsigned unsigned intint类型。注意规则类型。注意规则3 3又是规则又是规则2 2的一个例外。的一个例外。例如:例如:char c1 = -2;char c1 = -2;unsigned short s1 = 2;unsigned short s1 = 2;unsigned unsigned intint j = 3; j = 3;coutcout(c1 * j)(c1 * j)endlendl; /; /乘法,输出乘法,输出42949672904294967290,而不是,而不是-6-6coutcouttypeid(c1 * j).name()typeid(c1 * j).name()endlendl; /; /输出输出unsigned unsigned intintcoutcout(s1 * j)(s1 * j)endlendl; ; / /乘法,输出乘法,输出6 6coutcouttypeid(s1 * j).name()typeid(s1 * j).name()endlendl; /; /输出输出unsigned unsigned intintn n由上面例子可知,由上面例子可知,unsigned unsigned intint被系统认为是整型数值中的最大范围被系统认为是整型数值中的最大范围的类型,因此其它类型与之计算时,都要转换到的类型,因此其它类型与之计算时,都要转换到unsigned unsigned intint。此时。此时如果另一个整数恰好是负值,而结果是不带符号的正值,就不能得到如果另一个整数恰好是负值,而结果是不带符号的正值,就不能得到预期结果,但二进制结果是正确的,例如预期结果,但二进制结果是正确的,例如42949672904294967290与与-6-6是一样是一样的。的。n n在处理表达式的过程中,并不是将变量直接转换成最大范围的类型,在处理表达式的过程中,并不是将变量直接转换成最大范围的类型,而是在表达式处理过程中,按照需要逐步进行转换。例如而是在表达式处理过程中,按照需要逐步进行转换。例如:int i=1; char ch=2;int i=1; char ch=2;float f= 3.0f; double float f= 3.0f; double dfdf = 4.0; = 4.0;coutcout(ch*i+f*2.0-df)(ch*i+f*2.0-df)endlendl; ; 表达式表达式ch*i+f*2.0-dfch*i+f*2.0-df的计算过程为:的计算过程为:(1) (1) 将将chch转换为转换为intint型,计算型,计算chch*i*i,即,即2*12*1,结果为,结果为2 2,类型为,类型为intint。(2) (2) 将将f f转换为转换为doubledouble型,计算型,计算f*2.0f*2.0,即,即3.0*2.03.0*2.0,结果为,结果为6.06.0,类型,类型为为doubledouble。(3) (3) 将将chch*i*i的结果的结果2 2转换为转换为doubledouble型,计算型,计算2.0+6.02.0+6.0,结果为,结果为8.08.0,类型,类型为为doubledouble。(4) (4) 计算计算8.0-df8.0-df,即,即4.04.0,整个表达式的结果为,整个表达式的结果为4.04.0,类型为,类型为doubledouble。自动类型转换的基本规则是自动类型转换的基本规则是“ “宽化宽化” ”或者或者“ “提升提升” ”,即将较小范围的数,即将较小范围的数值类型转换到较大范围的数据类型。大多数自动类型转换是安全的。值类型转换到较大范围的数据类型。大多数自动类型转换是安全的。n n3.4.2 3.4.2 赋值转换赋值转换n n赋值类型转换出现在初始化表达式或者赋值表达式中。当初始化或赋赋值类型转换出现在初始化表达式或者赋值表达式中。当初始化或赋值运算符的左值表达式的类型与右值表达式类型不同,且类型兼容时,值运算符的左值表达式的类型与右值表达式类型不同,且类型兼容时,将进行类型转换到左值类型。即先计算出右值表达式的值,然后将其将进行类型转换到左值类型。即先计算出右值表达式的值,然后将其转换为左值类型后再赋给左值。转换为左值类型后再赋给左值。例如:例如:char char chch = b; = b;short s = short s = chch; ;/char/char转换到转换到shortshortcoutcout s s endlendl; ; /输出:输出:9898intint i = 4000000; i = 4000000;s = i;s = i;/intint转换到转换到shortshortcoutcout s s endlendl; ; /输出:输出:23042304,因为,因为i i的值超出的值超出s s的存储范围,的存储范围,发生截断发生截断float f = i;float f = i;/intint转换到转换到floatfloatcoutcout f f endlendl; ; /输出:输出:4e+0064e+006double d = 23.56;double d = 23.56;i = d;i = d;/double/double转换到转换到intintcoutcout i i endlendl; ; /输出:输出:2323,因为整型变量不能存放小数部分,因为整型变量不能存放小数部分float t = 34;float t = 34;i = t;i = t;/float/float转换到转换到intintcoutcout i i )-较小范围的整数较小范围的整数( (如如short)short),将截断高位,将截断高位字节,仅保留低位字节的值。如果原先数值大于小范围类型可表示的字节,仅保留低位字节的值。如果原先数值大于小范围类型可表示的范围,将将出错。范围,将将出错。较小范围的整数较小范围的整数( (如如charchar或或float)float)较大范围的整数较大范围的整数( (如如intint或或double)double),将保持原值不改变。,将保持原值不改变。n n 一般情况下,编译器对于可能导致数据丢失的情形会给出警告,但不一般情况下,编译器对于可能导致数据丢失的情形会给出警告,但不完全。不经意之间就可能产生意料不到的结果。例如:完全。不经意之间就可能产生意料不到的结果。例如:intint i = 2, j = 4; i = 2, j = 4;double double dfdf; ;dfdf = i/j*100; = i/j*100;/i/j/i/j的值为的值为0 0,而不是,而不是0.50.5coutcout dfdf= = dfdf t; t;/输出输出0 0,而不是,而不是5050i = 4.6, j = 5.7;i = 4.6, j = 5.7;/编译时给出警告编译时给出警告float x = i + j; float x = i + j; /x/x的值并不是的值并不是10.310.3,而是,而是9 = 4 + 59 = 4 + 5coutcout x= x n; x= x n; /输出输出9 93.4.3 3.4.3 强制类型转换强制类型转换n n强制类型转换强制类型转换( (也称显式类型转换也称显式类型转换) )是由程序员用类型转换是由程序员用类型转换运算符明确指明的一种转换操作,将一个表达式强制转换运算符明确指明的一种转换操作,将一个表达式强制转换到某个指定类型。强制类型转换的一般形式为:到某个指定类型。强制类型转换的一般形式为: () 或者或者 ( ()例如:例如: intint a = 7, b = 2; a = 7, b = 2; double y1 = a / b double y1 = a / b 此时此时y1y1的值是的值是3.03.0。但如果程序员希望得到。但如果程序员希望得到3.53.5,就要对,就要对除法的操作数进行强制类型转换如下:除法的操作数进行强制类型转换如下: y1 = double(a)/b y1 = double(a)/b 或者或者 y1 = (double)a/b y1 = (double)a/b 或者或者 y1 = a / double(b);y1 = a / double(b); 关于强制类型转换,说明以下两点。关于强制类型转换,说明以下两点。n n(1)(1)一个强制类型转换是否正确取决于所处理的值的范围,一个强制类型转换是否正确取决于所处理的值的范围,一般来说,强制转换是不安全的。一般来说,强制转换是不安全的。n n(2) (2) 类型强制转换作用于一个表达式,并非作用于数据存类型强制转换作用于一个表达式,并非作用于数据存储单元,即不改变变量存储的类型和值。例如:储单元,即不改变变量存储的类型和值。例如: double width = 2.36, height = 5.5, area1; double width = 2.36, height = 5.5, area1; intint area2 = area2 = int(widthint(width)*)*int(heightint(height);); /area1 /area1值为值为10,width10,width和和heightheight仍为仍为doubledouble型型 area1 = width*height; area1 = width*height;/area2/area2值为值为12.9812.98何时需要进行强制类型转换?何时需要进行强制类型转换? 只有当自动类型转换和赋值转换不能达到目的时,才使用只有当自动类型转换和赋值转换不能达到目的时,才使用强制类型转换。强制类型转换。一般来说,强制类型转换是不安全的,只有在特定条件下一般来说,强制类型转换是不安全的,只有在特定条件下执行才比较安全,所以应谨慎使用。执行才比较安全,所以应谨慎使用。上机注意事项n n1 严禁玩游戏n n2 带鞋套n n3 先把书上的程序输入,然后改动其中的部分内容,观察有何变化,包括故意产生一些输入错误,观察会产生哪些编译错误.n n4 所有文件拷贝到硬盘上操作,不要对U盘上的文件进行编译n n5 刚开始时,不要进行中英文的输入切换n n6 逐渐熟悉VC+的集成环境
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号