《C语言课件谭浩强cha.ppt》由会员分享,可在线阅读,更多相关《C语言课件谭浩强cha.ppt(58页珍藏版)》请在三一办公上搜索。
1、第5章 选择结构程序设计,51 关系运算符和关系表达式关系运算是逻辑运算中比较简单的一种。所谓“关系运算”实际上是“比较运算”。将两个值进行比较,判断比较的结果是否符合给定的条件。例如,a3是一个关系表达式,大于号()是一个关系运算符,如果a的值为5,则满足给定的“a3”条件,因此关系表达式的值为“真”(即“条件满足”);如果a的值为2,不满足“a3”条件,则称关系表达式的值为“假”(即“条件不满足”)。,5.1.1 关系运算符及其优先次序 C语言提供6种关系运算符:(1)(大于)(4)=(大于或等于)(5)=(等于)(6)!=(不等于)关于优先次序:1前4种关系运算符(,)的优先级别相同,后
2、两种也相同。前4种高于后2种。例如,“”优先于“=”。而“”与“”优先级相同。,2关系运算符的优先级低于算术运算符。3.关系运算符的优先级高于赋值运算符。高 低 算术运算符 关系运算符 赋值运算符例如:ca+b 等效于 c(a+b)ab!=c 等效于(ab)!=c a=bc 等效于 a=(bc),运算符 优先级 结合性*,/,%高 左+,-左,=左=,!=左=低 右 运算符的目:参与运算的操作数的个数单目、双目、三目除=外,奇数目运算符右结合性 偶数目运算符左结合性,5.1.2关系表达式用关系运算符将两个表达式(可以是算术表达式或关系表达式、逻辑表达式、赋值表达式、字符表达式)连接起来的式子,
3、称关系表达式。例如,下面都是合法的关系表达式:ab,abbc,(a3)(b=5),ab,(ab)(bc)关系表达式的值是一个逻辑值,即“真”或“假”。例如,关系表达式“5=3”的值为“假”,“5=0”的值为“真”。C语言没有逻辑型数据(Pascal语言以True表示“真”,以Fa1se表示“假”。PASCAL和FORTRAN等语言都有逻辑型变量和逻辑型常量),以1代表“真”,以“0”代表“假”。,例如,若a=3,b=2,c=1,则:ab的值为”真”,表达式的值为1。(ab)=c的值为“真”(因为ab的值为1,等于c的值),表达式的值为1。bca的值为“假”,表达式的值为0。如果有以下赋值表达式
4、:dab d的值为1。fabc f的值为0(因为“”运算符是自左至右的结合方向,先执行“ab”,得值为1,再执行关系运算:“1c”得值0,赋给f,52逻辑运算符和逻辑表达式用逻辑运算符将关系表达式或逻辑量连接起来就是逻辑表达式。下面介绍C语言中的逻辑运算符和逻辑运算。5.2.1逻辑运算符及其优先级C语言提供三种逻辑运算符:1&逻辑与(相当于其它语言中的AND)2|逻辑或(相当于其它语言中的OR)3!逻辑非(相当于其它语言中的NOT)&和|”是“双目(元)运算符”,它要求有两个运算量(操作数),如(ab)&(xy),(ab)|(xy)。“!”是“一目(元)运算符”,只要求有一个运算量,如!(ab
5、)。逻辑运算举例如下:a&b 若a,b为真,则a&b为真。a|b 若a,b之一为真,则a|b为真。!a 若a为真,则!a为假。,下表为逻辑运算的“真值表”。用它表示当a和b的值为不同组合时,各种逻辑运算所得到的值。a b!a!b a&b a|b T T F F T T T F F T F F 在一个逻辑表达式中如果包含多个逻辑运算符,如!a&b|xy&c 优先次序:高 低!算术运算符关系运算符&|赋值运算符!a&b|xy&c((!a)&b)|(xy)&c)(ab)&(xy)可写成:ab&xy(a=b)|(x=y)可写成:a=b|xy(!a)|(ab)可写成:!a|ab,运算符 优先级 结合性!
6、右*,/,%高 左+,-左,=左=,!=左&左|左=低 右,5.2.2逻辑表达式如前所述,逻辑表达式的值应该是一个逻辑量“真”或“假”。C语言编译系统在给出逻辑运算结果时,以数值1代表“真”,以0代表“假”,但在判断一个量是否为“真”时,以0代表“假”,以非0代表“真”。即将一个非零的数值认作为“真”。例如:若a4,则!a的值为0。因为a的值为非0,被认作“真”,对它进行“非”运算,得“假”,“假”以0代表。若a=4,b=5,则a&b的值为1。因为a和b均为非0,被认为是“真”,因此a&b的值也为“真”,值为1。a、b值同前,a|b的值为1。a、b值同前,!a|b的值为1。4&0|2的值为1。
7、,通过这几个例子可以看出,由系统给出的逻辑运算结果不是0就是1,不可能是其它数值。而在逻辑表达式中作为参加逻辑运算的运算对象(操作数)可以是0(“假”)或任何非0的数值(按“真”对待)。如果在一个表达式中不同位置上出现数值,应区分哪些是作为数值运算或关系运算的对象,哪些作为逻辑运算的对象,例如 53&2|84-!0表达式自左至右扫描求解。首先处理“53”(因为关系运算符优先于&)。在关系运算符两侧的5和3作为数值参加关系运算,”53”的值为:1。再进行”1&2”的运算,此时1和2均是逻辑运算对象,均作“真”处理,因此结果为1。再往下进行“1|84-!0”的运算。根据优先次序,先进行“!0”运算
8、得1,因此,要运算的表达式变成:“1|84-1”,即“1|83”,关系运算符“”两侧的8和3作为数值参加比较,“83”的值为0(“假”)。最后得到“1|0”的结果1。,实际上,逻辑运算符两侧的运算对象不但可以是0和1,或者是0和非0的整数,也可以是任何类型的数据。可以是字符型、实型或指针型等。系统最终以0和非0来判定它们属于“真”或“假”。例如 c&d的值为1(因为c和d的Ascii值都不为0,按“真”处理)。在逻辑表达式的求解中,并不是所有的逻辑运算符都被执行,只是在必须执行下一个逻辑运算符才能求出表达式的解时,才执行该运算符(逻辑短路)。例如:1a&b&c 只有a为真(非0)时,才需要判别
9、b的值,只有a和b都为真的情况下才需要判别c的值。只要a为假,就不必判别b和c,(此时整个表达式已确定为假)。如果a为真,b为假,不判别c。,2a|b|c 只要a为真(非0)就不必判别b和c 对&运算符只有a0,才继续进行右面的运算。对|运算符来说,只有a=0才继续进行其右面的运算。因此,如果有下面的逻辑表达式:(mab)&(n=cd)当a=1,b=2,c=3,d=4,m和n的原值为时,由于ab的值为0,m=0,而n=cd不被执行,因此n的值不是0而仍保持原值1。这点请读者注意。熟练掌握C语言的关系运算符和逻辑运算符后,可以巧妙地用一个逻辑表达式来表示一个复杂的条件。,例如,判别某一年year
10、是否闰年。闰年的条件是符合下面二者之一:能被4整除,但不能被100整除。能被4整除,又能彼400整除。可以用一个逻辑表达式来表示:year40&year100!=0|year400=0当year为某一整数值时,上述表达式值为真(1),则year为闰年;否则为非闰年。可以加一个“!”用来判别非闰年:!(year40&year100!=0|year400=0)若表达式值为真(1),year为非闰年。也可以用下面逻辑表达式判别非闰年:(year4!=0)|(year100=0|year400!=0)表达式为真,year为非闰年。请注意表达式中右面的括弧内的不同运算符(,!,&、=)的运算优先次序。,
11、53 if语句if语句是用来判定所给定的条件是否满足,根据判定的结果(真或假)决定执行给出的两种操作之一。5.3.1 if语句的三种形式C语言提供了三种形式的if语句:1if(表达式)语句例如:if(xy)printf(”d”,x);这种if语句的执行过程见图,2if(表达式)语句1 else 语句2 例如:if(xy)printf(”d”,x);else printf(”d”,y);见图,3 if(表达式1)语句1 else if(表达式2)语句2 else if(表达式3)语句3 else if(表达式m)语句m else 语句m+1 流程图,例如。if(number500)cost015
12、;else if(number300)cost=010:else if(number100)cost=0075;else if(number50)cost0.05;else cost0;说明:三种形式的if语句中在if后面都有“表达式”,一般为逻辑表达式或关系表达式。例如,if(a=b&x=y)printf(”a=b,x=y”);系统对表达式的值进行判断,若为0,按“假”处理,若为非0,按“真”处理,执行指定的语句。假如有以下语句:if(3)printf(“ok.”);是合法的,执行结果输出”ok”。因为表达式的值为3,按“真”处理。由此可见,表达式的类型不限于逻辑表达式,可以是任意的数值类型
13、(包括整型、实型、字符型、指针型数据)。例如,下面的语句也是合法的:if(a)printf(”d”,a);执行结果:输出a的AscII码97。,2第二、第三种形式的if语句中,在每个else前面有一分号,整个语句结束处有一分号。例如:if(x0)printf(“%f”,x);else printf(“%f”,-x);这是由于分号是C语句中不可缺少的部分,这个分号是让语句中的内嵌语句所要求的。如果无此分号,则出现语法错误。但应注意,不要误认为上面是两个语句(if语句和else语句)。它们都属于同一个if语句。else子句不能作为语句单独使用,它必须是if语句的一部分,与if配对使用。,3在if和
14、else后面可以只含一个内嵌的操作语句(如上例),也可以有多个操作语句,此时用花括号“”将几个语句括起来成为一个复合语句(如果需要多条语句,必须使用复合语句)。如:if(abcarea=sqrt(s*(s-a)*(s-b)*(s-c));printf(”area6.2f”,area);else printf(”it is not a trilateral”);注意在 外面不需要再加分号。因为 内是一个完整的复合语句,不需另附加分号。,例5.1输入两个实数,按代数值由小到大次序输出这两个数。/*example 5.1 at page 93*/main()float a,b,t;scanf(%f,
15、%f,运行情况如下。输入:3.6,-3.2输出:-320,360,例52输入三个数,按大小顺序输出。main()float a,b,c,t;printf(Input a,b,cn);scanf(%f,%f,%f,运行情况如下:3,7,1 100,300,700,5.3.2语句的嵌套在if语句中又包含一个或多个if语句称为if语句的嵌套。一般形式如下:if()if()语句1 else 语句2 else if()语句3 else 语句4,应当注意if与else的配对关系。从最内层开始,else总是与它上面最近的(未曾配对的)if配对。假如写成:if()if()语句1 else if()语句2 el
16、se 语句3编程序者把else写在与第一个if(外层if)同一列上,希望else与第一个if对应,但实际上else是与第二个if配对,因为它们相距最近。因此最好使内嵌if语句也包含else部分,这样if的数目和else的数目相同,从内层到外层一一对应,不致出错。,如果if与else的数目不一样,为实现程序设计者的企图,可以加花括弧来确定配对关系。例如:if()if()语句1 else 语句2这时if限定了内嵌if语句的范围,因此else与第一个让配对。例53有一函数:-1(x0)编一程序,输入一个x值,输出y值。有以下几种写法,请读者判断哪些是正确的?,程序1:main()int x,y;sc
17、anf(”d”,x);if(x=0)if(x0)y=1;else y=0;else y一1;,程序3:将上述if语句改为:y一1;if(x!=0)if(x0)y1:else y0;程序4:y0;if(x=0)if(x0)y1;else y-1;只有程序1和2是正确的。一般把内嵌的if语句放在外层的else子句中(如程序1那样),这样由于有外层的else相隔,内嵌的else不会和外层的if配对,而只能与内嵌的让配对,从而不致搞混,如像程序3、4那样就容易混淆。,5.3.3条件运算符若if语句中,在表达式为“真”和“假”时,且都只执行一个赋值语句给同一个变量赋值时,可以用简单的条件运算符来处理。例
18、如,若有以下if语句:if(ab)max=a;else maxb;可以用下面的条件运算符(?:)来处理:max(ab)?a:b;其中”(ab)?a:b”是一个“条件表达式”。它是这样执行的。如果(ab)条件为真,则条件表式取值a,否则取值b.条件运算符要求有三个操作对象,称三目(元)运算符。条件表达式的一般形式为表达式1?表达式2:表达式3 它的执行过程见图57。,说明1条件运算符的执行顺序:先求解表达式1,若为非0(真)则求解表达式2,此时表达式2的值就作为整个条件表达式的值。若表达式1的值为0(假),则求解表达式3,表达式3的值就是整个条件表达式的值。max(ab)?a:b执行结果就是将条
19、件表达式的值赋给max,也就是将a和b二者中大者赋给max。2条件运算符优先于赋值运算符,因此上面赋值表达式的求解过程是先求解条件表达式,再将它的值赋给max。条件运算符的优先级别比关系运算符和算术运算符都低。因此,max=(ab)?a:b括号可以不要,可写成 max=ab?a:b如果有 ab?a:b1,相当于ab?a:(b1),而不相当于(ab?a:b)1。,3条件运算符的结合方向为“自右至左”。如果有以下条件表达式:ab?a:cd?c:d相当于 ab?a:(cd?c:d)a=1,b=2,c=3,d4,则条件表达式的值等于4。4条件表达式不能取代一般的if语句,只有在if语句中内嵌的语句为赋
20、值语句(且两个分支都给同一个变量赋值)时才能代替if语句。象下面的if语句就无法用一个条件表达式代替。if(ab)printf(“d”,a);else printf(“d”,b);但可以用下面语句代替:printf(”d”,ab?a:b);即将条件表达式的值输出。,5条件表达式中,表达式1的类型可以与表达式2和表达式3的类型不同。如 x?a:bx是整型变量,若x=0,则条件表达式的值为b。表达式2和表达式3的类型也可以不同,此时条件表达式的值的类型为二者中较高的类型。如 xy?1:1.5如xy值应为1,由于15是实型,比整型高(见第二章27),因此,将1转换成实型值10。,6补充条件运算符如果
21、表达式1不成立,则计算表达式2的值,但并不计算表达式3。如果有以下程序:main()int a=2,b=1,i=3,c;c=ab?2:+i;printf(c=%d,i=%dn,c,i);运行结果为c=2,i=3如果将c=ab?2:+i改为c=ab?2:+i,则运行结果为c=4,i=4,例54输入一个字符,判别它是否大写字母,如果是,将它转换成小写字母;如果不是,不转换。然后输出最后得到的字符。/*example 5.4 at page 98*/main()char ch;scanf(%c,运行结果如下:条件表达式中的(ch32),其中32是小写字母和大写字母ASCII码的差值(请参阅附录1)。
22、,54 switch语句switch语句是多分支选择语句。if语句只有两个分支可供选择,而实际问题中常常需要用到多分支的选择。例如,学生成绩分类(90分以为A等,8089分为B等,7079分为c,等,);人口统计分类(按年龄分为老、中、青、少、儿童);工资统计分类;银行存款分类;等。当然这些都可以用嵌套的让语句来处理,但如果分支较多,则嵌套的if语句层数多,程序冗长而且可读性降低。C语言提供switch语句直接处理多分支选择,它相当于Pascal语言中的case语句。它的一般形式如下:switch(表达式)case常量表达式1:语句1 case常量表达式2:语句2 case常量表达式n:语句n
23、 default:语句n+1,例如,根据考试成绩的等级打印出百分制分数段:switch(grade)case A:printf(“85100n”);case B:printf(“7084n”);case C:printf(“6069n”);case D:printf(“60n”);default:printf(”errorn”);,说明:1switch后面括弧内的“表达式”,可以是整型表达式或字符型表达式,也可以是枚举型数据(见第十章)。对其它类型,原来的C标准是不允许的,而新的ANSI标准允许上述表达式和case常量表达式为任何类型。2当表达式的值与某一个case后面的常量表达式的值相等时,
24、就执行此case后面的语句,若所有的case中的常量表达式的值都没有与表达式的值匹配的,就执行defau1t后面的语句。,3 每一个case的常量表达式的值必须互不相同,否则就会出现互相矛盾的现象(对表达式的同一个值,有两种或多种执行方案)。4各个case的出现次序不影响执行结果。例如,可以先出现caseD:,然后是caseA:5 执行完一个case后面的语句后,流程控制转移到下一个case继续执行。“case常量表达式”只是起语句标号(程序入口)作用,并不是在该处进行条件判断。在执行switch语句时,根据switch后面表达式的值找到匹配的入口标号,就从此标号开始执行下去,不再进行判断。,
25、例如,上面的例子中,若grade的值等于A,则将连续输出:85100 7084 6069 60 error因此,应该在执行一个case分支后,使流程跳出switch结构,即终止switch语句的执行,可以用了个break语句来达到此目的,将上面的switch结构改写如下:switch(grade)caseA:printf(“85100n”);break;caseB:printf(“7084n”);break;caseC:printf(“16069n”);break;caseD:printf(“60n”);break;default printf(“errorn“);,最后一个分支(defaul
26、t)可以不加break语句。如果grade的值为B,则只输出7084。在case后面中虽然包含一个以上执行语句,但可以不必用花括弧括起来,会自动顺序执行本case后面所有的执行语句。当然加上花括弧也可以。6多个case可以共用一组执行语句,如:case A:case B:case C:printf(“60n”);break;grade的值为A、B或C时都执行同一组语句。,55程序举例例55写程序,判某一年是否闰年。判别某一年year是否闰年。闰年的条件是符合下面二者之一:能被4整除,但不能被100整除。能被4整除,又能被400整除。可以用一个逻辑表达式来表示:year40&year100!=0
27、|year400=0当year为某一整数值时,上述表达式值为真(1),则year为闰年;否则为非闰年。以变量Leap代表是否闰年的信息。若闰年,令leap=1。非闰年,leap=0。最后判断leap是否1(真);若是,则输出“闰年”信息。程序如下:,/*example 5.5 at page 101*/main()int year,leap;printf(Input a yearn);scanf(%d,if(leap)printf(%d is,year);else printf(%d is not,year);printf(a leap yearn);/*if(year%4=0*/运行情况如下
28、:1989 1989 is not a leap year 2000 2000 is a leap year,例56 求ax2bxc=0方程的解。有以下几种可能:a=0,不是二次方程。b2一4ac=0,有两个相等实根。b2一4ac0,有两个不等实根。b2一4ac0,有两个共轭复根。程序如下:/*example 5.6 at page 102*/#include math.hmain()float a,b,c,disc,x1,x2,realpart,imagpart,zero=1e-6;printf(Input a,b,cn);scanf(%f,%f,%f,if(fabs(a)zero)/*0*
29、/realpart=-b/(2*a);imagpart=sqrt(-disc)/(2*a);printf(has complex roots:n);printf(%8.4f+%8.4fin,realpart,imagpart);printf(%8.4f-%8.4fin,realpart,imagpart);,程序中用disc代表b2一4ac,先计算disc的值,以减少以后的重复计算。对于判断b2一4ac是否等于0时,要注意一个问题:由于disc(即b2一4ac)是实数,而实数在计算和存储时会有一些微小的误差,因此不能直接进行如下判断:if(disc=0)。因为这样可能会出现本来是零的量,由于上
30、述误差而被判别为不等于零而导致结果错误。所以采取的办法是判别disc的绝对值(fabs(disc)是否小于一个很小的数(例如10-6),如果小于此数,就认为disc=0。程序中以realpart代表实部p,以imagpart代表虚部q,以增加可读性。,习题.()给出一个不多于位的正整数,要求:)求出它是几位数;)分别打印每一位数字;)按逆序打印各位数字思路:分别剥离每一个数字如:剥离成,同时注意高位为空和低位为的情况,解main()int n1,n2,n3,n4,n5,temp,place=0;long num;scanf(“%ld”,解2/*use loop*/#include“math.h
31、”main()int n5,i,temp,place=5;long num;scanf(“%ld”,解3/*use char*/main()char n1,n2,n3,n4,n5;scanf(“%c%c%c%c%c”,解4/*use char and loop*/main()char c5,t;int i,number=0;for(i=0;i=0,练习1设有int i;则表达式i=1,+i|+i;i的值为1)12)23)34)42设有int i;则表达式(i=1,i=10)?i+|+i:+i的值为1)12)23)34)10 5)113设有int i,j,k;则表达式i=1,j=2,k=3,i后
32、i的值为。,5下列程序的输出是1)0032)0123)1034)112main()int a=-1,b=4,k;k=(a+=0)执行后输出结果是 1)1,1,2 2)2,2,1 3)2,2,2 4)2,2,3,7有以下程序(2003上半年)main()int a=5,b=4,c=3,d=2;if(abc)printf(%dn,d);else if(c-1=d)=1)printf(%dn,d+1);elseprintf(%dn,d+2);执行后输出结果是1)2 2)3 3)4 4)编译时有错,无结果,8有以下程序(2003上半年)main()int i;for(i=0;i3;i+)switch(
33、i)case 1:printf(%d,i);case 2:printf(%d,i);default:printf(%d,i);执行后输出结果是 A)011122 B)012 C)012020 D)120,9以下程序运行后的输出结果是。(2003下半年)main()int i,m=0,n=0,k=0;for(i=9;i=11;i+)switch(i/10)case 0:m+;n+;break;case 10:n+;break;default:k+;n+;printf(%d%d%dn,m,n,k);,10执行下面程序段时输出的结果是。int i=5;switch(i)case 5:case 6:i
34、+=2;case 7:break;case 8:i+=2;printf(i=%d,i);,11下面的程序的功能是将学生成绩90分以上输出字符A,8960分输出字符”Pass”,其余输出“Fail”。main()float grade;int sel;scanf(%f,12若有以下定义:float x;int a,b;则正确的switch 语句是A)switch(x)B)switch(x)case1.0:printf(*n);case1,2:printf(*n);case2.0:printf(*n);case3:printf(*n);C)switch(a+b)D)switch(a+b)case 1:printf(*n);case 1:printf(*n);case 1+2:printf(*n);case 2:printf(*n);,