5.1 关系运算符和关系表达式
5.2 逻辑运算符和逻辑表达式
5.3 if语句
5.4 switch语句
5.5 程序举例习题第 5章 选择结构程序设计在第 3章中已介绍了选择结构,它是三种基本结构之一。在大多数程序中都会包含选择结构。它的作用是,根据所指定的条件是否满足,决定从给定的两组操作选择其一。在本章中介绍如何用 c语言实现选择结构。在 c语言中选择结构是用 if语句实现的。 if语句最常用的形式是
if (关系表达式 )语句 1 else 语句 2
例如:
if ( x>0 ) y=1; else y=-1;
其中 x>0是一个关系表达式。,>”是一个关系运算符。
5.1 关系运算符和关系表达式关系运算是逻辑运算中比较简单的一种。所谓“关系运算”实际上是“比较运算”。将两个值进行比较,判断其比较的结果是否符合给定的条件。例如,
a> 3是一个关系表达式,大于号 (> )是一个关系运算符,如果 a的值为 5,则满足给定的,a> 3”条件,
因此关系表达式的值为“真” (即“条件满足” );
如果 a的值为 2,不满足,a> 3”条件,则称关系表达式的值为“假”。
5.1.1 关系运算符及其优先次序
C语言提供 6种关系运算符:
优先级相同 (高 ):
① < (小于 )
② < =(小于或等于 )
③ > (大于 )
④ > =(大于或等于 )
优先级相同 (低 ):
⑤ = = (等于 )
⑥ !=(不等于 )
关于优先次序:
(1) 前 4种关系运算符 (<,< =,>,> =)的优先级别相同,后两种也相同。前 4种高于后 2种。例如,“>”优先于,==”。
而“>”与“<”优先级相同。
(2) 关系运算符的优先级低于算术运算符。
(3) 关系运算符的优先级高于赋值运算符。
以上关系见图 5.1。
例如:
c> a+ b 等效于 c> (a+ b)
a> b==c 等效于 (a> b)==c
a==b< c 等效于 a==(b< c)
a=b> c 等效于 a=(b> c)
图 5.1
5.1.2 关系表达式用关系运算符将两个表达式 (可以是算术表达式或关系表达式、逻辑表达式、赋值表达式、字符表达式 )连接起来的式子,称关系表达式。
例如,下面都是合法的关系表达式:
a> b,a+ b> b+ c,(a=3)> (b=5),'a'<
'b',(a> b)> (b< c)
关系表达式的值是一个逻辑值,即“真”或
“假”。例如,关系表达式,5==3”的值为“假”,
,5> =0”的值为“真”。 c语言没有逻辑型数据
(Pascal语言以 True表示“真”,以 false表示
“假”。 PascaL和 FORTRAN等语言都有逻辑型变量和逻辑型常量 ),以 1代表“真”,以,0”代表“假”。例如,
a=3,b=2,c=1,则:
关系表达式,a> b”的值为“真”,表达式的值为 1。
关系表达式,(a> b)==c”的值为“真” (因为 a> b的值为 1,等于 c的值 ),表达式的值为 1。
关系表达式,b+ c< a”的值为“假”,表达式的值为 0。
如果有以下赋值表达式:
d=a> bd的值为 1。
f=a> b> cf的值为 0 (因为“>”运算符是自左至右的结合方向,先执行,a> b”得值为 1,再执行关系运算,1> c”,得值 0,赋给 f)。
用逻辑运算符将关系表达式或逻辑量连接起来的式子就是逻辑表达式。在 basic和 Pascal语言中有以下形式的逻辑表达式 (AND是逻辑运算符 ):
(a> b)AND(x> y)
如果 a> b且 x> y,则上述逻辑表达式的值为
“真”。下面介绍 c语言中的逻辑运算符和逻辑运算。
5.2.1 逻辑运算符及其优先次序
C语言提供三种逻辑运算符:
5.2 逻辑运算符和逻辑表达式
(1) &&逻辑与 (相当于其他语言中的 aND)
(2) || 逻辑或 (相当于其他语言中的OR )
(3) ! 逻辑非 (相当于其他语言中的 NO T)
“&&”和,||”是“双目 (元 )运算符”,它要求有两个运算量 (操作数 ),如 (a> b)&&(x> y),(a> b)||(x>
y)。,!”是“一目 (元 )运算符”,只要求有一个运算量,如 (a> b)。
逻辑运算举例如下:
a&&b若 a,b为真,则 a&&b为真。
a||b 若 a,b之一为真,则 a||b为真。
!a 若 a为真,则 !a为假。
在一个逻辑表达式中如果包含多个逻辑运算符,如
!a && b||x> y && c
按以下的优先次序:
(1) !(非 )→&&( 与 )→( 或 ),即,!”为三者中最高的。
(2) 逻辑运算符中的,&&”和,||”低于关系运算符,
,!”高于算术运算符。见图 5.2。
图 5.2
例如:
(a> b) && (x> y)可写成 a> b && x> y
(a==b)||(x==y) 可写成 a==b||x==y
(!a)||(a> b) 可写成 !a||a> b
5.2.2 逻辑表达式如前所述,逻辑表达式的值应该是一个逻辑量“真”
或“假”。 c语言编译系统在给出逻辑运算结果时,
以数值 1代表“真”,以 0代表“假”,但在判断一个量是否为“真”时,以 0代表“假”,以非 0
代表“真”。即将一个非零的数值认作为“真”。
例如:
(1) 若 a=4,则 !a的值为 0。因为 a的值为非 0,被认作
“真”,对它进行“非”运算,得“假”,“假”
以 0代表。
(2) 若 a=4,b=5,则 a&&b的值为 1。因为 a和 b均为非 0,被认为是“真”,因此 a&&b的值也为
“真”,值为 1。
(3) a,b值同前,a||b的值为 1。
(4) a,b值同前,!a||b的值为 1。
(5) 4&&0||2的值为 1。
通过这几个例子可以看出,由系统给出的逻辑运算结果不是 0就是 1,不可能是其他数值。而在逻辑表达式中作为参加逻辑运算的运算对象 (操作数 )
可以是 0(“假” )或任何非 0的数值 (按“真”对待 )。如果在一个表达式中不同位置上出现数值,应区分哪些是作为数值运算或关系运算的对象,哪些作为逻辑运算的对象。例如,
5> 3 && 8< 4-!0
表达式自左至右扫描求解。首先处理,5> 3”(因为关系运算符优先于 &&)。在关系运算符两侧的 5和 3作为数值参加关系运算,,5> 3”的值为 1。再进行
,1&&8<4-!0”的运算,8的左侧为,&&”,右侧为,<”
运算符,根据优先规则,应先进行,<”的运算,即先进行,8<4-!0”的运算。现在 4的左侧为,<”,右侧为
,-”运算符,而,-”优先于,<”,因此应先进行,4-!0”
的运算,由于,!”的级别最高,因此先进行,!0”的运算,得到结果 1。然后进行,4-1”的运算,得结果 3,
再进行,8<3”的运算,得 0,最后进行,1&&0”的运算,得 0。
实际上,逻辑运算符两侧的运算对象不但可以是 0和
1,或者是 0和非 0的整数,也可以是任何类型的数据。可以是字符型、实型或指针型等。系统最终以
0和非 0来判定它们属于“真”或“假”。例如
'c' && 'd'
的值为 1(因为‘ c?和‘ d?的 ascII值都不为 0,按“真”
处理 )。
在逻辑表达式的求解中,并不是所有的逻辑运算符都被执行,只是在必须执行下一个逻辑运算符才能求出表达式的解时,才执行该运算符。例如:
(1) a && b && c只有 a为真 (非 0)时,才需要判别 b的值,
只有 a和 b都为真的情况下才需要判别 c的值。只要 a为假,就不必判别 b和 c(此时整个表达式已确定为假 )。
如果 a为真,b为假,不判别 c。见图 5.3。
(2) a||b||c只要 a为真 (非 0),就不必判断 b和 c;只有 a为假,
才判别 b; a和 b都为假才判别 c。见图 5.4。
图 5.3 图 5.4
也就是说,对 &&运算符来说,只有 a≠0,才继续进行右面的运算。对运算符 ‖ 来说,只有 a=0,才继续进行其右面的运算。因此,如果有下面的逻辑表达式:
(m=a> b) && (n=c> d)
当 a=1,b=2,c=3,d=4,m和 n的原值为 1时,由于
,a> b”的值为 0,因此 m=0,而,n=c> d”不被执行,因此 n的值不是 0而仍保持原值 1。这点请读者注意。
熟练掌握 c语言的关系运算符和逻辑运算符后,可以巧妙地用一个逻辑表达式来表示一个复杂的条件。
例如,要判别某一年 year是否闰年。闰年的条件是符合下面二者之一:
①能被 4整除,但不能被 100整除。②能被 4整除,又能被 400整除。
可以用一个逻辑表达式来表示:
(year% 4==0 && year% 100!=0)||year%
400==0
当 year为某一整数值时,如果上述表达式值为真 (1),
则 year为闰年;否则 year为非闰年。
可以加一个,!”用来判别非闰年:
!((year% 4==0 && year% 100!=0)||year% 400==0)
若表达式值为真 (1),year为非闰年。也可以用下面逻辑表达式判别非闰年:
(year% 4!=0)||(year% 100==0 && year% 400!=0)
若表达式值为真,year为非闰年。请注意表达式中右面的括弧内的不同运算符 (%,!,&&0,==)的运算优先次序。
5.3 if语句
if语句是用来判定所给定的条件是否满足,根据判定的结果 (真或假 )决定执行给出的两种操作之一。
5.3.1 if语句的三种形式
C语言提供了三种形式的 if语句:
1,if(表达式 ) 语句例如:
if(x> y) printf("% d",x);
这种 if语句的执行过程见图 5.5(a)。
2,if(表达式 )语句 1 else语句 2
例如,if (x> y) printf("% d",x);
else printf("% d",y);见图 5.5(b)。
图 5.5
3,if(表达式 1) 语句 1
else if(表达式 2)语句 2
else if(表达式 3) 语句 3
…
else if(表达式 m) 语句 m
else语句 n
流程图见图 5.6。
图 5.6
例如:
if(number>500)cost=0.15;
else if(number>300)cost=0.10;
else if(number>100)cost=0.075;
else if(number>50)cost=0.05;
elsecost=0;
说明:
(1) 三种形式的 if语句中在 if后面都有“表达式”,一般为逻辑表达式或关系表达式。例如,if(a==b &&
x==y)printf(“a=b,x=y”);在执行 if语句时先对表达式求解,
若表达式的值为 0,按“假”处理,若表达式的值为非 0,
按“真”处理,执行指定的语句。假如有以下 if语句:
if(3) printf("O,k,");
是合法的,执行结果输出“O,k.”,因为表达式的值为 3,按“真”处理。由此可见,表达式的类型不限于逻辑表达式,可以是任意的数值类型 (包括整型、实型、字符型、指针型数据 )。例如,下面的 if语句也是合法的:
if('a') printf("% d",'a');
执行结果:输出‘ a?的 ASCII码 97。
(2) 第二、第三种形式的 if语句中,在每个 else前面有一分号,整个语句结束处有一分号。例如:
if (x>0)
Print ("%f",x);
else 各有一个分号
printf("%f",-x);
这是由于分号是 c语句中不可缺少的部分,这个分号是 if语句中的内嵌语句所要求的。如果无此分号,
则出现语法错误。但应注意,不要误认为上面是两个语句 (if语句和 else语句 )。它们都属于同一个 if语句。 else子句不能作为语句单独使用,它必须是 if
语句的一部分,与 if配对使用。
(3) 在 if和 else后面可以只含一个内嵌的操作语句 (如上例 ),也可以有多个操作语句,此时用花括号
“{}”将几个语句括起来成为一个复合语句。
如:
if (a+ b>c && b+ c> a && c+ a> b)
{ s=0.5*(a+b+c); area=sqrt(S*(S-a)*(S-b)*(S-c));
printf("area=% 6,2f",area);}
else printf("it is not a trilateral");
注意在第 3行的花括号“}”外面不需要再加分号。
因为{}内是一个完整的复合语句,不需另附加分号。
例 5.1输入两个实数,按代数值由小到大的次序输出这两个数。
这个问题的算法很简单,只需要作一次比较即可。
对类似这样简单的问题可以不必先写出算法或画流程图,而直接编写程序。或者说,算法在编程者的脑子里,相当于在算术运算中对简单的问题可以“心算”而不必在纸上写出来一样。
程序如下:
main()
{
float a,b,t;
scanf("% f,% f",&a,&b);
if(a> b)
{ t=a; a=b; b=t;}
printf("% 5,2f,% 5,2f",a,b);
}
运行情况如下:
3.6,-3.2
-3.20,3.60
例 5.2输入 3个数 a,b,c,要求按由小到大的顺序输出。解此题的算法比上一题稍复杂一些。可以用伪代码写出算法:
if a > b 将 a和 b对换 (a是 a,b中的小者 )
if a > c 将 a和 c对换 (a是 a,c中的小者,因此 a是三者中最小者 )
if b > c 将 b和 c对换 (b是 b,c中的小者,也是三者中次小者 )
然后顺序输出 a,b,c即可。
按此算法编写程序:
main()
{
float a,b,c,t;
scanf("% f,% f,% f",&a,&b,&c);
if(a> b)
t=a; a=b; b=t;} /* 实现 a和 b的互换 */
if(a> c)
t=a; a=c; c=t;} /* 实现 a和 c的互换 */
if(b> c)
{ t=b; b=c; c=t;} /* 实现 b和 c的互换 */
printf("% 5,2f,% 5,2f,% 5,2f",a,b,
c);
}
运行情况如下:
3,7,1
1.00,3.00,7.00
5.3.2 if语句的嵌套在 if语句中又包含一个或多个 if语句称为 if语句的嵌套。一般形式如下:
if()
if()语句 1
else语句 2内嵌 if
else
if()语句 3
else语句 4内嵌 if
应当注意 if与 else的配对关系。 else总是与它上面的最近的
if配对。假如写成,
if()
if()语句 1
else
if()语句 2
else 语句 3内嵌 if
编程序者把 else写在与第一个 if(外层 if)同一列上,希望 else
与第一个 if对应,但实际上 else是与第二个 if配对,因为它们相距最近。因此最好使内嵌 if语句也包含 else部分 (如本节 (5.3.2节 )最早列出的形式 ),这样 if的数目和 else的数目相同,从内层到外层一一对应,不致出错。
如果 if与 else的数目不一样,为实现程序设计者的企图,
可以加花括弧来确定配对关系。例如,
if()
{ if ()语句 1}
else语句 2(内嵌 if)
这时 { }限定了内嵌 if语句的范围,因此 else与第一个 if
配对。
例 5.3有一函数,
y=-1(x<0)
0(x=0)
1(x>0)
编一程序,输入一个 x值,输出 y值。
可以先写出算法:
输入 x
若 x < 0y =-1;若 x = 0y = 0;若 x > 0y = 1
输出 y或输入 x
若 x < 0y = -1
否则:
若 x = 0y = 0;若 x > 0y = 1
输出 y。也可以用流程图表示,见图 5.7。
图 5.7
有以下几个程序,请读者判断哪个是正确的?
程序 1:
main()
{ int x,y;
scanf("% d",&x);
if(x< 0)y=-1;
else if(x==0) y=0;
else y=1;
printf("x=% d,y=% d\ n",x,y);
}
程序 2,将上面程序的 if语句 (第 4~ 6行 )改为:
if (x> =0)
if (x> 0)y= 1;
else
y= 0;
else y=-1;
程序 3,将上述 if语句改为:
y=-1;
if(x!=0)
if(x> 0) y=1;
else y=0;
程序 4:
y=0;
if(x> =0)
if(x> 0) y=1;
else y=-1;
图 5.8
只有程序 1和程序 2是正确的。程序 1体现了图 5.7的流程,显然它是正确的。程序 2的流程图见图 5.8。它也能实现题目的要求。程序 3的流程图见图 5.9。程序 4的流程图见图 5.10。它们不能实现题目的要求。
请注意程序中的 else与 if的配对关系。例如程序 3中的 else子句是和它上一行的内嵌的 if语句配对,而不与笫 2行的 if语句配对。为了使逻辑关系清晰,
避免出错,一般把内嵌的 if语句放在外层的 else子句中 (如程序 1那样 ),这样由于有外层的 else相隔,
内嵌的 else不会被误认为和外层的 if配对,而只能与内嵌的 if配对,这样就不会搞混,如像程序 3和程序 4那样写就很容易出错。
图 5.9? 图 5.10
5.3.3 条件运算符若 if语句中,在表达式为“真”和“假”时,且都只执行一个赋值语句给同一个变量赋值时,可以用简单的条件运算符来处理。例如,若有以下 if语句:
if (a> b) max=a;
else max=b;
可以用下面的条件运算符来处理:
max=(a> b)? a∶ b;
其中,(a> b)? a∶ b”是一个“条件表达式”。它是这样执行的:如果 (a> b)条件为真,则条件表达式取值 a,否则取值 b。
条件运算符要求有 3个操作对象,称三目 (元 )运算符,
它是 c语言中唯一的一个三目运算符。条件表达式的一般形式为图 5.11表达式 1?表达式 2∶ 表达式 3。
它的执行过程见图 5.11。
图 5.11
说明:
(1) 条件运算符的执行顺序:先求解表达式 1,若为非 0(真 )则求解表达式 2,此时表达式 2的值就作为整个条件表达式的值。若表达式 1的值为 0(假 ),则求解表达式 3,表达式 3的值就是整个条件表达式的值。
max=(a> b)? a∶ b
执行结果就是将条件表达式的值赋给 max。也就是将 a和 b二者中大者赋给 max。
(2) 条件运算符优先于赋值运算符,因此上面赋值表达式的求解过程是先求解条件表达式,再将它的值赋给 max。
条件运算符的优先级别比关系运算符和算术运算符都低。因此
max=(a> b)? a∶ b
括号可以不要,可写成
max=a> b? a∶ b
如果有
a> b? a∶ b+ 1
相当于 a> b? a∶ (b+ 1),而不相当于 (a> b? a∶ b)
+ 1。
(3) 条件运算符的结合方向为“自右至左”。如果有以下条件表达式,a> b? a∶ c> d? c∶ d相当于 a
> b? a∶ (c> d? c∶ d)
如果 a=1,b=2,c=3,d=4,则条件表达式的值等于
4。
(4) 条件表达式不能取代一般的 if语句,只有在 if语句中内嵌的语句为赋值语句 (且两个分支都给同一个变量赋值 )时才能代替 if语句。像下面的 if语句就无法用一个条件表达式代替。
if(a> b) printf("% d",a);
else printf("% d",b);
但可以用下面语句代替:
printf("% d",a> b? a∶ b);
即将条件表达式的值输出。
(5) 条件表达式中,表达式 1的类型可以与表达式 2和表达式 3的类型不同。如 x? 'a'∶ 'b'
x是整型变量,若 x=0,则条件表达式的值为 'b'。表达式 2和表达式 3的类型也可以不同,此时条件表达式的值的类型为二者中较高的类型。如
x> y? 1∶ 1,5
如果 x≤y,则条件表达式的值为 1,5,若 x> y,值应为 1,由于 1,5是实型,比整型高 (见第 3章 3,7),
因此,将 1转换成实型值 1.0。
例 5.4输入一个字符,判别它是否大写字母,如果是,
将它转换成小写字母;如果不是,不转换。然后输出最后得到的字符。
关于大小写字母之间的转换方法,在本书例 3.7中已做了介绍,因此可直接编写程序:
main()
{ charch;
scanf("% c",& ch);
ch=(ch> ='a' && ch< =?Z')? (ch+ 32)∶ ch;
printf("% c",ch)
}
运行结果如下:
a
a
条件表达式中的 (ch+ 32),其中 32是小写字母和大写字母 ASCII码的差值。
5.4 Switch 语 句
Switch语句是多分支选择语句。用来实现如图 3.6所表示的多分支选择结构。 if语句只有两个分支可供选择,而实际问题中常常需要用到多分支的选择。
例如,学生成绩分类 (90分以上为‘ a?等,80~ 89
分为‘ b?等,70~ 79分为‘ c?等 ……) ;人口统计分类 (按年龄分为老、中、青、少、儿童 );工资统计分类;银行存款分类 …… 。
当然这些都可以用嵌套的 if语句来处理,但如果分支较多,则嵌套的 if语句层数多,程序冗长而且可读性降低。 c语言提供 Switch语句直接处理多分支选择,它相当于 Pascal语言中的 case语句。它的一般形式如下:
switch(表达式 )
{ case 常量表达式 1:语句 1
case 常量表达式 2:语句 2
…
case 常量表达式 n:语句 n
default,语句 n+ 1
}
例如,要求按照考试成绩的等级打印出百分制分数段,可以用 Switch语句实现:
Switch(grade)
{ case 'a'∶ printf("85~ 100\ n");
case 'b'∶ printf("70~ 84\ n");
case 'c'∶ printf("60~ 69\ n");
case 'D'∶ printf("< 60\ n");
default∶ printf("error\ n");
}
说明:
(1) switch后面括弧内的“表达式”,ANSI标准允许它为任何类型。
(2) 当表达式的值与某一个 case后面的常量表达式的值相等时,就执行此 case后面的语句,若所有的 case
中的常量表达式的值都没有与表达式的值匹配的,
就执行 default后面的语句。
(3) 每一个 case的常量表达式的值必须互不相同,否则就会出现互相矛盾的现象 (对表达式的同一个值,
有两种或多种执行方案 )。
(4) 各个 case和 default的出现次序不影响执行结果。
例如,可以先出现,default,…”,再出现,case
D?,…”,然后是,case?a?,…” 。
(5) 执行完一个 case后面的语句后,流程控制转移到下一个 case继续执行。,case常量表达式”只是起语句标号作用,并不是在该处进行条件判断。在执行 Switch语句时,根据 Switch后面表达式的值找到匹配的入口标号,就从此标号开始执行下去,
不再进行判断。例如,上面的例子中,若 grade的值等于‘ a?,则将连续输出:
85~ 100
70~ 84
60~ 69
< 60
error
因此,应该在执行一个 case分支后,使流程跳出
Switch结构,即终止 Switch语句的执行。可以用一个 break语句来达到此目的。将上面的 Switch结构改写如下:
Switch(grade)
{ case 'a'∶ printf("85~ 100\ n"); break;
case 'b'∶ printf("70~ 84\ n"); break;
case 'c'∶ printf("60~ 69\ n"); break;
case 'D'∶ printf("< 60\ n"); break;
default ∶ printf("error\ n");
}
最后一个分支 (default)可以不加 break语句。 如果
grade的值为‘ b?,则只输出,70~ 84”。流程图见图 5.12。
图 5.12
在 case后面中虽然包含一个以上执行语句,但可以不必用花括弧括起来,会自动顺序执行本 case后面所有的执行语句。当然加上花括弧也可以。
(6) 多个 case可以共用一组执行语句,如:
…
case 'a'∶
case 'b'∶
case 'c'∶ printf("> 60\ n"); break;
…
grade的值为‘ a?、‘ b?或‘ c?时都执行同一组语句。
5.5 程序举例例 5.5写程序,判断某一年是否闰年。
我们用图 5.13来表示判别闰年的算法。以变量 leap代表是否闰年的信息。若某年为闰年,则令 leap=1;
若为非闰年,令 leap=0。最后判断 leap是否为
1(真 ),若是,则输出“闰年”信息。
图 5.13
据此编写程序如下:
main()
{
int year,leap;
scanf("% d",&year);
if (year% 4==0)
{ if (year% 100==0)
{ if (year% 400==0)
leap=1;
else leap=0;}
else
leap=1;}
else
leap=0;
if (leap)
printf("% d is ",year);
else
printf("% d is not ",year);
printf("a leap year.\ n");
}
运行情况如下:
① 1989
1989 is not a leap year.
② 2000
2000 is a leap year.
也可以将程序中第 5~ 13行改写成以下的 if语句:
if(year% 4!=0)
leap=0;
else if(year% 100!=0)
leap=1;
else if(year% 400!=0)
leap=0;
else
leap=1;
也可以用一个逻辑表达式包含所有的闰年条件,将上述 if语句用下面的 if语句代替:
if((year%4==0 && year%100!=0) || (year%400==0))
leap=1;
else leap=0;
例 5.6求 ax2+ bx+ c=0方程的解。
例 4.12曾介绍过基本的算法,实际上应该有以下几种可能:
① a=0,不是二次方程。
② b2-4ac=0,有两个相等实根。
③ b2-4ac> 0,有两个不等实根。
④ b2-4ac< 0,有两个共轭复根。
画出 N S流程图表示算法 (图 5.14)。
图 5.14
据此编写程序如下:
#include<math,h>
main()
{ float a,b,c,d,disc,x1,x2,realpart,
imagpart;
scanf("% f,% f,% f",&a,&b,&c);
printf("The equation");
if(fabs(a)< =le-6)
printf("is not a quadratic");
else
{disc=b*b-4*a*c;
if(fabs(disc)< =le-6)
printf("has two equal roots:%8.4\ n",-b
/ (2*a));
else if(disc> le-6)
{ x1=(-b+ sqrt(disc))/ (2*a);
x2=(-b-sqrt(disc))/ (2*a);
printf("has distinct real roots:%8.4f and
%8.4f\ n",x1,x2);
}
else
{ realpart=-b/ (2*a);
imagpart=sqrt(-disc)/ (2*a);
printf("has comPlex roots∶ \ n");
printf("%8.4f+%8.4fi\ n",realpart,
imagpart);
printf("%8.4f-%8.4fi\ n",realpart,
imagpart);
} }
}
程序中用 disc代表 b2-4ac,先计算 disc的值,以减少以后的重复计算。对于判断 b2-4ac是否等于 0时,
要注意一个问题:由于 disc(即 b2-4ac)是实数,而实数在计算和存储时会有一些微小的误差,
因此不能直接进行如下判断,if(disc==0)…… 因为这样可能会出现本来是零的量,由于上述误差而被判别为不等于零而导致结果错误。所以采取的办法是判别 disc的绝对值 (fabs(disc))是否小于一个很小的数 (例如 10-6),如果小于此数,就认为
disc=0。程序中以 realpart代表实部 P,以 imagpart
代表虚部 q,以增加可读性。
运行结果如下:
① 1,2,1
The equation has two equalroots∶ -1,0000
② 1,2,2
The equation has complex roots:
-1,0000+ 1,0000i
-1,0000-1,0000i
③ 2,6,1
The equation has distinct real roots:-0.1771
and =2.8229
例 5.7运输公司对用户计算运费。路程 (S)越远,每公里运费越低。标准如下:
s< 250km没有折扣
250≤S< 500 2%折扣
500≤S< 1000 5%折扣
1000≤S< 2000 8%折扣
2000≤S< 3000 10%折扣
3000≤S 15%折扣设每公里每吨货物的基本运费为 P(Price的缩写 ),货物重为 w(weight的缩写 ),距离为 S,折扣为
d(discount的缩写 ),则总运费 f(freight的缩写 )的计算公式为 f=P*w*S*(1-d)分析此问题,折扣的变化是有规律的:从图 5.15可以看到,折扣的“变化点”都是 250的倍数 (250,500,1000,2000,
3000)。利用这一特点,可以在横轴上加一种坐标
c,c的值为 S/250。 c代表 250的倍数。当 c<1时,表示 S<250,无折扣; 1≤c< 2时,表示 250≤S<500,
折扣 d=2%; 2≤c< 4时,d=5%; 4≤c< 8时,d=8
%; 8≤c< 12时,d=10%; c≥12时,d=15%。
图 5.15
据此写出程序如下:
main()
{
int c,S;
float P,w,d,f;
scanf("% f,% f,% d",&P,&w,&S);
if(S> =3000) c=12;
else c=S/ 250;
switch(c)
{
case0∶ d=0; break;
case1∶ d=2; break;
case2∶
case3∶ d=5; break;
case4∶
case5∶
case6∶
case7∶ d=8; break;
case8∶
case9∶
case10∶
case11∶ d=10; break;
case12∶ d=15; break;
}
f=P*w*S*(1-d/ 100,0);
printf("freight=% 15,4f",f);
}
运行情况如下:
100,20,300
freight= 588000.0000
请注意,c,S是整型变量,因此 c=S/ 250为整数。
当 S≥3000时,令 c=12,而不使 c随 S增大,这是为了在 Switch语句中便于处理,用一个 case可以处理所有 S≥3000的情况。
习题
5.1 什么是算术运算?什么是关系运算?什么是逻辑运算?
5.2 C语言中如何表示“真”和“假”?系统如何判断一个量的“真”和“假”?
5.3 写出下面各逻辑表达式的值。设 a=3,b=4,c=5。
(1) a+ b> c && b==c
(2) a||b+ c && b-c
(3) !(a> b) && !c||1
(4) !(x=a) && (y=b) && 0
(5) !(a+ b)+ c-1 && b+ c/ 2
5.4 有 3个整数 a,b,c,由键盘输入,输出其中最大的数。
5.5 有一函数:
x (x< 1)
y = 2x-1 (1≤x< 10)
3x-11 (x≥10)
写一程序,输入 x,输出 y值。
5.6 给一个不多于 5位的正整数,要求:①求出它是几位数;②分别打印出每一位数字;③按逆序打印出各位数字,例如原数为 321,应输出 123。
图 5.16
5.7 企业发放的奖金根据利润提成。利润 I低于或等于 10万元的,奖金可提 10%;利润高于 10万元,低于 20万元 (100000< I≤200000)时,低于 10万元的部分按 10%提成,高于 100000元的部分,可提成 7,5
%; 200000< I≤400000时,低于 20万的部分仍按上述办法提成 (下同 )。高于 20万元的部职?%提成;
400000< I≤600000时,高于 40万元的部分按 3%提成;
600000< I≤1000000时,高于 60万的部分按 1,5%提成; I> 1000000时,超过 100万元的部分按 1%提成。
从键盘输入当月利润 I,求应发奖金总数。
要求,(1)用 if语句编程序; (2)用 Switch语句编程序。
5.8 有 4个圆塔,圆心分别为 (2,2),(-2,2),(-2,-
2),(2,-2),圆半径为 1。见图 5.16。这 4个塔的高度为 10m,塔以外无建筑物。今输入任一点的坐标,
求该点的建筑高度 (塔外的高度为零 )。
5.2 逻辑运算符和逻辑表达式
5.3 if语句
5.4 switch语句
5.5 程序举例习题第 5章 选择结构程序设计在第 3章中已介绍了选择结构,它是三种基本结构之一。在大多数程序中都会包含选择结构。它的作用是,根据所指定的条件是否满足,决定从给定的两组操作选择其一。在本章中介绍如何用 c语言实现选择结构。在 c语言中选择结构是用 if语句实现的。 if语句最常用的形式是
if (关系表达式 )语句 1 else 语句 2
例如:
if ( x>0 ) y=1; else y=-1;
其中 x>0是一个关系表达式。,>”是一个关系运算符。
5.1 关系运算符和关系表达式关系运算是逻辑运算中比较简单的一种。所谓“关系运算”实际上是“比较运算”。将两个值进行比较,判断其比较的结果是否符合给定的条件。例如,
a> 3是一个关系表达式,大于号 (> )是一个关系运算符,如果 a的值为 5,则满足给定的,a> 3”条件,
因此关系表达式的值为“真” (即“条件满足” );
如果 a的值为 2,不满足,a> 3”条件,则称关系表达式的值为“假”。
5.1.1 关系运算符及其优先次序
C语言提供 6种关系运算符:
优先级相同 (高 ):
① < (小于 )
② < =(小于或等于 )
③ > (大于 )
④ > =(大于或等于 )
优先级相同 (低 ):
⑤ = = (等于 )
⑥ !=(不等于 )
关于优先次序:
(1) 前 4种关系运算符 (<,< =,>,> =)的优先级别相同,后两种也相同。前 4种高于后 2种。例如,“>”优先于,==”。
而“>”与“<”优先级相同。
(2) 关系运算符的优先级低于算术运算符。
(3) 关系运算符的优先级高于赋值运算符。
以上关系见图 5.1。
例如:
c> a+ b 等效于 c> (a+ b)
a> b==c 等效于 (a> b)==c
a==b< c 等效于 a==(b< c)
a=b> c 等效于 a=(b> c)
图 5.1
5.1.2 关系表达式用关系运算符将两个表达式 (可以是算术表达式或关系表达式、逻辑表达式、赋值表达式、字符表达式 )连接起来的式子,称关系表达式。
例如,下面都是合法的关系表达式:
a> b,a+ b> b+ c,(a=3)> (b=5),'a'<
'b',(a> b)> (b< c)
关系表达式的值是一个逻辑值,即“真”或
“假”。例如,关系表达式,5==3”的值为“假”,
,5> =0”的值为“真”。 c语言没有逻辑型数据
(Pascal语言以 True表示“真”,以 false表示
“假”。 PascaL和 FORTRAN等语言都有逻辑型变量和逻辑型常量 ),以 1代表“真”,以,0”代表“假”。例如,
a=3,b=2,c=1,则:
关系表达式,a> b”的值为“真”,表达式的值为 1。
关系表达式,(a> b)==c”的值为“真” (因为 a> b的值为 1,等于 c的值 ),表达式的值为 1。
关系表达式,b+ c< a”的值为“假”,表达式的值为 0。
如果有以下赋值表达式:
d=a> bd的值为 1。
f=a> b> cf的值为 0 (因为“>”运算符是自左至右的结合方向,先执行,a> b”得值为 1,再执行关系运算,1> c”,得值 0,赋给 f)。
用逻辑运算符将关系表达式或逻辑量连接起来的式子就是逻辑表达式。在 basic和 Pascal语言中有以下形式的逻辑表达式 (AND是逻辑运算符 ):
(a> b)AND(x> y)
如果 a> b且 x> y,则上述逻辑表达式的值为
“真”。下面介绍 c语言中的逻辑运算符和逻辑运算。
5.2.1 逻辑运算符及其优先次序
C语言提供三种逻辑运算符:
5.2 逻辑运算符和逻辑表达式
(1) &&逻辑与 (相当于其他语言中的 aND)
(2) || 逻辑或 (相当于其他语言中的OR )
(3) ! 逻辑非 (相当于其他语言中的 NO T)
“&&”和,||”是“双目 (元 )运算符”,它要求有两个运算量 (操作数 ),如 (a> b)&&(x> y),(a> b)||(x>
y)。,!”是“一目 (元 )运算符”,只要求有一个运算量,如 (a> b)。
逻辑运算举例如下:
a&&b若 a,b为真,则 a&&b为真。
a||b 若 a,b之一为真,则 a||b为真。
!a 若 a为真,则 !a为假。
在一个逻辑表达式中如果包含多个逻辑运算符,如
!a && b||x> y && c
按以下的优先次序:
(1) !(非 )→&&( 与 )→( 或 ),即,!”为三者中最高的。
(2) 逻辑运算符中的,&&”和,||”低于关系运算符,
,!”高于算术运算符。见图 5.2。
图 5.2
例如:
(a> b) && (x> y)可写成 a> b && x> y
(a==b)||(x==y) 可写成 a==b||x==y
(!a)||(a> b) 可写成 !a||a> b
5.2.2 逻辑表达式如前所述,逻辑表达式的值应该是一个逻辑量“真”
或“假”。 c语言编译系统在给出逻辑运算结果时,
以数值 1代表“真”,以 0代表“假”,但在判断一个量是否为“真”时,以 0代表“假”,以非 0
代表“真”。即将一个非零的数值认作为“真”。
例如:
(1) 若 a=4,则 !a的值为 0。因为 a的值为非 0,被认作
“真”,对它进行“非”运算,得“假”,“假”
以 0代表。
(2) 若 a=4,b=5,则 a&&b的值为 1。因为 a和 b均为非 0,被认为是“真”,因此 a&&b的值也为
“真”,值为 1。
(3) a,b值同前,a||b的值为 1。
(4) a,b值同前,!a||b的值为 1。
(5) 4&&0||2的值为 1。
通过这几个例子可以看出,由系统给出的逻辑运算结果不是 0就是 1,不可能是其他数值。而在逻辑表达式中作为参加逻辑运算的运算对象 (操作数 )
可以是 0(“假” )或任何非 0的数值 (按“真”对待 )。如果在一个表达式中不同位置上出现数值,应区分哪些是作为数值运算或关系运算的对象,哪些作为逻辑运算的对象。例如,
5> 3 && 8< 4-!0
表达式自左至右扫描求解。首先处理,5> 3”(因为关系运算符优先于 &&)。在关系运算符两侧的 5和 3作为数值参加关系运算,,5> 3”的值为 1。再进行
,1&&8<4-!0”的运算,8的左侧为,&&”,右侧为,<”
运算符,根据优先规则,应先进行,<”的运算,即先进行,8<4-!0”的运算。现在 4的左侧为,<”,右侧为
,-”运算符,而,-”优先于,<”,因此应先进行,4-!0”
的运算,由于,!”的级别最高,因此先进行,!0”的运算,得到结果 1。然后进行,4-1”的运算,得结果 3,
再进行,8<3”的运算,得 0,最后进行,1&&0”的运算,得 0。
实际上,逻辑运算符两侧的运算对象不但可以是 0和
1,或者是 0和非 0的整数,也可以是任何类型的数据。可以是字符型、实型或指针型等。系统最终以
0和非 0来判定它们属于“真”或“假”。例如
'c' && 'd'
的值为 1(因为‘ c?和‘ d?的 ascII值都不为 0,按“真”
处理 )。
在逻辑表达式的求解中,并不是所有的逻辑运算符都被执行,只是在必须执行下一个逻辑运算符才能求出表达式的解时,才执行该运算符。例如:
(1) a && b && c只有 a为真 (非 0)时,才需要判别 b的值,
只有 a和 b都为真的情况下才需要判别 c的值。只要 a为假,就不必判别 b和 c(此时整个表达式已确定为假 )。
如果 a为真,b为假,不判别 c。见图 5.3。
(2) a||b||c只要 a为真 (非 0),就不必判断 b和 c;只有 a为假,
才判别 b; a和 b都为假才判别 c。见图 5.4。
图 5.3 图 5.4
也就是说,对 &&运算符来说,只有 a≠0,才继续进行右面的运算。对运算符 ‖ 来说,只有 a=0,才继续进行其右面的运算。因此,如果有下面的逻辑表达式:
(m=a> b) && (n=c> d)
当 a=1,b=2,c=3,d=4,m和 n的原值为 1时,由于
,a> b”的值为 0,因此 m=0,而,n=c> d”不被执行,因此 n的值不是 0而仍保持原值 1。这点请读者注意。
熟练掌握 c语言的关系运算符和逻辑运算符后,可以巧妙地用一个逻辑表达式来表示一个复杂的条件。
例如,要判别某一年 year是否闰年。闰年的条件是符合下面二者之一:
①能被 4整除,但不能被 100整除。②能被 4整除,又能被 400整除。
可以用一个逻辑表达式来表示:
(year% 4==0 && year% 100!=0)||year%
400==0
当 year为某一整数值时,如果上述表达式值为真 (1),
则 year为闰年;否则 year为非闰年。
可以加一个,!”用来判别非闰年:
!((year% 4==0 && year% 100!=0)||year% 400==0)
若表达式值为真 (1),year为非闰年。也可以用下面逻辑表达式判别非闰年:
(year% 4!=0)||(year% 100==0 && year% 400!=0)
若表达式值为真,year为非闰年。请注意表达式中右面的括弧内的不同运算符 (%,!,&&0,==)的运算优先次序。
5.3 if语句
if语句是用来判定所给定的条件是否满足,根据判定的结果 (真或假 )决定执行给出的两种操作之一。
5.3.1 if语句的三种形式
C语言提供了三种形式的 if语句:
1,if(表达式 ) 语句例如:
if(x> y) printf("% d",x);
这种 if语句的执行过程见图 5.5(a)。
2,if(表达式 )语句 1 else语句 2
例如,if (x> y) printf("% d",x);
else printf("% d",y);见图 5.5(b)。
图 5.5
3,if(表达式 1) 语句 1
else if(表达式 2)语句 2
else if(表达式 3) 语句 3
…
else if(表达式 m) 语句 m
else语句 n
流程图见图 5.6。
图 5.6
例如:
if(number>500)cost=0.15;
else if(number>300)cost=0.10;
else if(number>100)cost=0.075;
else if(number>50)cost=0.05;
elsecost=0;
说明:
(1) 三种形式的 if语句中在 if后面都有“表达式”,一般为逻辑表达式或关系表达式。例如,if(a==b &&
x==y)printf(“a=b,x=y”);在执行 if语句时先对表达式求解,
若表达式的值为 0,按“假”处理,若表达式的值为非 0,
按“真”处理,执行指定的语句。假如有以下 if语句:
if(3) printf("O,k,");
是合法的,执行结果输出“O,k.”,因为表达式的值为 3,按“真”处理。由此可见,表达式的类型不限于逻辑表达式,可以是任意的数值类型 (包括整型、实型、字符型、指针型数据 )。例如,下面的 if语句也是合法的:
if('a') printf("% d",'a');
执行结果:输出‘ a?的 ASCII码 97。
(2) 第二、第三种形式的 if语句中,在每个 else前面有一分号,整个语句结束处有一分号。例如:
if (x>0)
Print ("%f",x);
else 各有一个分号
printf("%f",-x);
这是由于分号是 c语句中不可缺少的部分,这个分号是 if语句中的内嵌语句所要求的。如果无此分号,
则出现语法错误。但应注意,不要误认为上面是两个语句 (if语句和 else语句 )。它们都属于同一个 if语句。 else子句不能作为语句单独使用,它必须是 if
语句的一部分,与 if配对使用。
(3) 在 if和 else后面可以只含一个内嵌的操作语句 (如上例 ),也可以有多个操作语句,此时用花括号
“{}”将几个语句括起来成为一个复合语句。
如:
if (a+ b>c && b+ c> a && c+ a> b)
{ s=0.5*(a+b+c); area=sqrt(S*(S-a)*(S-b)*(S-c));
printf("area=% 6,2f",area);}
else printf("it is not a trilateral");
注意在第 3行的花括号“}”外面不需要再加分号。
因为{}内是一个完整的复合语句,不需另附加分号。
例 5.1输入两个实数,按代数值由小到大的次序输出这两个数。
这个问题的算法很简单,只需要作一次比较即可。
对类似这样简单的问题可以不必先写出算法或画流程图,而直接编写程序。或者说,算法在编程者的脑子里,相当于在算术运算中对简单的问题可以“心算”而不必在纸上写出来一样。
程序如下:
main()
{
float a,b,t;
scanf("% f,% f",&a,&b);
if(a> b)
{ t=a; a=b; b=t;}
printf("% 5,2f,% 5,2f",a,b);
}
运行情况如下:
3.6,-3.2
-3.20,3.60
例 5.2输入 3个数 a,b,c,要求按由小到大的顺序输出。解此题的算法比上一题稍复杂一些。可以用伪代码写出算法:
if a > b 将 a和 b对换 (a是 a,b中的小者 )
if a > c 将 a和 c对换 (a是 a,c中的小者,因此 a是三者中最小者 )
if b > c 将 b和 c对换 (b是 b,c中的小者,也是三者中次小者 )
然后顺序输出 a,b,c即可。
按此算法编写程序:
main()
{
float a,b,c,t;
scanf("% f,% f,% f",&a,&b,&c);
if(a> b)
t=a; a=b; b=t;} /* 实现 a和 b的互换 */
if(a> c)
t=a; a=c; c=t;} /* 实现 a和 c的互换 */
if(b> c)
{ t=b; b=c; c=t;} /* 实现 b和 c的互换 */
printf("% 5,2f,% 5,2f,% 5,2f",a,b,
c);
}
运行情况如下:
3,7,1
1.00,3.00,7.00
5.3.2 if语句的嵌套在 if语句中又包含一个或多个 if语句称为 if语句的嵌套。一般形式如下:
if()
if()语句 1
else语句 2内嵌 if
else
if()语句 3
else语句 4内嵌 if
应当注意 if与 else的配对关系。 else总是与它上面的最近的
if配对。假如写成,
if()
if()语句 1
else
if()语句 2
else 语句 3内嵌 if
编程序者把 else写在与第一个 if(外层 if)同一列上,希望 else
与第一个 if对应,但实际上 else是与第二个 if配对,因为它们相距最近。因此最好使内嵌 if语句也包含 else部分 (如本节 (5.3.2节 )最早列出的形式 ),这样 if的数目和 else的数目相同,从内层到外层一一对应,不致出错。
如果 if与 else的数目不一样,为实现程序设计者的企图,
可以加花括弧来确定配对关系。例如,
if()
{ if ()语句 1}
else语句 2(内嵌 if)
这时 { }限定了内嵌 if语句的范围,因此 else与第一个 if
配对。
例 5.3有一函数,
y=-1(x<0)
0(x=0)
1(x>0)
编一程序,输入一个 x值,输出 y值。
可以先写出算法:
输入 x
若 x < 0y =-1;若 x = 0y = 0;若 x > 0y = 1
输出 y或输入 x
若 x < 0y = -1
否则:
若 x = 0y = 0;若 x > 0y = 1
输出 y。也可以用流程图表示,见图 5.7。
图 5.7
有以下几个程序,请读者判断哪个是正确的?
程序 1:
main()
{ int x,y;
scanf("% d",&x);
if(x< 0)y=-1;
else if(x==0) y=0;
else y=1;
printf("x=% d,y=% d\ n",x,y);
}
程序 2,将上面程序的 if语句 (第 4~ 6行 )改为:
if (x> =0)
if (x> 0)y= 1;
else
y= 0;
else y=-1;
程序 3,将上述 if语句改为:
y=-1;
if(x!=0)
if(x> 0) y=1;
else y=0;
程序 4:
y=0;
if(x> =0)
if(x> 0) y=1;
else y=-1;
图 5.8
只有程序 1和程序 2是正确的。程序 1体现了图 5.7的流程,显然它是正确的。程序 2的流程图见图 5.8。它也能实现题目的要求。程序 3的流程图见图 5.9。程序 4的流程图见图 5.10。它们不能实现题目的要求。
请注意程序中的 else与 if的配对关系。例如程序 3中的 else子句是和它上一行的内嵌的 if语句配对,而不与笫 2行的 if语句配对。为了使逻辑关系清晰,
避免出错,一般把内嵌的 if语句放在外层的 else子句中 (如程序 1那样 ),这样由于有外层的 else相隔,
内嵌的 else不会被误认为和外层的 if配对,而只能与内嵌的 if配对,这样就不会搞混,如像程序 3和程序 4那样写就很容易出错。
图 5.9? 图 5.10
5.3.3 条件运算符若 if语句中,在表达式为“真”和“假”时,且都只执行一个赋值语句给同一个变量赋值时,可以用简单的条件运算符来处理。例如,若有以下 if语句:
if (a> b) max=a;
else max=b;
可以用下面的条件运算符来处理:
max=(a> b)? a∶ b;
其中,(a> b)? a∶ b”是一个“条件表达式”。它是这样执行的:如果 (a> b)条件为真,则条件表达式取值 a,否则取值 b。
条件运算符要求有 3个操作对象,称三目 (元 )运算符,
它是 c语言中唯一的一个三目运算符。条件表达式的一般形式为图 5.11表达式 1?表达式 2∶ 表达式 3。
它的执行过程见图 5.11。
图 5.11
说明:
(1) 条件运算符的执行顺序:先求解表达式 1,若为非 0(真 )则求解表达式 2,此时表达式 2的值就作为整个条件表达式的值。若表达式 1的值为 0(假 ),则求解表达式 3,表达式 3的值就是整个条件表达式的值。
max=(a> b)? a∶ b
执行结果就是将条件表达式的值赋给 max。也就是将 a和 b二者中大者赋给 max。
(2) 条件运算符优先于赋值运算符,因此上面赋值表达式的求解过程是先求解条件表达式,再将它的值赋给 max。
条件运算符的优先级别比关系运算符和算术运算符都低。因此
max=(a> b)? a∶ b
括号可以不要,可写成
max=a> b? a∶ b
如果有
a> b? a∶ b+ 1
相当于 a> b? a∶ (b+ 1),而不相当于 (a> b? a∶ b)
+ 1。
(3) 条件运算符的结合方向为“自右至左”。如果有以下条件表达式,a> b? a∶ c> d? c∶ d相当于 a
> b? a∶ (c> d? c∶ d)
如果 a=1,b=2,c=3,d=4,则条件表达式的值等于
4。
(4) 条件表达式不能取代一般的 if语句,只有在 if语句中内嵌的语句为赋值语句 (且两个分支都给同一个变量赋值 )时才能代替 if语句。像下面的 if语句就无法用一个条件表达式代替。
if(a> b) printf("% d",a);
else printf("% d",b);
但可以用下面语句代替:
printf("% d",a> b? a∶ b);
即将条件表达式的值输出。
(5) 条件表达式中,表达式 1的类型可以与表达式 2和表达式 3的类型不同。如 x? 'a'∶ 'b'
x是整型变量,若 x=0,则条件表达式的值为 'b'。表达式 2和表达式 3的类型也可以不同,此时条件表达式的值的类型为二者中较高的类型。如
x> y? 1∶ 1,5
如果 x≤y,则条件表达式的值为 1,5,若 x> y,值应为 1,由于 1,5是实型,比整型高 (见第 3章 3,7),
因此,将 1转换成实型值 1.0。
例 5.4输入一个字符,判别它是否大写字母,如果是,
将它转换成小写字母;如果不是,不转换。然后输出最后得到的字符。
关于大小写字母之间的转换方法,在本书例 3.7中已做了介绍,因此可直接编写程序:
main()
{ charch;
scanf("% c",& ch);
ch=(ch> ='a' && ch< =?Z')? (ch+ 32)∶ ch;
printf("% c",ch)
}
运行结果如下:
a
a
条件表达式中的 (ch+ 32),其中 32是小写字母和大写字母 ASCII码的差值。
5.4 Switch 语 句
Switch语句是多分支选择语句。用来实现如图 3.6所表示的多分支选择结构。 if语句只有两个分支可供选择,而实际问题中常常需要用到多分支的选择。
例如,学生成绩分类 (90分以上为‘ a?等,80~ 89
分为‘ b?等,70~ 79分为‘ c?等 ……) ;人口统计分类 (按年龄分为老、中、青、少、儿童 );工资统计分类;银行存款分类 …… 。
当然这些都可以用嵌套的 if语句来处理,但如果分支较多,则嵌套的 if语句层数多,程序冗长而且可读性降低。 c语言提供 Switch语句直接处理多分支选择,它相当于 Pascal语言中的 case语句。它的一般形式如下:
switch(表达式 )
{ case 常量表达式 1:语句 1
case 常量表达式 2:语句 2
…
case 常量表达式 n:语句 n
default,语句 n+ 1
}
例如,要求按照考试成绩的等级打印出百分制分数段,可以用 Switch语句实现:
Switch(grade)
{ case 'a'∶ printf("85~ 100\ n");
case 'b'∶ printf("70~ 84\ n");
case 'c'∶ printf("60~ 69\ n");
case 'D'∶ printf("< 60\ n");
default∶ printf("error\ n");
}
说明:
(1) switch后面括弧内的“表达式”,ANSI标准允许它为任何类型。
(2) 当表达式的值与某一个 case后面的常量表达式的值相等时,就执行此 case后面的语句,若所有的 case
中的常量表达式的值都没有与表达式的值匹配的,
就执行 default后面的语句。
(3) 每一个 case的常量表达式的值必须互不相同,否则就会出现互相矛盾的现象 (对表达式的同一个值,
有两种或多种执行方案 )。
(4) 各个 case和 default的出现次序不影响执行结果。
例如,可以先出现,default,…”,再出现,case
D?,…”,然后是,case?a?,…” 。
(5) 执行完一个 case后面的语句后,流程控制转移到下一个 case继续执行。,case常量表达式”只是起语句标号作用,并不是在该处进行条件判断。在执行 Switch语句时,根据 Switch后面表达式的值找到匹配的入口标号,就从此标号开始执行下去,
不再进行判断。例如,上面的例子中,若 grade的值等于‘ a?,则将连续输出:
85~ 100
70~ 84
60~ 69
< 60
error
因此,应该在执行一个 case分支后,使流程跳出
Switch结构,即终止 Switch语句的执行。可以用一个 break语句来达到此目的。将上面的 Switch结构改写如下:
Switch(grade)
{ case 'a'∶ printf("85~ 100\ n"); break;
case 'b'∶ printf("70~ 84\ n"); break;
case 'c'∶ printf("60~ 69\ n"); break;
case 'D'∶ printf("< 60\ n"); break;
default ∶ printf("error\ n");
}
最后一个分支 (default)可以不加 break语句。 如果
grade的值为‘ b?,则只输出,70~ 84”。流程图见图 5.12。
图 5.12
在 case后面中虽然包含一个以上执行语句,但可以不必用花括弧括起来,会自动顺序执行本 case后面所有的执行语句。当然加上花括弧也可以。
(6) 多个 case可以共用一组执行语句,如:
…
case 'a'∶
case 'b'∶
case 'c'∶ printf("> 60\ n"); break;
…
grade的值为‘ a?、‘ b?或‘ c?时都执行同一组语句。
5.5 程序举例例 5.5写程序,判断某一年是否闰年。
我们用图 5.13来表示判别闰年的算法。以变量 leap代表是否闰年的信息。若某年为闰年,则令 leap=1;
若为非闰年,令 leap=0。最后判断 leap是否为
1(真 ),若是,则输出“闰年”信息。
图 5.13
据此编写程序如下:
main()
{
int year,leap;
scanf("% d",&year);
if (year% 4==0)
{ if (year% 100==0)
{ if (year% 400==0)
leap=1;
else leap=0;}
else
leap=1;}
else
leap=0;
if (leap)
printf("% d is ",year);
else
printf("% d is not ",year);
printf("a leap year.\ n");
}
运行情况如下:
① 1989
1989 is not a leap year.
② 2000
2000 is a leap year.
也可以将程序中第 5~ 13行改写成以下的 if语句:
if(year% 4!=0)
leap=0;
else if(year% 100!=0)
leap=1;
else if(year% 400!=0)
leap=0;
else
leap=1;
也可以用一个逻辑表达式包含所有的闰年条件,将上述 if语句用下面的 if语句代替:
if((year%4==0 && year%100!=0) || (year%400==0))
leap=1;
else leap=0;
例 5.6求 ax2+ bx+ c=0方程的解。
例 4.12曾介绍过基本的算法,实际上应该有以下几种可能:
① a=0,不是二次方程。
② b2-4ac=0,有两个相等实根。
③ b2-4ac> 0,有两个不等实根。
④ b2-4ac< 0,有两个共轭复根。
画出 N S流程图表示算法 (图 5.14)。
图 5.14
据此编写程序如下:
#include<math,h>
main()
{ float a,b,c,d,disc,x1,x2,realpart,
imagpart;
scanf("% f,% f,% f",&a,&b,&c);
printf("The equation");
if(fabs(a)< =le-6)
printf("is not a quadratic");
else
{disc=b*b-4*a*c;
if(fabs(disc)< =le-6)
printf("has two equal roots:%8.4\ n",-b
/ (2*a));
else if(disc> le-6)
{ x1=(-b+ sqrt(disc))/ (2*a);
x2=(-b-sqrt(disc))/ (2*a);
printf("has distinct real roots:%8.4f and
%8.4f\ n",x1,x2);
}
else
{ realpart=-b/ (2*a);
imagpart=sqrt(-disc)/ (2*a);
printf("has comPlex roots∶ \ n");
printf("%8.4f+%8.4fi\ n",realpart,
imagpart);
printf("%8.4f-%8.4fi\ n",realpart,
imagpart);
} }
}
程序中用 disc代表 b2-4ac,先计算 disc的值,以减少以后的重复计算。对于判断 b2-4ac是否等于 0时,
要注意一个问题:由于 disc(即 b2-4ac)是实数,而实数在计算和存储时会有一些微小的误差,
因此不能直接进行如下判断,if(disc==0)…… 因为这样可能会出现本来是零的量,由于上述误差而被判别为不等于零而导致结果错误。所以采取的办法是判别 disc的绝对值 (fabs(disc))是否小于一个很小的数 (例如 10-6),如果小于此数,就认为
disc=0。程序中以 realpart代表实部 P,以 imagpart
代表虚部 q,以增加可读性。
运行结果如下:
① 1,2,1
The equation has two equalroots∶ -1,0000
② 1,2,2
The equation has complex roots:
-1,0000+ 1,0000i
-1,0000-1,0000i
③ 2,6,1
The equation has distinct real roots:-0.1771
and =2.8229
例 5.7运输公司对用户计算运费。路程 (S)越远,每公里运费越低。标准如下:
s< 250km没有折扣
250≤S< 500 2%折扣
500≤S< 1000 5%折扣
1000≤S< 2000 8%折扣
2000≤S< 3000 10%折扣
3000≤S 15%折扣设每公里每吨货物的基本运费为 P(Price的缩写 ),货物重为 w(weight的缩写 ),距离为 S,折扣为
d(discount的缩写 ),则总运费 f(freight的缩写 )的计算公式为 f=P*w*S*(1-d)分析此问题,折扣的变化是有规律的:从图 5.15可以看到,折扣的“变化点”都是 250的倍数 (250,500,1000,2000,
3000)。利用这一特点,可以在横轴上加一种坐标
c,c的值为 S/250。 c代表 250的倍数。当 c<1时,表示 S<250,无折扣; 1≤c< 2时,表示 250≤S<500,
折扣 d=2%; 2≤c< 4时,d=5%; 4≤c< 8时,d=8
%; 8≤c< 12时,d=10%; c≥12时,d=15%。
图 5.15
据此写出程序如下:
main()
{
int c,S;
float P,w,d,f;
scanf("% f,% f,% d",&P,&w,&S);
if(S> =3000) c=12;
else c=S/ 250;
switch(c)
{
case0∶ d=0; break;
case1∶ d=2; break;
case2∶
case3∶ d=5; break;
case4∶
case5∶
case6∶
case7∶ d=8; break;
case8∶
case9∶
case10∶
case11∶ d=10; break;
case12∶ d=15; break;
}
f=P*w*S*(1-d/ 100,0);
printf("freight=% 15,4f",f);
}
运行情况如下:
100,20,300
freight= 588000.0000
请注意,c,S是整型变量,因此 c=S/ 250为整数。
当 S≥3000时,令 c=12,而不使 c随 S增大,这是为了在 Switch语句中便于处理,用一个 case可以处理所有 S≥3000的情况。
习题
5.1 什么是算术运算?什么是关系运算?什么是逻辑运算?
5.2 C语言中如何表示“真”和“假”?系统如何判断一个量的“真”和“假”?
5.3 写出下面各逻辑表达式的值。设 a=3,b=4,c=5。
(1) a+ b> c && b==c
(2) a||b+ c && b-c
(3) !(a> b) && !c||1
(4) !(x=a) && (y=b) && 0
(5) !(a+ b)+ c-1 && b+ c/ 2
5.4 有 3个整数 a,b,c,由键盘输入,输出其中最大的数。
5.5 有一函数:
x (x< 1)
y = 2x-1 (1≤x< 10)
3x-11 (x≥10)
写一程序,输入 x,输出 y值。
5.6 给一个不多于 5位的正整数,要求:①求出它是几位数;②分别打印出每一位数字;③按逆序打印出各位数字,例如原数为 321,应输出 123。
图 5.16
5.7 企业发放的奖金根据利润提成。利润 I低于或等于 10万元的,奖金可提 10%;利润高于 10万元,低于 20万元 (100000< I≤200000)时,低于 10万元的部分按 10%提成,高于 100000元的部分,可提成 7,5
%; 200000< I≤400000时,低于 20万的部分仍按上述办法提成 (下同 )。高于 20万元的部职?%提成;
400000< I≤600000时,高于 40万元的部分按 3%提成;
600000< I≤1000000时,高于 60万的部分按 1,5%提成; I> 1000000时,超过 100万元的部分按 1%提成。
从键盘输入当月利润 I,求应发奖金总数。
要求,(1)用 if语句编程序; (2)用 Switch语句编程序。
5.8 有 4个圆塔,圆心分别为 (2,2),(-2,2),(-2,-
2),(2,-2),圆半径为 1。见图 5.16。这 4个塔的高度为 10m,塔以外无建筑物。今输入任一点的坐标,
求该点的建筑高度 (塔外的高度为零 )。