




已阅读5页,还剩55页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
新编C语言程序设计教程 清华大学出版社,周二强 软件学院 计算机科学与工程系 配套视频: 博客:/stunt,第3章 操作符与表达式,3.1概述 3.2赋值操作符和赋值表达式 3.2.1 赋值操作符 3.2.2 类型不匹配时的赋值操作 3.2.3 复合赋值操作符 3.3算术操作符和算术表达式 3.3.1 算术表达式的求值 3.3.2 强制类型转换操作符 3.3.3 自增自减操作符,3.4逗号操作符和逗号表达式 3.5值与编译系统相关的表达式 3.6 典型例题分析,操作符,操作符也称运算符,是一种表示对数据进行何种处理的符号,如+,*,&等。 操作符处理的对象(数据)称为操作数。操作数可以是字面量、变量或函数调用等。根据所需操作数的个数,操作符可分类为单目操作符(一个操作数),双目操作符(二个操作数)和三目操作符(三个操作数)。 根据功能,操作符可分为赋值、算术、关系与逻辑、位和地址操作符等几种。,表达式,用操作符把操作数连接起来的,符合C语言语法规则的式子如3+2*5-6 ,称作表达式。C语言丰富的操作符构成了种类繁多的表达式。 C语言表达式最重要的特征是每个表达式都有一个确定的值及(该值的)类型。所谓表达式的值是指按照规定的规则,对表达式进行运算所得到的结果。,求解表达式的值,要求解表达式的值就必须熟悉操作符的运算顺序。表达式中操作符的运算顺序服从于操作符的优先级和结合性规则。3+2*5-6 优先级规则要求表达式求值时,优先级高的操作符先进行运算,类似于熟知的“先乘除后加减”规则。 表达式中两个相邻的操作符具有相同的优先级时,首先运算哪一个操作符的问题由操作符的结合性规则来决定。,结合性,显然优先级相同的操作符的结合性也相同。 若按自左向右的顺序进行运算,则称该优先级的操作符的结合性为左结合;若按自右向左的顺序进行运算,则称该优先级的操作符的结合性为右结合。 +、*、/,C语言表达式举例,其中的字母均为变量。 i + (j m / n) % 5 n 5 & i % 3 = = 0 x = y+ % 2 i j ? n = 2 : n = -2 n = 2 x = 3, y *= 6, 89 + 56,常见的数学运算,C语言表达式中的操作符和操作数必须写在同一行上。对于数学上复杂的表达式如 在改写成单行的表达式时需用到库函数。 常见的数学运算如求绝对值、求平方根、求幂等在C语言中都已用库函数实现,如求绝对值可用fabs函数,求平方根可用sqrt函数,求幂可用pow函数。 有关数学运算的库函数归类在数学库中,在math.h头文件中声明。用include命令把math.h头文件包含到程序中后,就可以方便地使用这些有关数学运算的库函数了。,(fabs(a)+sqrt(b*b-pow(x, y)/5 (fabs(a)+sqrt(b*b-pow(x, y)*0.2,表达式求值和C语句,表达式求值时,不仅需要注意操作符的优先级和结合性,还需注意操作数的数据类型和表达式的序列点。 5/2 5/2.0 在后面加一个分号(;),C语言表达式就变成了C语句,此时计算机执行C语句的过程,就是对表达式“求值”的过程。,return,3.2 赋值操作符和赋值表达式,赋值操作符“=”是双目操作符、右结合,由它构成的赋值表达式的一般形式为:变量=表达式。 赋值表达式的操作是先计算出右边子表达式的值,再把值转换成变量的类型后存入变量所标示的存储空间。如:i = 5 / 2; 由于赋值操作符的优先级较低,可记为:先计算再赋值。,例3-1 分析下面程序的运行,变量i的值并不会消失,赋值语句i = i + 1;执行过程中,会先计算赋值操作符右边子表达式i + 1的值。在求i + 1的值时变量i的值(1)被取到运算器中,然后运算器求出i + 1的值为2。接着,计算结果会由运算器传回到变量i所标识的存储单元中,变量i值变为2。 变量i的值并不会因被“取到”运算器中而消失。计算后,运算器中的和会被赋值给变量i,因此这条语句不矛盾。,变量i的值并不会消失,执行赋值语句j = i;时,变量i所标示的内存空间的存储状态(2的补码)会被传送到变量j所标示的内存空间中,因此变量j的值变为2,变量j原来的值因为存储状态的改变而消失,但是变量i的值仍然为2, 因为变量i所标示的内存空间的存储状态没有改变仍然为2的补码。计算机在执行时只是检测一下(只是检测没有改变)变量i所标示的内存空间的状态(相关导线上的开关是接通还是断开),然后把变量j所标示的内存空间也设置成同样的状态。,赋值表达式合法吗?,赋值操作符左边的操作数只能是变量,如3 = i、i+ = 5和a + b = 23等的赋值表达式都不合法。 赋值表达式i = j = k = 23合法吗? 赋值操作是右结合,故该表达式的操作顺序为i=(j=(k=23)。 子表达式k=23是一个合法的赋值表达式。C语言表达式都有一个值,赋值表达式的值就是该表达式左边的操作数,即变量,也就是说表达式k=23执行完赋值操作后,它的值就是k,此时原表达式变为i=(j = k)。,问题,表达式(a = 3 * 2)= 5 * 7,与表达式a = 3 * 2 = 5 * 7等价吗? = 3 * 2)= 5 * 7执行时,先计算子表达式a = 3 * 2,值为a,故原表达式变为a = 5 * 7。原表达式执行时,变量a先被赋值为6,后又被赋值为35。 表达式a = 3 * 2 = 5 * 7等价于a = (3 * 2 = 5 * 7)即a =(6 = 35)。子表达式6 = 35是不合法的赋值表达式(左操作数非变量),因此表达式a = 3 * 2 = 5 * 7非法。,合法并不代表合理,注意: 表达式(a = 3 * 2)= 5 * 7合法并不代表合理!为什么要写这样的代码呢? 在某些编译系统中赋值表达式的值为变量的值(如23)并非变量(如k),语句i = j = k = 23;应理解成k = 23;j = 23;i = 23;三条赋值语句的简写形式。此时,赋值表达式(a = 3 * 2)= 5 * 7求值后变为6 = 5 * 7,也不合法。 程序员应该牢记,程序的可读性是程序最重要的属性之一。,return,3.2.2类型不匹配时的赋值操作,所谓类型不匹配时的赋值操作是指赋值表达式中赋值操作符左边子表达式值的类型与右边变量的类型不一致。 字符型数据在内存中以ASCII码形式存储,ASCII码可以看成整数,因此C语言允许字符型数据与整型数据通用。把字符型看作码长一个字节的整型后,C语言的基本数据类型就只有整型和浮点型两大类了。 因此类型不匹配时的赋值操作有?,1.整型之间相互赋值,编码长度相同的整型变量相互赋值时, 只是简单地把等号左边变量所标示内存空间的存储状态设置成与等号右边变量的相同。如short i = -1;unsigned short ui;当有赋值语句ui = i;时, 变量ui所标示内存空间的存储状态为16个1, 变量ui的值为65535。 如:unsigned short uj = 65535,short j;,当有赋值语句j = uj;时, 变量j所标示内存空间的存储状态同样为16个1,变量j的值为-1。,编码长度不同的整型相互赋值,设整型变量a,b,有赋值语句a = b;。 如果b的编码长度小于a,赋值时遵循的原则是使赋值后a的值与b的值保持一致。如何保持一致呢? 具体地说,若b为有符号整型,则当b为正数时,赋值后a的低位状态与b的内存空间状态一致,其它位为0;当b为负数时,赋值后a的低位状态与b的内存空间状态一致,其它位为1(这样就可以保证a的值与b的值一致,可参考练习二第2.6题)。 若b为无符号整型,则赋值后a 的低位与b的内存空间状态一致,其它位为0。,例3-2编码长度不同的整型相互赋值,b的编码长度大于a,如果b的编码长度大于a,则赋值后a的内存空间状态只与b的低位一致。b的高位状态丢失使a的值与b的值可能相差很大,因此这类赋值操作非常危险,编程时尽量不要出现。,2.整型与浮点型之间相互赋值,将浮点型数据赋值给整型变量时,仅把浮点数的整数部分赋给整型变量。 将整型数据赋给浮点型变量时,先把整型数据转换成小数部分为0的浮点数,再正常赋值。,例3-3 整型和浮点型之间相互赋值,return,3.2.3复合赋值操作符,赋值表达式i = i + 1和i = i * (a + b)可以分别简写为i += 1,i *= a + b,其中操作符+=和操作符*=称为复合赋值操作符。 从表3-1可知,C语言中大部分双目操作符都可以与赋值操作符组成复合赋值操作符,如由减法操作符组成的-=、由除法操作符组成的/=和由取余操作符组成的%=等。 i = i * a + b 不过类似i = i * a + b的表达式不能用复合赋值操作符简写。,return,3.3 算术操作符和算术表达式,C语言中的算术操作符有+, -,*,/,%,用算术操作符和括号将操作数连接起来组成的式子,称为算术表达式。 C语言中算术操作符的优先级和结合性虽然和数学上的定义一致,但由于操作数的类型有整型(char,short,long)和浮点型(float,double)之分,当类型不同的操作数混合运算时,正确求出算术表达式的值也并非易事。,类型转换的规则,当两个操作数的类型不同时,求值之前会先进行类型转换以统一数据类型。类型转换的规则如下: 1.float型自动转换成double型(为提高运算精度),char型自动转换成int(机器字长)。如果int型码长4个字节,则short型和unsigned short型也会自动转换成int型。 如:A 32 float f = 2.3; f * 3.2;,类型转换的规则,2.码长相同的整型变量混合运算时,有符号数会被认为是无符号数,结果也是无符号数。 例3-4 1.有unsigned short ui = 23;int j = -32;,那么ui + j的值大于0吗? 分析:int型的码长为2个字节(TC中)时, ui,j的编码长度相同。码长相同的无符号数与有符号数混合运算时结果为无符号数,而无符号数不可能小于0,因此ui + j的值大于0。 int型的码长为4个字节(vc6.0中)时,?,unsigned short型会根据规则1自动转换成int型,在运算器中计算的是int型的23和int型的-32的和,结果为-9(int型),因此,ui + j的值小于0。,类型转换的规则,例3-4 2. 有unsigned short ui = 23; short j = -32;,那么ui + j的值大于0吗? 分析:int型的码长为2个字节(TC中)时,变量ui和变量j不用转换成int型可以直接运算。码长相同的无符号数与有符号数混合运算时结果为无符号数,而无符号数不可能小于0且ui + j的值不可能为0,因此ui + j的值大于0。 int型的码长为4个字节(vc6.0中)时,求值时变量ui和变量j需要转换成int型,因此 ui + j结果为-9(int型),值小于0。,类型转换的规则,3. 有unsigned long ui = 23; short j = -32;,那么ui + j的值大于0吗? 分析:int型的码长为2个字节(TC中)时,因变量ui为长整型故变量j也需要转换成长整型。码长相同的无符号数与有符号数混合运算时结果为无符号数,而无符号数不可能小于0且ui + j的值不可能为0,因此ui + j的值大于0类型为unsigned long。 int型的码长为4个字节(vc6.0中)时,求值时变量j需要转换成int型,码长相同的无符号数与有符号数混合运算时结果为无符号数,而无符号数不可能小于0且ui + j的值不可能为0,因此ui + j的值大于0类型为unsigned long。,类型转换的规则,3.整型与浮点型混合运算时,整型转换成double型,运算结果也是double型。 float f = 2.3; f + 3;,类型转换的方法,表达式求值时进行类型转换的方法与不匹配类型互相赋值时处理方法相同,但是此时会产生新的临时变量参加表达式求值,原变量本身的类型和值不会改变。 int i = 2; 3.0/i的值为: ,类型为:,例3-5计算下面算术表达式的值,20 + a + 5 / 2 + 12.6 / 3 分析: 计算时先算优先级高的操作符,即两个除法操作符,计算完除法后,原表达式变为连加运算,加法运算符的结合性为左结合,因此从左自右进行连加运算。,例3-5计算下面算术表达式的值,20 + a + 5 / 2 + 12.6 / 3 先算子表达式5 / 2, 操作数类型相同,计算结果为2,int型。再算子表达式12.6 / 3, 操作数类型不同,3需转换成double型3.0,计算结果为4.2,double型。接着算子表达式20 + a, 操作数类型相同(a自动转换成int型97),计算结果为117,int型。再算子表达式117 + 2,操作数类型类型相同,计算结果是119,int型。最后算子表达式119 + 4.2,操作数类型不同,119转换成double型119.0,结果是123.2,double型。,return,3.3.2 强制类型转换操作符,如果表达式f % 2中的f是浮点型变量,则系统会判定该表达式不合法,因为求余操作符%只能用于整型变量。想用浮点型变量作为求余操作符的操作数时,必须把浮点型变量的类型强制转换成整型。 强制类型转化的一般形式为: (类型名)(表达式) 如有int i = 5;,则表达式i / 2的值为2,整型,但表达式(double)i / 2的值为?,强制类型转换,如有int i = 5;,则表达式i / 2的值为2,整型,但(double)i / 2的值为2.5,浮点型。 表达式(double)i / 2求值时先进行“(double)i”操作即强制类型转化,操作过程可理解为先定义一个double型临时无名变量,再用变量i给临时无名变量赋值,最后用这个double型的临时无名变量取代i参与表达式求值。 操作过程可模拟为double d; d = i; d / 2。 即使f是浮点型变量,表达式(int)f % 2也是合法的。,例3-6 强制类型转换,return,3.3.3 自增自减操作符,编程时经常要使变量的值增1或减1, i=i+1; C语言中比i += 1或i -= 1更简洁地实现此操作的表达式为i+,+i,或i- ,-i,其中的+就是自增操作符,-为自减操作符。 表达式i+和+i都可以使变量i的值增加1,可两者的区别为?,表达式i+和+i的区别,表达式i+的值是i的原值,而表达式+i的值是i加1后的新值。表达式i-和-i都可以让变量i的值减少1,但两者的区别也为表达式的值不同,表达式i-的值是i的原值,而表达式-i的值是i减1后的新值。 如有int i = -3,求表达式j = +i的值。 表达式j = +i中自增操作符+的优先级高于赋值操作符,因此先计算子表达式+i的值。表达式+i 求值时先把变量i的值加1变为-2,再把变量i的新值-2作为子表达式+i 的值,最后执行赋值操作把变量j的值变为-2,并且整个表达式的值也为-2。,自增自减操作符只能用于变量,如有float f = 3.2, k;,求表达式k = f-的值。 有上例求值过程可知,因子表达式f-的值为3.2,故变量k的值及表达式k = f-的值均为3.2,且此表达式求值完毕后,变量f的值变为2.2。 自增自减操作符只能用于变量,类似2+,-(x+y)的表达式都不合法。,例3-7 int i = -3时求表达式 -i+的值。,分析: 表达式-i+中有两个操作符。由表3-1可知,负号操作符-与自增操作符优先级相同,且此优先级操作符的结合性为右结合,因此表达式-i+相当于-(i+)。子表达式i+的值为i的值即-3,故原表达式-i+的值为3。 注意表达式(-i)+ 是非法的,因为自增自减操作符只能用于变量。,return,3.4 逗号操作符,逗号操作符“,”是C语言中优先级最低的操作符,逗号表达式的一般形式为:子表达式1,子表达式2,子表达式n。 逗号操作符是左结合,故逗号表达式的求解过程是自左向右,先求解表达式1,再求解表达式2,最后求解表达式n。最后求解的子表达式的值和类型也是整个逗号表达式的值和类型, 再次提醒:C语言中的表达式都有值及类型。,例3-8 分析下面两个表达式 (1) a =(a = 3 * 5, a * 4),分析: 表达式(1)中,括号操作符优先级最高,先求解括号里面子表达式的值,最后执行赋值操作,因此表达式(1)是一个赋值表达式。括号里面的子表达式为逗号表达式,求解时先求解表达式a = 3 * 5,即把15赋值给变量a,在求解表达式a * 4时,a的值为15,故a * 4的值是60,且60也是表达式a = 3 * 5, a * 4的值,因此当最后执行赋值操作时,60会被赋给变量a,整个表达式执行完毕后,a的值是60。,例3-8 分析下面两个表达式 (2) b = a = 3 * 5,a * 4,因逗号操作符的优先级最低,故表达式(2)相当于(b = a = 3 * 5),(a * 4),显然是一个逗号表达式,整个表达式最终的值为60。执行完此表达式后变量b,a的值均为15。,注意:,例3-8中的表达式a =(a = 3 * 5, a * 4) 只能用来分析表达式的求值过程,程序中绝对不要出现类似的表达式。把a = 60写的如此丑陋实在不可取。 逗号表达式多用于将多条C语句连接成一条C语句。如i=0;j=0;可写成一条C语句 i=0,j=0;。,return,3.5值与编译系统相关的表达式,大多数的表达式在不同的编译系统中有相同的值,但是在有些表达式中,C标准没有具体规定表达式中的子表达式的求值顺序,如表达式a = f1( ) + f2( )求值时,是先调用函数f1还是先调用函数f2并没有具体的规定。 又如类似( ) * ( )表达式求值时,先对哪个括号里的子表达式求值也没有具体的规定。由于不同的编译系统对子表达式的求值顺序有着不同的优化原则,所以就会出现一个表达式在不同的编译系统中可能有不同的值的问题。,如有int i = 2时,表达式 (i+)+(i+)+ (i+)的值,在不同的编译系统中就可能不一样。 有些编译系统自左向右顺序求解括号内表达式的值,则原表达式的值为2+3+49。 有些编译系统把2作为子表达式中所有i的值,即相当于括号内的子表达式同时求值,则整个表达式的值为2+2+26,在求出整个表达式的值后,再实现i自加3次,最终变量i的值同样变为5。,int j = 3时,函数调用语句printf(“%d,%dn“, j, j+);的输出值,也不确定。 C标准对函数调用时,作为输入数据的表达式的求值顺序没有明确规定。有些编译系统按自左向右顺序求值, 此时表达式j,j+的值都为3,函数调用语句的输出结果为3,3。 有些编译系统按自右向左顺序求值, 此时先计算表达式j+的值再考虑j的值,函数调用语句的输出结果为4,3。,在编程时,不要使用结果与编译系统相关的C语言表达式。,int j = 3时,函数调用语句printf(“%d,%dn“, j, j+);的输出值 希望输出3,3时, 可以将上面的语句改写为printf (“%d,%dn”, j, j);和j+;两条语句。 希望输出4,3时, 可以将上面的语句改写为i = j+;和printf(“%d,%dn“, j, i);两条语句。,学习时表达式时有两方面的要求,C语言表达式类型丰富,表达能力强,在学习时有两方面的要求: 一方面能根据操
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 离婚后子女抚养责任及财产分割补充协议
- 棕榈油种植基地租赁合同范本:油脂加工与品牌合作
- 离婚抚养协议:子女医疗及意外保险安排
- 市政管道工程施工组织设计方案
- 大桥拆除重建工程技术方案
- 汽车类专业课试题及答案
- 1.2微生物的培养技术及应用教学设计-2024-2025学年高二下学期生物人教版选择性必修3
- 新能源安全管理2025年策略报告:技术创新与行业监管
- 2025年教育信息化基础设施建设与教育信息化产业发展策略研究报告
- 淘宝上的大数据营销方案
- 公路养护技术管理与实施细则
- 2025-2030留学培训行业市场运行态势及发展前景预测与商业合作机会研究报告
- 房地产开发公司工程部经理个人工作总结
- 2025年交通工程师资格考试试题及答案解析
- 2025年私人住宅装修合同及详细工程清单
- 2025年法本法硕真题及答案
- 变压器装配工职业技能考核试卷及答案
- 驻场人员管理协议书8篇
- 2023-2025年中考物理试题分类汇编内能及内能和利用(有解析)
- 秋季传染病健康知识培训课件
- 2025-2026学年北师大版数学小学三年级上册(全册)教案设计及教学计划
评论
0/150
提交评论