3运算符表达式_第1页
3运算符表达式_第2页
3运算符表达式_第3页
3运算符表达式_第4页
3运算符表达式_第5页
已阅读5页,还剩24页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第3章运算符与表达式运算符和表达式是 C语言的核心语法,C语言运算符丰富,不仅有优先级概念,还有结 合性的概念;不仅有算术、关系和逻辑运算符,还有赋值、逗号运算符。由于C语言运算符丰富,因此表达式类型多,而且将字符、逻辑值数值化,使得C语言表达式的使用变得非常灵活。熟练掌握 C语言的运算符和表达式是学好C语言的基本要求。3.1运算符与表达式概述3.1.1 C运算符简介运算是对数据的加工过程,表示不同运算的符号叫做运算符,而参与运算的数据叫做操 作数。不同的计算机语言有不同的运算符集。C语言中提供了丰富的运算符,它除了常规运算符如算术运算符、关系运算符、逻辑运算符外,还有如赋值运算符、逗号运算符

2、、位处理 运算符、指针运算符、访问结构体和联合体成员运算符等C语言所特有的运算符。在 C语言中,除了几个控制语句外,几乎所有的操作都是通过由运算符构造的表达式来完成,因此C语言运算符的作用范围很广。1 运算符分类及属性C语言的运算符可分为如表3-1所示的15类。每个运算符除了优先级外,还有结合性等属性。一个表达式的计算顺序需要将运算符的优先级和结合性综合起来考虑。表3-1 C语言运算符的优先级及结合性优先级运算符含义操作数个数结合方向举例1()->圆括号下标运算符 指向结构体成员结构体成员自左至右(a4b)*c array5 p-涉um stud, name2!卄(类型)*&si

3、zeof逻辑非 按位取反自增自减负号 类型转换 间接访问 取地址(取指针) 变量或类型的长度1单目运算符自右至左!a0(i+M(餡-X(float)n/20xVpp=&xsizeof(long) <§izeof(x)3*/%乘法 除法 求余2双目运算符自左至右a*ba/b2舲4+加法减法2双目运算符自左至右a北a-b5左移右移2双目运算符自左至右a* a莎续表优先级运算符含义操作数个数结合方向举例6<>小于 小于等于大于 大于等于2双目运算符自左至右if (x <y)其余运算符类似7!等于不等于2双目运算符自左至右if (x 占) while (i!

4、/)8&位与2双目运算符自左至右a&b9A位异或2双目运算符自左至右bA02410|位或2双目运算符自左至右044 | c11&&逻辑与2双目运算符自左至右(a沙)&&(c <d)12|逻辑或2双目运算符自左至右(>1) && (y <?)13?:条件3三目运算符自右至左xm 少?a:b144=-=* = / %= & = "=1 =赋值(复合赋值)2双目运算符自右至左am 4ba+z=b(同 am-lb) a*b4c(同 am*(b -4c) a&=b(同 a=a&b) 其余复

5、合运算符类似15逗号2双目运算符自左至右a=, b£ c 丄12本章将详细讨论 C语言的算术运算符、赋值运算符、强制类型转换运算符、逗号运算符、关系运算符、逻辑运算符。其余的运算符将在后续章节中逐步介绍。2 关于运算符的几点说明(1) C语言的运算符按其性质分类有15类;按运算符所要求操作数的个数分类,又可以分为单目运算符、双目运算符和三目运算符。例如:”为单目运算符,“* ”、“/”为双目运算符,“ ?:”为三目运算符。(2) 优先级别。一个表达式中可以有多个运算符,这时首先按运算符的优先级别进行运 算,C语言运算符的优先级别与数学运算中的意义相同,它决定了一个表达式的运算顺序。如

6、果一个操作数两侧有两个不同优先级别的运算符,则先执行优先级别高的运算。如4-9*7,在9的两侧分别为-、*,根据C运算符的运算级别,则先 *后-。(3) 结合性。如果一个操作数的两侧有两个优先级别相同的运算符,则按结合方向顺序 进行处理。C语言运算符的结合性分为: 左结合性。如果一个运算符对其操作数自左至右执行规定的运算,则称该运算符是左结合的。运算符、-、*、/、:、&&、|等都是左结合性的运算符。例如:5*8/38两侧的运算符分别为*、/,它们的优先级相同,根据“自左至右”方向的结合原则先*后/,即8先和其左边的运算符结合(5*8),再与其右边的运算符结合 (40/3)。

7、右结合性。如果一个运算符对其操作数自右向左执行规定的运算,则称该运算符是右结合的。运算符 -!、亠亠、-等都是右结合性的运算符。例如:25 / 23a=b =c=8b两侧都是赋值运算符“£ (即优先级相同),根据“自右至左”方向的结合原则,它先与其右侧的赋值运算符结合,即a=(b c=8)。由于赋值运算符“ 是一个双目运算符,因此b右侧赋值运算符的右边要求有一个操作数,这里是“c”,那么是把c的值直接赋给b呢?还是先进行“ c =8”运算呢?由于 c两侧的运算符级别相同且是“右结合性”,因此c应先与其右的赋值运算符结合,故表达式相当于a=(b=(c)。关于“结合性”的概念是其他高级语

8、言没有的,是C语言的特点之一。(4)在使用C语言的运算符时,应注意运算符对操作数类型的要求。如、-、*、/的运算对象可以是整型或实型数据,而运算符:(求余运算符)要求参加运算的两个操作数都必须是整型数据。(5)一个运算符两侧的操作数类型可以不同,C编译会自动进行类型转换,使二者具有同一种类型,然后进行运算。(6)C语言的运算符较多,又有其优先级和结合性,初学者要特别仔细,善于归纳。3.1.2 C表达式简介用运算符将常量、变量、函数等(称为操作数)连接起来的符合C语言规定的式子称为C语言表达式。作为表达式的特例,一个单独的变量或常量也可以称为一个表达式。下面是几个表达式的例子:a b-c*3 d

9、/eaz8y=a b|ca =a bC语言中所有的运算都是用表达式表示的,清楚地了解表达式的求值顺序是正确书写表 达式的关键。表达式的求值顺序取决于表达式中参与运算的运算符的优先级、结合性和语言的具体实现。例如,表达式:a b*c因“ +”的优先级低于“ * ”,所以运算顺序为先计算b*c的值,然后再与 a相加。再如,表达式:n由于运算符“ -”(负号运算符)和“”的优先级相同,结合性均为右结合的,所以求解该表达式的顺序为:先进行n运算,然后再对运算结果求负。即相当于:-(n)。3.2算术运算符和算术表达式算术运算是我们日常生活中使用最为常见的一种运算。c语言不仅提供了基本算术运算符,如加、减

10、、乘、除和求余等,还提供了增量、减量运算符。3.2.1基本算术运算符和算术表达式1 基本算术运算符C语言中的基本算术运算符包括单目算术运算符:(负号)和双目算术运算符:-(加)-(减)* (乘)/ (除):(模除)单目运算符“ 一”又叫做一元减运算符,其作用与数学中的负号相同,即取操作数的负 值。双目算术运算符、与数学中的加、减的作用相同,而*、/则分别对应数学中的乘、除。例如,3 5,6_4,3*a,b/c等。双目运算符:叫做模运算符或称为求余运算符,其作用是取 被除数的模,即被除数除以除数后的余数。例如,13 5的结果为3,3 5的结果也为3,而-13: 5的结果为-3。单目算术运算符“”

11、结合方向为“自右至左”,其优先级别高于双目算术运算符,双目 算术运算符的*、/、:的优先级别相同,运算符 、一的优先级别相同,但前者的优先级别高 于后者。双目算术运算符的结合方向为“自左至右”。需要说明的是:(1)运算符“:”要求它的两个操作数都是整型数据。(2)其他运算符可以是任何基本数据类型。(3)若运算符“ /”的两个操作数都为整数,则运算结果即商也为整数,小数部分被自然 舍弃了。例如:13/5的运算结果为2,5/13的运算结果为0。参加运算的两个数只要有一个为实型,则结果是实型。2 .算术表达式用算术运算符和括号将运算对象(也称操作数)连接起来的、符合C语言语法规则的式子称为C算术表达

12、式。运算对象包括常量、变量、函数等。例如,下面是一个合法的C算术表达式:a*b/c -1.5 aC语言规定了运算符的优先级和结合性。在写C表达式时一定要注意运算符的优先次序和结合方向,C表达式求值时,先按优先级别高低次序执行。如果在一个运算对象两侧的运 算符的优先级别相同,则按规定的“结合方向”处理。如:a-b c*d该表达式的运算顺序为:(1)由于b两侧的运算符的优先级别相同,则按“自左至右”结合方向进行,因此b先与减号结合,执行(a-b)运算;(2)由于c两侧运算符的优先级不同,*高于,因此c先与*结合,执行(c*d)运算;(3)最后执行(a七)(c*d)运算。3.2.2增量减量运算符C语

13、言提供了两个使变量的值增1、减1的运算符:(增量)-(减量)它们都是单目运算符,其运算结果是将操作数的值加1、减1。例如:设变量i的值为5,则亠亠i后i的值将变为6,即表达式亠亠i相当于赋值表达式i=i V。又如一i相当于赋值表达式i=i-1。由于增量、减量运算符本身就隐含有赋值操作,所以它们的操作数必须是一个变量。例如:5亠亠或(a - b)亠亠都是不合法的。但是,与其他单目运算符不同的是,这两个单目运算符的操作数既可以放在运算符的前面,又可以放在运算符的后边。如:i (前置增量)i(后置增量)28 / 23i (前置减量)i-(后置减量)作为一个单独的表达式时,运算符前置和后置是没有什么区

14、别的,但在一个还包含有其 他运算的表达式中,运算符前置和后置却会产生不同的效果。在一个包含有其他运算的表达 式中,增量或减量运算符的前置意味着先对其操作数进行相应的增量或减量,然后再进行其 他的运算;而后置增量或后置减量运算符先对其操作数进行其他运算,然后对操作数进行相 应的增量或减量运算。例3.1测试表达式中前置、后置增量运算符的运算顺序。#include :stdio.h .void mai n() int i =5, j, k;printf( iW d, j 仝 d , i, j);k =i ::; printf( i 二 d, k= dn , i, k);运算结果为:i =6, j =

15、6, i =7, k =6表达式使用中应注意的问题:(1) 和一的结合方向是“自右至左”,即右结合性。如果有H , i的左边是负号运算符,右边是增量运算符。因负号运算符与增量运算符同优先级,而它们的结合方向为“自右至左”故先进行“ i”运算,再进行负号运算,即它相当于-(i)。例如,如果i的值为3,对于printf( - d ,:;囂);语句,则先取出i的值使用,输出-i的值-3,然后使i增值为4。另外,假 若按左结合性,则上式相当于(-i),而()是不合法的。(2) 增量、减量运算符常用于循环语句中,使循环变量自动加1或减1。也用于指针变量,使指针指向下一个或上一个存储单元。这些将在后续章节

16、中介绍。(3) 在一个表达式中含有多个增量(减量)时,系统在计算表达式前,先对表达式中的增量(减量)进行扫描,并对其前置变量逐一增1 (减1),然后计算表达式的值,最后再对后置变量增1 (减1)操作。例3.2多个增量(减量)运算符组成的表达式的运算顺序。#include :stdio.hvoid mai n() int i =3, k;0 一)p 一)(i 一); printf( i= d, k- d , i, k);i f;kp黑i) (皿'i) (:;:;'i);printf( i - d, k- d , i, k);23;k=(i) (i ) (i);printf( i=

17、 d, k- dn , i, k);运行结果为:i=6, k£ i£, k=18 i£ k=15结果分析: 首先分析表达式()()()的值。有人认为它相当于3 4 5,即卩12。事实上,用Turbo C系统时它等于 9。它是先把i的原值(3)取出来参加表达式的运算,因此先进行 三个i相加得9;然后再使变量i进行三次增1,故i的值变为6。 分析表达式(亠亠i)亠(亠亠i)亠(i)的值。有人认为它相当于4亠5亠6,即15。事实上,它的值是18。原因是:i的自增1是在整个表达式计算之前就进行的,即对表达式扫描,先对i进行三次增1,i的值变为6;然后进行6 6 6的运算,

18、故得18。 分析表达式(亠亠i)亠(i亠亠)亠(i)的值。系统先对表达式扫描,遇到两次亠亠i和一次i,先对i进行两次增1,i的值变为5 ;然后进行5 5 5的运算,故得15 ;运算完后再使变量 i 增1 (因为i+是先引用后增1)。(4)C语言中的运算符有的是一个字符,有的是由两个字符构成,在表达式中如何组合呢?如i亠亠亠j是理解为(i亠亠)j呢?还是i (一j)呢? C语言在编译处理时尽可能多地 “自左至 右”将若干个字符组成一个运算符(在处理标识符时也按同一原则处理),如i行巧,将解释为眉)j,而不是i C;:;j)。(5)含有增量(减量)的表达式作为函数的参数时,表达式的求值顺序与上面介

19、绍的有所不同。例如,Turbo C环境下,如果i的初值为3,则:printf( - d : ( i) ( i) (i );的输出结果为14。这是因为:对函数参数求值时并不是先扫描后求值,它首先求第一个i的值为4,再求第二个卄i的值为5 (因求第一个卄i后i的值已为4),再求第三个i卄的值 为5 (因求第二个 十+i后i的值已为5),最后将它们的和 445代等于14输出。(6)C语言中类似上述的问题还有一些。例如, i的初值为3,如果有下面函数的调用: printf( - d, : d ; i, i 一);在有的系统中,对函数的参数是从左至右求值,输出“3, 3”。在多数系统中,对函数参数的求值

20、顺序是自右至左(Turbo C就是如此)。上面的 printf函数是要输出两个表达式的值(i 和i亠亠分别是两个表达式),先计算出i亠亠的值再计算i的值,i亠亠的值为3,计算i亠亠后i的 值变为4,这个4就成了第一个参数i的值,因此上面函数输出的结果是“4, 3 ”。对于上述问题,读者不必死记,因不同系统的处理方法不一样。但应当知道使用C语言可能出问题的地方,必要时上机试一下,以免遇到问题时不知其所以然。使用和-运算符能给编程带来方便,使程序更加简洁,但也会出现一些人们“想不到” 的副作用,初学者要慎用。3.3赋值运算符和赋值表达式在程序中使用最频繁的表达式就是赋值表达式,在C语言中,赋值的方

21、法灵活多变。本节介绍C语言的赋值运算符和赋值表达式及表达式中类型的转换。29 / 233.3.1赋值运算符和赋值表达式1 赋值运算符“=”为C语言的赋值运算符。赋值运算符的运算级别仅高于逗号运算符“,”,低于其他所有的运算符。它的结合方向是自右至左。运算符“(属于双目运算符,其左边的操作数称为赋值运算符的左值,其左值只能是 一个变量;右操作数可以是任意表达式。2 .赋值表达式由赋值运算符将一个变量和一个表达式连接起来的式子称为“赋值表达式”。例如a =5 3”就是一个赋值表达式,它的作用是执行一次赋值操作(或称赋值运算),把表达式5 3的结果赋给变量 a。赋值表达式的一般形式如下:左值二右值(

22、1)左值(left value,缩写lvalue )是能出现在赋值表达式左边的表达式。左值表达式具 有存放数据的空间,并且存放是允许的。例如:int a =10;/ a是变量,所以它是正确的左值a b -20;/错误,a b是一个表达式,没有对应的存储单元,它不能作为左值(2)右值(right value ,缩写rvalue)是可以出现在赋值表达式右边的表达式。右值表达 式可以是任意类型的表达式。例如:int x, y =8, z;x弓;z =(z 亠y)*5 _x*x;赋值表达式的作用就是将赋值运算符的右值(即右值表达式的运算结果)赋给左值变量, 该值同时又是整个赋值表达式的值。如赋值表达式

23、a£/3是把右值表达式 6/3的值2赋给左值a,同时整个赋值表达式a =6/3的值也等于2。由于赋值表达式的右值表达式可以是任意合法的C表达式,而赋值表达式本身就是一个合法的C表达式,所以赋值表达式可以作为赋值表达式的右值。例如:冃5就是一个合法的赋值表达式,由于赋值运算符具有右结合性,故上述表达式相当于:i司同a=b =c=7(表达式的值为a =5 (c =7)(表达式的值为a=(b =6) -(c=4)(表达式的值为a =(b W0)/(c =2)(表达式的值为F面是赋值表达式的一些例子:即先把5赋给变量j,然后把表达式j=5的值赋给变量i。7, a、b、c的值均为7)12, a

24、的值为12, c的值为7)2, a的值为2, b的值为6, c的值为4)5, a的值为5, b的值为10, c的值为2)将赋值表达式作为表达式的一种,使赋值操作不仅可以出现在赋值语句中,而且可以以表达式的形式出现在其他语句(如循环语句)中,这是C语言灵活的一种表现。以后将会看到这种应用的优越性。3.3.2复合赋值运算符C语言中的所有双目算术运算符和双目位运算符均可与赋值运算符组合成一个单一的运芒二(取模等)=(右移等)算符,即复合赋值运算符,一共有十个:=(加等)-=(减等)&二(与等)匚(或等)后五种是有关位运算的,将在第* =(乘等)/=(除等)心(异或等):十(左移等)13章中介

25、绍。复合赋值运算符的优先级别和结合性都与赋值运算符相同。复合赋值运算符可以用来构 成复合赋值表达式,其构成形式与赋值表达式相同。复合赋值表达式的运算过程为:先将左值和右值作运算符所规定的算术或位运算,然后将其结果赋给其左值表达式。下面以*二为例说明复合赋值表达式的运算过程。设i和j的值分别为5和6,则:i* d j表示先计算复合赋值表达式的右值表达式的值,即算术表达式ij的值,其运算结果为11;然后把左值和右值作复合赋值运算所规定的算术运算,即i与上述结果的乘积,其运算结果为55;最后进行赋值运算操作,即把上述运算结果赋给运算符的左值i。同时整个表达式的值亦为55。从其功能上看i* =i j等

26、价于i=i*(i j)。下面再来看一个赋值表达式包含复合赋值运算符的例子:a* 二a-二a a也是一个赋值表达式。如a的初值为2,此赋值表达式的求解过程如下:(1)运算符*=和-二的优先级相同且具有右结合性,故先进行“a-=a,a”运算,相当于a=a-(a,a),它的值为-2;(2)再进行“ a* =2”运算,相当于 a=a*( -2)=(-2)*( -2)=4。注意,此时a*(2)所用的a的值为-2,而不再是2,这是因为第(1)步运算已对a进行了 重新赋值。由此可见,表达式a*=a=aa相当于:a=a*(a =a-(a a)C语言采用这种复合运算符,一是为了简化程序,使程序精练简洁,二是为了

27、提高编译效率。3.4数据类型的转换3.4.1隐式类型转换一般来说,一个双目运算符的两个操作数的类型必须一样才能进行运算操作,但c语言 允许在一个表达式中存在不同数据类型的操作数。在对这样的表达式求值时,编译系统会对 其中的一些操作数自动地进行类型转换一一称为隐式类型转换,以使一个双目运算符两个操 作数的类型一致。例如:10 15.2-27* a'=b 是合法的。运算时,不同类型的数据要先转换成同一类型,然后进行运算。隐式类型转换的规则为:(1)无条件的隐式类型转换。所有的 char型和short型都必须转换为int型,所有的float31 / 23型都必须转换成 double型。即使两

28、个操作数都是相同类型,也要进行类型转换。(2)统一类型的隐式类型转换。如果一个运算符的多个操作数的类型不一致,则需要将 较低的类型转换为较高的类型,然后基于同一类型进行运算。例如,如果类型级别最高的一 个操作数为long型,则其他操作数也要转换成long型;如果类型级别最高的一个操作数为double型,则其他操作数也要转换为double型。无条件类型转换图3-1 隐式类型转换规则隐式转换规则如图 3-1所示。低 I如果一个运算符的多个I操作数类型不一致,则I首先需要将较低类型的操作数转换为较高的类!型,然后进行运算 高图3-1中的横向箭头表示必定转换,而纵向箭头表示涉及不同类型数据之间的运算时

29、的转换方向,即当一个运算符的多个操作数为不同类型时的转换方向。纵向箭头的方向只表示数据类型的高低,数据类型由低向高转换,并不表示一定要逐级转换,例如一个double型与一个int型数据之间的运算, 是直接将int型转换为double型,而不是先由int型转换为long, 再由long型转换为double型。例如:f为float型,表达式:a b f运算次序为: 进行a b的运算,先将 a、b都转换成int型(无条件转换),转换后分别是int型数 据97和98,然后对两个int型数据进行运算,结果为 int型数据195; 进行195-f的运算,需要把int型195和float型f都转换成doub

30、le型相加(其中,float 到double型的转换是无条件转换,int到double型的转换是统一类型转换),其结果为double 型。应当说明的是,类型的转换仅是临时性的,它并不改变变量的数据类型,只是在执行运算时将变量值的类型作了临时的转换。例3.3 隐式类型转换的效果。#include :stdio.hvoid mai n() int i =3, j;j =i 1.5;/* 语句 A */printf( di - d, fi - fn ; j, i 1.5);/* 语句 B */运行结果如下:di 詔,fi =4.500000说明: “语句A ”和“语句B”中的表达式 1.5运算时,i

31、、1.5都转换成double型,结果为 double 型(4.50000000000000); “语句A”中将double型的1.5赋给整型变量j,结果j的值为4 (详见3.4.2节的赋 值类型转换)。3.4.2赋值表达式两侧数据的类型转换赋值表达式的左值是变量,而不同类型变量存储数据的形式是不一样的,因此赋值表达 式两侧数据类型的转换规则与数据的存储形式有密切的关系。1 整型数据与实型数据之间的转换(1)将实型数据(包括单、双精度)赋给整型变量时舍弃实数的小数部分。如i为整数变量,执行“ i£76”时的结果是i的值为6。(2)将整型数据赋给单、双精度变量时数值不变,但以浮点数形式存

32、储到变量中,如将整数23赋给float型变量f (即f=23),先将整数23转换为浮点数形式,再存储到f中,f的值为 23.00000。2 字符型数据与整型数据之间的转换字符型数据赋给整型变量时,由于字符数据占1个字节,而整型变量为2个字节,因此将字符数据(8位)放到整型变量低8位,整型变量高 8位的处理有两种情况:(1)如果所用系统将字符处理为无符号量或对unsigned int型变量赋值,则整型变量的高8位全部补0。(2)如果所用的系统将字符处理为带符号的量,则整型变量的高 8位要进行“符号扩展”。即若字符的最高位为 0,则整型变量的高 8位全部补0;若字符的最高位为 1,则高8位全部 补

33、1。这样做的目的是使数值保持不变(请读者回顾一下补码存储的原理)。3 .不同类型的整型数据之间的转换(1)整型常量赋给整型变量。整型变量可分为int、short、long和unsigned int、unsignedshort、unsigned long等类型,整型常量也有相类似的int、long类型。在将一个整型常量赋给上述几种类型的整型变量时如何做到类型匹配?请注意以下几点: 一个整型常量,如果其值在£2 76832 767范围内,系统认为它是int型,它可以赋值给int型和long int型变量。 一个整型常量,如果其值超过了上述范围,而在-2 147 483 648 2 147

34、 483 647范围内,则认为它是long int型,可以将它赋值给一个long int型变量。 常量中无unsigned型。但一个非负值的整型常量可以赋值给unsigned型变量,只要它的范围不超过变量的表示数值范围即可。例如,将50 000赋给一个unsigned int型变量是可以的,而将 70 000赋给它是不行的(溢出)。 在一个整型常量后加一个字母 I或L,则认为是long int型常量。例如123l、432L、0L等。这往往用于函数调用中。如果函数的形参为long int型,则要求实参也为 long int 型,此时用123作实参不行,而要用 123L作实参。(2)不同类型整型数

35、据间的赋值约定:将带符号的整型数据(int型)赋给long int型变量时,long int型变量的低16位接受 整型数据的16位,而高16位要进行符号扩展。符号扩展的方法是:如果int型数据为正值(符号位为0),则long int型变量的高16位全部补0;如果int型数据为负值(符号位为1), 34 / 23则long int型变量的高16位全部补1。例如:long a =5, b=_5;赋值后的结果如图 3-2所示。5000000000000010100000000000000000000000000000101a11111111111110111111111111111111111111

36、1111111011图3-2 int型数据到long型变量的赋值int型常量(5)*long型变量(5)int型常量(_5)Ilong型变量(_5)将一个long int型数据赋给一个int型变量,要进行数值位截取。数值位截取的方法 是:将long int型数据中低16位原封不动搬到int型变量中。这时应注意由于数据范围的变 化出现的数据错误。例如:int c =196607;赋值后的结果如图 3-3所示。19660700000000000000101111111111111111c1111111111111111图3-3 long型数据到int型变量的赋值long 型常量(196607)!i

37、nt型变量(J) 将unsigned int型数据赋给long int变量,要进行数值位扩展。数值位扩展的方法是: 将long int变量的高16位全部补0。例如:unsigned d =32779; long e;e -d;赋值后的结果如图 3-4所示。1000000000001011100000000000101132779d00000000000000001000000000001011图3-4 unsigned int型数据到long型变量的赋值常量(32779)i runsigned 变量(32779)Ilong 型变量(32779) 将一个unsigned型数据赋给一个占字节数相同

38、的整型变量(如unsigned int至int,unsigned long 至 long, unsigned short 至 short),就是将 unsigned 型数据原样送至U非 unsigned 型变量中。这时,应注意由于数据范围的变化出现的数据错误。 将非unsigned型数据赋给长度相同的unsigned型变量,就是将非unsigned型数据原样赋给unsigned型变量。例3.4 不同类型整型数据间的赋值验证。#inelude :stdio.h .void mai n() int a =53, b »3, c £5533, d 乂xABCDE;long x =

39、a, y =b;unsigned u -2;printf( a= d, a- un ; a, a);/ : d以带符号十进制形式输出整数printf( b仝二d, b仝二un , b, b);/ u以无符号十进制形式输出整数printf( c= d, c= un ; c, c);printf(dm;:d, d m;:xn ,d, d);/x以无符号十六进制形式输出整数printf(u= d, u= un ,u, u);printf(x=b:ld, x =*:lxn; x, x);/:Id以带符号十进制形式输出长整数printf(yWId, y W:lxn; y, y);/:lx以无符号十六进制

40、形式输出长整数运行结果如下:a =53, a =53b-3, b=65533c =-3, c =65533d -17186, d 二bedeu -2, u -65534x 吒3, x -35y =_3, y ffffffd赋值后,例3.4中各变量对应存储单元的存储结果如图3-5所示。0000000000110101b1111111111111101c1111111111111101d10111100110111100000000000000000000000000011010111111111111111111111111111111101xy1111111111111110图3-5例3.4中

41、各变量存储单元的存储结果注意:C语言一般是以补码形式存放数据的,整型数据的最高位应是符号位(1表示负,0表示正),而unsigned型的数据是无符号数据,所有位都是数值位。因此,即使两个变量的 内存存储单元的内容完全相同,即长度相同,对应位上的二进制数相同(注意,它们的含义 可能并不相同),它们的结果可能并不一样。例如,假设变量i、j的内存存储单元的存储情况如图3-6所示,若i、j为unsigned型,贝U i的值为65 535,j的值为3 683 ;若i、j为int 型,则i的值为-1, j的值仍为3 683。35 / 233.4.3强制类型转换虽然隐式类型转换有一定的优越性,但是,由于程序

42、员无法控制表达式的类型,进而可 能影响表达式最终结果的精度。例如:int i =7;float f;f£/2 10.2;其结果是f的值为13.2,而不是13.7。这是因为编译器在处理赋值运算右边的表达式时,按 照运算符的优先级,先进行 i/2的计算。由于算术运算符“/”两边的操作数的数据类型一致,没有必要进行类型转换,从而使得计算的结果为一整型值3。因此,导致最终的计算结果少了一个 0.5。为了解决类似问题以及提高程序设计的灵活性,C语言提供了强制类型转换运算符,即“(类型标识符)”。例如:(double)f(将f转换成double类型)(int)(x y)(将x y的值转换成整型)

43、(float)i/2(将i的值转换为float型后再除以整数 2)强制类型转换的一般形式为:(类型名)(表达式)有了强制类型转换运算符,通过如下语句我们就可以使上例得到一个满意的结果。f =(double)i/2 10.2;分析:由于i被强制转换成了 double型,根据隐式转换规则,整数2也被编译器转换成double型,除法运算结果也是double型。最终将使f获得正确的结果 13.7。关于强制类型转换需要注意的几点:(1) 强制类型转换的表达式要用括号括起来。例如,要把x y的结果强制转换成int型,必须写成(int)(x y),如果写成(int)x y,则编译器解释为将x转换成整型,然后

44、与 y相加。(2) 在对一个变量进行强制类型转换时,得到一个所需类型的中间值,原来变量的类型并未发生变化。例如:(int)x,如果x原为float型,进行强制类型运算后得到一个int类型的中间值,它的值等于 x的整数部分,而x的类型不变(仍为 float 型)。3.5逗号运算符和逗号表达式逗号“,”既是一个 c语言的标点符号,又是一个c语言的运算符。它是一种特别的运算符一一逗号运算符。用逗号运算符连接起来的式子称为逗号表达式。例如:a b, b*c, c -a就是一个逗号表达式。逗号表达式的一般形式如下:表达式1,表达式2,表达式3,表达式n逗号表达式的求解过程是:自左向右地计算各个表达式的值

45、,即先计算表达式1,再计算表达式2,,最后计算表达式 n。而整个逗号表达式的值为最后一个表达式n的值。例如,若a、b、c的初值分别为2、7、10,则如下语句分别执行后(都是基于初值) : x=(a=a b, b=c*4, c =c-a); y =a=a b, b =c*c, c 虫-a;变量x的值为1,而变量y的值为9。因为逗号运算符的运算级别是最低的,在执行语句时把“ a b"的值9赋给a,再把“ a=ab”的值9赋给y,故y的值为9。其实,逗号表达式无非是把若干个表达式“串联”起来。在许多情况下,使用逗号表达 式的目的只是想分别得到各个表达式的值,而并非一定需要得到整个逗号表达式

46、的值,逗号 表达式最常用于循环语句(for语句)中。逗号运算符也称为“顺序求值运算符”。值得提出的是,在 C语言中并不是任何地方出现逗号都是作为逗号运算符,它还能作为 分隔符来使用。如函数参数的分隔,变量说明中各变量之间的分隔等,在使用中要加以区别。例如:int a, b, c;printf( : d, : d, : dn ; a, b, c);其中的“ a, b, c”并不是一个逗号表达式,而是将 a、b、c进行分隔,作为分隔符使用。又如:printf( : d, : d, : d , (a, b, c), b, c);则“ (a, b, c)”是一个逗号表达式,它的值等于c的值。因为整个括

47、号内的内容作为printf函数的一个参数,括号内的逗号不是参数分隔符而是逗号运算符。3.6关系运算符和关系表达式“关系运算”实际上是“比较运算” 符“”把两个操作数连接起来。如果 值等于5,则为“假”。例如,“x .10”是一个关系表达式,它由关系运算 x的值等于20,则关系表达式的值为“真”;如果x的1 关系运算符C语言中的关系运算符都是二元运算符,共包括以下六个运算符:<(小于)<=(小于等于)>(大于)>=(大于等于)=(等于)!=(不等于)37 / 23(左结合性)(“ ”优先于“!二”) (“-”优先于“ ”)(“二”优先于“”)例如:a b :=c等效于(a

48、 b):二ca b! p等效于(a b)!二ca b-c等效于 a (b -c)x=c =b等效于 x=(c 二b)2 .关系表达式用关系运算符将两个表达式连接起来的式子,就是关系表达式。例如:a bc=dx :=0n! =10 x :8.3x_y a-ba*b 13.6都是合法的关系表达式。关系表达式的一般形式如下:表达式1 关系运算符 表达式2关系表达式的值是一个逻辑值,即“真”或“假”。当给定的条件满足(成立)时,关系表达式的值为“真”,否则为“假”。值得提出的是:数据在计算机中都是表示为二进制形式, 因此,关系比较实质上就是比较两个操作数的大小。C语言中并没有提供逻辑型数据,关系运算的

49、结果是一个整型数,当两个操作数满足关系运算所要求的比较关系时,其结果为1,相当于逻辑真;否则为0,相当于逻辑假。说明:在其他的高级语言如Pascal语言中,提供了逻辑型变量和逻辑型常量,它是以True表示“真”,以False表示“假”。例如:i =(3 :5) 8由于(3:5)满足条件,值为1,则i的值为9。如果把括号去掉:i =3 :5 8由于算术运算符的优先级高于关系运算符,所以编译器将把它解释为:i =3 :(5 8) 这时i的值为1。注意:关系运算符的两个操作数可以是任何基本数据类型,但是在比较实数的相等时, 有时会判断错误,这是由于实数在计算机中的存储方式和计算误差所引起的。例如,有

50、两个 实型变量g和f,经过一系列的运算后,设它们的值在理论上都应当是5.0,然而由于计算的误差,它们的实际值可能分别是 4.999999和5.000001,从而使得关系运算“ g二二f”的结果是 0。因此,在判断两个实数是否相等时,应当判断它们之差的绝对值是否小于一个给定的足够小的数。例如,按如下方式比较:fabs(g 书:1e-5的值将为1。其中fabs()是C语言中求实数绝对值的库函数。3.7逻辑运算符和逻辑表达式一个简单的条件可以用一个关系表达式来表示。如果要指定的是一个由几个简单的条件组成的复合条件,例如x 0且x :10、y:0或y .10、a b且x y等等,这就需要用逻辑运算符把

51、它们连接起来组成逻辑表达式。1 .逻辑运算符C语言中的逻辑运算符包括单目逻辑运算符:!逻辑非(相当于其他语言的NOT )和双目逻辑运算符:&&逻辑与(相当于其他语言的AND )II逻辑或(相当于其他语言的OR)逻辑运算符是用来表示操作数的逻辑关系,与关系运算的结果相同,逻辑运算的结果也只有“真”、“假”两个逻辑量。C语言编译系统对于逻辑运算结果,以数值 1代表“真”,以数值0代表“假”。逻辑运算对操作数没有特别的限定,可以是任何数据类型,在判断一个操 作数是否为“真”时,以 0代表“假”,以非0代表“真”。即将一个非0的数值认作为“真”。例如,如果将2、a、12.0或23.1作

52、为逻辑操作数,则都是作为逻辑“真”处理。(1)逻辑非:当操作数的值为假时,对该操作数逻辑非运算的结果为真;当操作数的值为真时,对该操作数逻辑非运算的结果为假。例如,若a=5,b=7,则:!(a b)运算结果为1(真)! a运算结果为0(假)(2)逻辑与:只要两个操作数中有一个操作数的值为0 (假),则逻辑与运算的结果就为0(假)。仅当两个操作数全为非0 (真)时,运算结果才为1 (真)。例如,若a=5, b=7,则:(a :b)&&a运算结果为1 (真)(a b)&&b运算结果为0 (假)(a :b)&&(a :0)运算结果为0 (假)(a b)

53、&&(a :0)运算结果为0 (假)(3)逻辑或:只要两个操作数中有一个操作数的值为非0 (真),则逻辑或运算的结果就为 1(真)。仅当两个操作数全为0 (假)时,运算结果才为0 (假)。例如,若 a=5, b=7,则:(a 岀)| a运算结果为1 (真)(a b) | b运算结果为1 (真)(a <b) | (a :0)运算结果为1 (真)(a <0) | (b :0)运算结果为0 (假)说明:由系统给出的逻辑运算结果只有两个值0(假)和1 (真),不可能是第三者。而逻辑运算中的操作数可以是 0 (假)或任何非 0的数值(按“真”对待)。 逻辑运算的操作数不仅可以是整型,还可以是任意类型,如字符型、实型、指针类型 等。C语言的逻辑运算规则如表3-2所示。表3-2逻辑运算真值表AB!A!BA&&BA | B非0非00011非0001010非01001001100(4)逻辑运算符的优先级:在一个逻辑表达式

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论