第 4章 选择结构程序设计
要设计选择结构程序,要考虑两个方面的问题:一是
在 C语言中如何来表示条件,二是在 C语言中实现选择结
构用什么语句。
在 C语言中表示条件,一般用关系表达式或逻辑表达
式,实现选择结构用 if语句或 switch语句。
4.1 关系运算及其表达式
4.2 逻辑运算及其表达式
4.3 if语句
4.4 switch语句
4.5 选择结构程序举例
良好的源程序书写风格 ──注释
[Return]
4.1 关系运算及其表达式
所谓“关系运算”实际上就是“比较运算”,即将
两个数据进行比较,判定两个数据是否符合给定的关系。
例如,,a > b”中的,>”表示一个大于关系运算。如
果 a的值是 5,b的值是 3,则大于关系运算,>”的结果为
“真”,即条件成立;如果 a的值是 2,b的值是 3,则大
于关系运算,>”的结果为“假”,即条件不成立。
4.1.1 关系运算符及其优先次序
1.关系运算符
C语言提供 6种关系运算符:
<(小于 ),<=(小于或等于 ),>(大于 ),
>=(大于或等于 ),==(等于 ),!=(不等于 )
注意,在C语言中,“等于”关系运算符是双等号
,= =”,而不是单等号,=,(赋值运算符)。
2,优先级
( 1) 在关系运算符中, 前 4个优先级相同, 后 2个也相同, 且前 4
个高于后 2个 。
( 2) 与其它种类运算符的优先级关系
关系运算符的优先级, 低于算术运算符, 但高于赋值运算符 。
4.1.2 关系表达式
1,关系表达式的概念
所谓关系表达式是指, 用关系运算符将两个表达式连
接起来, 进行关系运算的式子 。
例如, 下面的关系表达式都是合法的:
a>b,a+b>c-d,(a=3)<=(b=5),'a'>='b',(a>b)= =(b>c)
2,关系表达式的值 ——逻辑值 ( 非, 真, 即, 假, ) 。
由于C语言没有逻辑型数据, 所以用整数, 1, 表示
,逻辑真,, 用整数, 0, 表示, 逻辑假, 。
例如, 假设 num1=3,num2=4,num3=5,则:
( 1) num1>num2的值 =0。
( 2) (num1>num2)!=num3的值 =1。
( 3) num1<num2<num3的值 =1。
思考题,任意改变 num1或 num2的值, 会影响整个表
达式的值吗? 为什么?
( 4) (num1<num2)+num3的值 =6,因为 num1<num2的
值 =1,1+5=6。
再次强调, C语言用整数, 1”表示, 逻辑真,, 用整
数, 0”表示, 逻辑假, 。 所以, 关系表达式的值, 还可
以参与其它种类的运算, 例如算术运算, 逻辑运算 等 。
[Return]
4.2 逻辑运算及其表达式
关系表达式只能描述单一条件,例如,x>=0”。如果
需要描述,x>=0”、同时,x<10”,就要借助于逻辑表达
式了。
4.2.1 逻辑运算及其优先次序
1.逻辑运算符及其运算规则
( 1) C语言提供三种逻辑运算符:
&& 逻辑与(相当于“同时”)
|| 逻辑或(相当于“或者”)
! 逻辑非(相当于“否定”)
例如,下面的表达式都是逻辑表达式:
(x>=0) && (x<10), (x<1) || (x>5), ! (x= =0),
(year%4==0)&&(year%100!=0)||(year%400==0)
( 2) 运算规则
1) &&:当且仅当两个运算量的值都为, 真, 时,
运算结果为, 真,, 否则为, 假, 。
2) ||,当且仅当两个运算量的值都为, 假, 时, 运
算结果为, 假,, 否则为, 真, 。
3) !,当运算量的值为, 真, 时, 运算结果为
,假, ;当运算量的值为, 假, 时, 运算结果为, 真, 。
例如, 假定 x=5,则 (x>=0) && (x<10)的值为, 真,,
(x<-1) || (x>5)的值为, 假, 。
2,逻辑运算符的运算优先级
( 1) 逻辑非的优先级最高, 逻辑与次之, 逻辑或最低,
即:
!(非) → &&(与) → ||(或)
( 2) 与其它种类运算符的优先关系
! → 算术运算 → 关系运算 → &&→ || → 赋值运算
4.2.2 逻辑表达式
1,逻辑表达式的概念
所谓逻辑表达式是指, 用逻辑运算符将 1个或多个表达
式连接起来, 进行逻辑运算的式子 。 在 C语言中, 用逻辑表
达式表示多个条件的组合 。
例如,(year%4==0)&&(year%100!=0)||(year%400==0)就
是一个判断一个年份是否是闰年的逻辑表达式。
逻辑表达式的值也是一个逻辑值 ( 非, 真, 即
,假, ) 。
2,逻辑量的真假判定 ──0和非0
C语言用整数, 1, 表示, 逻辑真,, 用, 0, 表示
,逻辑假, 。 但在判断一个数据的, 真, 或, 假, 时,
却以0和非0为根据:如果为0, 则判定为, 逻辑假, ;
如果为非0, 则判定为, 逻辑真, 。
例如, 假设 num=12,则,! num的值 =0, num>=1
&& num<=31的值 =1, num || num>31的值 =1。
3,说明
( 1) 逻辑运算符两侧的操作数, 除可以是0和非0
的整数外, 也可以是其它任何类型的数据, 如实型, 字
符型等 。
( 2) 在计算逻辑表达式时, 只有在必须执行下一个表
达式才能求解时, 才求解该表达式 ( 即并不是所有的表达
式都被求解 ) 。 换句话说:
1) 对于逻辑与运算, 如果第一个操作数被判定为
,假,, 系统不再判定或求解第二操作数 。
2) 对于逻辑或运算, 如果第一个操作数被判定为
,真,, 系统不再判定或求解第二操作数 。
例如, 假设 n1,n2,n3,n4,x,y的值分别为 1,2,3、
4,1,1,则求解表达式, (x=n1>n2)&&(y=n3>n4)”后, x
的值变为0, 而 y的值不变, 仍等于 1!
[Return]
4.3 if语句和条件运算符
4.3.1 if语句
[案例 4.1] 输入任意三个整数 num1,num2,num3,求三个数中的最
大值。
/*案例代码文件名,AL4_1.C。 */
/*功能:说明 if 语句的格式。 */
main()
{int num1,num2,num3,max;
printf("Please input three numbers:");
scanf("%d,%d,%d",&num1,&num2,&num3);
if (num1>num2)
max=num1;
else
max=num2;
if (num3>max)
max=num3;
printf("The three numbers are:%d,%d,%d\n",num1,num2,num3);
printf("max=%d\n",max);
}
[程序演示 ]
程序运行情况如下:
Please input three numbers:11,22,18↙
The three numbers are:11,22,18
max=22
本案例中的第 1个 if语句,可优化为如下不带 else子句
的形式:
max=num1;
if(num2>max) max=num2;
这种优化形式的基本思想是:首先取一个数预置为
max(最大值),然后再用 max依次与其余的数逐个比较,
如果发现有比 max大的,就用它给 max重新赋值,比较完
所有的数后,max中的数就是最大值。这种方法,对从 3
个或 3个以上的数中找最大值的处理,非常有效。请读者
仔细体会。
[案例 4.2]输入任意三个数 num1,num2,num3,按从小到大的顺序
排序输出 。
/*案例代码文件名,AL4_2.C。 */
main()
{int num1,num2,num3,temp;
printf("Please input three numbers:");
scanf("%d,%d,%d",&num1,&num2,&num3);
if (num1>num2) {temp=num1;num1=num2;num2=temp;}
if (num2>num3) {temp=num2;num2=num3;num3=temp;}
if (num1>num2) {temp=num1;num1=num2;num2=temp;}
printf("Three numbers after sorted,%d,%d,%d\n",num1,num2,num3);
} [程序演示 ]
程序运行情况如下:
Please input three numbers:11,22,18↙
Three numbers after sorted,11,18,22
1,if语句的一般格式
if(表达式 )
{语句组 1;}
[else
{语句组 2;} ]
( 1) if语句中的, 表达式, 必须用, (”和, )”括起来 。
( 2) else子句 ( 可选 ) 是 if语句的一部分, 必须与 if配对使用, 不
能单独使用 。
( 3) 当 if和 else下面的语句组, 仅由一条语句构成时, 也可不使
用复合语句形式 ( 即去掉花括号 ) 。
2,if语句的执行过程
( 1) 缺省 else子句时
当, 表达式, 的值不等于 0( 即判定为, 逻辑真, )
时, 则执行语句组 1,否则直接转向执行下一条 。 如图 4-
1(a)所示 。
( 2) 指定 else子句时
当, 表达式, 的值不等于 0( 即判定为, 逻辑真, )
时, 则执行语句组 1,然后转向下一条语句;否则, 执行
语句组 2。 如图 4-1(b)所示 。
3,if语句的嵌套与嵌套匹配原则
if语句允许嵌套 。 所谓 if语句的嵌套是指, 在, 语句
组 1”或 ( 和 ), 语句组 2”中, 又包含有 if语句的情况 。
if语句嵌套时, else子句与 if的 匹配原则,与在它上
面, 距它最近, 且尚未匹配的 if配对 。
为明确匹配关系, 避免匹配错误, 强烈建议,将内
嵌的 if语句, 一律用花括号括起来 。
[案例 4.3] 写一程序, 从键盘上输入 1年份 year( 4位十
进制数 ), 判断其是否闰年 。 闰年的条件是:能被 4整除,
但不能被 100整除, 或者能被 400整除 。
算法设计要点,
( 1) 如果X能被Y整除, 则余数为0, 即如果X %
Y的值等于0, 则表示X能被Y整除 !
( 2) 首先将是否闰年的标志 leap预置为 0( 非闰年 ),
这样仅当 year为闰年时将 leap置为 1即可 。 这种处理两种状
态值的方法, 对优化算法和提高程序可读性非常有效,
请读者仔细体会 。 参考程序如下,
/*案例代码文件名,AL4_3.C。 */
/*功能:说明 if语句的嵌套格式和用法 。 */
main()
{int year,leap=0; /* leap=0:预置为非闰年 */
printf("Please input the year:");
scanf("%d",&year);
if (year % 4==0) {if (year % 100 != 0) leap=1;}
else {if (year%400==0) leap=1; }
if (leap) printf("%d is a leap year.\n",year);
else printf("%d is not a leap year.\n",year);
} [程序演示 ]
利用逻辑运算能描述复杂条件的特点, 可将上述程序优化如下:
main()
{int year;
printf("Please input the year:");
scanf("%d",&year);
if ((year%4==0 && year%100!=0)||(year%400==0))
printf("%d is a leap year.\n",year);
else
printf("%d is not a leap year.\n",year);
}
4,说明
( 1) if后面的, 表达式,, 除常见的关系表达式或逻辑表达式外,
也允许是其它类型的数据, 如整型, 实型, 字符型等 。
( 2) if语句允许嵌套, 但嵌套的层数不宜太多 。 在实际编程时,
应适当控制嵌套层数 (2~ 3层 )。
( 3), 语句组 1”和, 语句组 2”,可以只包含一个简单语句, 也可
以是复合语句 。
务必牢记,不管是简单语句, 还是复合语句中的各个语句, 每个
语句后面的分号必不可少 !
例如, [案例 4.1]中的:
if (num1>num2) max=num1;
else max=num2;语句:
if行后面的赋值语句, max=num1;”分号不能省略 。 但不要误认为 if
和 else是 2个独立的语句, 它们都属于 if语句中的一部分, else是 if语句
的子句 。
4.3.2 条件运算符
1,一般格式,表达式 1? 表达式 2:表达式 3
条件表达式中的, 表达式 1”,,表达式 2”,,表达
式 3”的类型, 可以各不相同 。
2,运算规则
如果, 表达式 1”的值为非 0(即逻辑真 ),则运算结果
等于, 表达式 2”的值;否则, 运算结果等于, 表达式 3”的
值 。 如图 4-2所示 。
3,运算符的优先级与结合性
条件运算符的优先级, 高于赋值运算符, 但低于关
系运算符和算术运算符 。 其结合性为, 从右到左, ( 即
右结合性 ) 。
[例 4.4] 从键盘上输入一个字符, 如果它是大写字母,
则把它转换成小写字母输出;否则, 直接输出 。
/*案例文件名,AL4_4.C*/
main()
{ char ch;
printf("Input a character,");
scanf("%c",&ch);
ch=(ch>='A' && ch<='Z')? (ch+32), ch;
printf("ch=%c\n",ch);
} [程序演示 ]
[Return]
4.4 switch语句
C语言提供了 switch语句直接处理多分支选择。
[案例 4.5] 从键盘上输入一个百分制成绩 score,按下列原则输出其
等级,score≥90,等级为 A; 80≤score<90,等级为 B; 70≤score<80,
等级为 C; 60≤score<70,等级为 D; score<60,等级为 E。
/*案例代码文件名,AL4_5.C。 */
main()
{int score,grade;
printf(“Input a score(0~100):,);
scanf(“%d”,&score);
grade = score/10; /*将成绩整除 10,转化成 switch语句中的 case标号 */
switch (grade)
{case 10:
case 9,printf(“grade=A\n”); break;
case 8,printf("grade=B\n"); break;
case 7,printf("grade=C\n"); break;
case 6,printf("grade=D\n"); break;
case 5:
case 4:
case 3:
case 2:
case 1:
case 0,printf(“grade=E\n”); break;
default,printf(“The score is out of range!\n”);
}
} [程序演示 ]
程序运行情况如下:
Input a score(0~100),85↙
grade=B
1,switch语句的一般形式
switch(表达式 )
{ case 常量表达式 1:语句组; break;
case 常量表达式 2:语句组; break;
......
case 常量表达式n:语句组; break;
[default:语句组; [break; ]]
}
2,执行过程
( 1) 当 switch后面, 表达式, 的值, 与某个 case后面
的, 常量表达式, 的值相同时, 就执行该 case后面的语句
( 组 ) ;当执行到 break语句时, 跳出 switch语句, 转向执
行 switch语句的下一条 。
( 2) 如果没有任何一个 case后面的, 常量表达式,
的值, 与, 表达式, 的值匹配, 则执行 default 后面的语
句 ( 组 ) 。 然后, 再执行 switch语句的下一条 。
3,说明
( 1) switch后面的, 表达式,, 可以是 int,char和枚
举型中的一种 。
( 2) 每个 case后面, 常量表达式, 的值, 必须各不
相同, 否则会出现相互矛盾的现象 ( 即对表达式的同一
值, 有两种或两种以上的执行方案 ) 。
( 3) case后面的常量表达式仅起语句标号作用, 并
不进行条件判断 。 系统一旦找到入口标号, 就从此标号
开始执行, 不再进行标号判断, 所以必须加上 break语句,
以便结束 switch语句 。
思考题,如果去掉 [案例 4.5]程序中的所有 break语句,
且输入的成绩为 75,输出会如何?
( 4) 各 case及 default子句的先后次序, 不影响程序执
行结果 。
( 5) 多个 case子句, 可共用同一语句 ( 组 ) 。
例如, 在 [案例 4.5]中的, case 10:,和, case 9:,共用
语句, printf("grade=A\n"); break;”,,case 5:,~“case 0:,
共用语句, printf("grade=E\n"); break;”。
( 6) 用 switch语句实现的多分支结构程序, 完全可
以用 if语句或 if语句的嵌套来实现 。
[Return]
4.5 选择结构程序设计举例
[案例 4.6] 求一元二次方程 ax2+bx+c=0的解( a≠0)。
/*案例代码文件名,AL4_6.C。 */
/*功能:求一元二次方程的解。 */
#include "math.h"
main()
{float a,b,c,disc,x1,x2,p,q;
scanf(“%f,%f,%f”,&a,&b,&c);
disc=b*b-4*a*c;
if (fabs(disc)<=1e-6) /*fabs():求绝对值库函数 */
printf(“x1=x2=%7.2f\n”,-b/(2*a)); /*输出两个相等的实根 */
else
{ if (disc>1e-6)
{x1=(-b+sqrt(disc))/(2*a); /*求出两个不相等的实根 */
x2=(-b-sqrt(disc))/(2*a);
printf("x1=%7.2f,x2=%7.2f\n",x1,x2);
}
else
{p=-b/(2*a); /*求出两个共轭复根 */
q=sqrt(fabs(disc))/(2*a);
printf(“x1=%7.2f + %7.2f i\n“,p,q); /*输出两个共轭复根 */
printf(”x2=%7.2f - %7.2f i\n“,p,q);
}
}
} [程序演示 ]
说明,由于实数在计算机中存储时,经常会有一些
微小误差,所以本案例判断 disc是否为 0的方法是:判断
disc的绝对值是否小于一个很小的数(例如 10-6)。
思考题,如果将系数 a,b,c定义成整数,能否直接
判断 disc是否等于 0?
[案例 4.7] 已知某公司员工的保底薪水为 500,某月所接工程的利
润 profit( 整数 ) 与利润提成的关系如下 ( 计量单位:元 ),
profit≤1000 没有提成;
1000< profit≤2000 提成 10%;
2000< profit≤5000 提成 15%;
5000< profit≤10000 提成 20%;
10000< profit 提成 25%。
算法设计要点:
为使用 switch语句, 必须将利润 profit与提成的关系, 转换成某些
整数与提成的关系 。 分析本题可知, 提成的变化点都是 1000的整数倍
( 1000,2000,5000,…… ), 如果将利润 profit整除 1000,则当:
profit≤1000 对应 0,1
1000< profit≤2000 对应 1,2
2000< profit≤5000 对应 2,3,4,5
5000< profit≤10000 对应 5,6,7,8,9,10
10000< profit 对应 10,11,12,……
为解决相邻两个区间的重叠问题, 最简单的方法就是:利润
profit先减 1( 最小增量 ), 然后再整除 1000即可:
profit≤1000 对应 0
1000< profit≤2000 对应 1
2000< profit≤5000 对应 2,3,4
5000< profit≤10000 对应 5,6,7,8,9
10000< profit 对应 10,11,12,……
/*案例代码文件名,AL4_7.C。 */
main()
{long profit;
int grade;
float salary=500;
printf("Input profit,");
scanf("%ld",&profit);
grade= (profit – 1) / 1000; /*将利润 -1,再整除 1000,转化成
switch语句中的 case标号 */
switch(grade)
{ case 0,break; /*profit≤1000 */
case 1,salary += profit*0.1; break; /*1000< profit≤2000 */
case 2:
case 3:
case 4,salary += profit*0.15; break; /*2000< profit≤5000 */
case 5:
case 6:
case 7:
case 8:
case 9,salary += profit*0.2; break; /*5000< profit≤10000 */
default,salary += profit*0.25; /*10000< profit */
}
printf("salary=%.2f\n",salary);
} [程序演示 ]
[Return]
良好的源程序书写风格 ──注释
必要的注释,可有效地提高程序的可读性,从而提
高程序的可维护性。
在C语言源程序中,注释可分为三种情况,( 1) 在
函数体内对语句的注释;( 2)在函数之前对函数的注释;
( 3)在源程序文件开始处,对整个程序的总体说明。
函数体内的语句,是由顺序结构、选择结构和循环
结构等三种基本结构构成的。在什么地方加以注释的原
则是:如果不加注释,理解起来就会有困难,或者虽无
困难、但浪费时间。
( 1)顺序结构
在每个顺序程序段 (由若干条语句构成 )之前,用注释
说明其功能。除很复杂的处理外,一般没有必要每条语
句都加以注释。
( 2)选择结构
在 C语言中,选择结构是由 if语句和 switch语句来实现
的。一般地说,要在前面说明其作用,在每个分支条件
语句行的后面,说明该分支的含义,如下所示:
1) if语句
/*…… (说明功能) */
if(条件表达式 ) /*条件成立时的含义 */
{……}
else /*入口条件含义 */
{……}
2) switch语句
/*…… (说明功能) */
switch(表达式 )
{ case 常量表达式 1,/*该入口值的含义 */
语句组;
……
case 常量表达式 n,/*该入口值的含义 */
语句组;
default,/*该入口值的含义 */
语句组;
}
如果条件成立时(或入口值)的含义,已经很明确了,
也可不再加以注释。
[Return]
要设计选择结构程序,要考虑两个方面的问题:一是
在 C语言中如何来表示条件,二是在 C语言中实现选择结
构用什么语句。
在 C语言中表示条件,一般用关系表达式或逻辑表达
式,实现选择结构用 if语句或 switch语句。
4.1 关系运算及其表达式
4.2 逻辑运算及其表达式
4.3 if语句
4.4 switch语句
4.5 选择结构程序举例
良好的源程序书写风格 ──注释
[Return]
4.1 关系运算及其表达式
所谓“关系运算”实际上就是“比较运算”,即将
两个数据进行比较,判定两个数据是否符合给定的关系。
例如,,a > b”中的,>”表示一个大于关系运算。如
果 a的值是 5,b的值是 3,则大于关系运算,>”的结果为
“真”,即条件成立;如果 a的值是 2,b的值是 3,则大
于关系运算,>”的结果为“假”,即条件不成立。
4.1.1 关系运算符及其优先次序
1.关系运算符
C语言提供 6种关系运算符:
<(小于 ),<=(小于或等于 ),>(大于 ),
>=(大于或等于 ),==(等于 ),!=(不等于 )
注意,在C语言中,“等于”关系运算符是双等号
,= =”,而不是单等号,=,(赋值运算符)。
2,优先级
( 1) 在关系运算符中, 前 4个优先级相同, 后 2个也相同, 且前 4
个高于后 2个 。
( 2) 与其它种类运算符的优先级关系
关系运算符的优先级, 低于算术运算符, 但高于赋值运算符 。
4.1.2 关系表达式
1,关系表达式的概念
所谓关系表达式是指, 用关系运算符将两个表达式连
接起来, 进行关系运算的式子 。
例如, 下面的关系表达式都是合法的:
a>b,a+b>c-d,(a=3)<=(b=5),'a'>='b',(a>b)= =(b>c)
2,关系表达式的值 ——逻辑值 ( 非, 真, 即, 假, ) 。
由于C语言没有逻辑型数据, 所以用整数, 1, 表示
,逻辑真,, 用整数, 0, 表示, 逻辑假, 。
例如, 假设 num1=3,num2=4,num3=5,则:
( 1) num1>num2的值 =0。
( 2) (num1>num2)!=num3的值 =1。
( 3) num1<num2<num3的值 =1。
思考题,任意改变 num1或 num2的值, 会影响整个表
达式的值吗? 为什么?
( 4) (num1<num2)+num3的值 =6,因为 num1<num2的
值 =1,1+5=6。
再次强调, C语言用整数, 1”表示, 逻辑真,, 用整
数, 0”表示, 逻辑假, 。 所以, 关系表达式的值, 还可
以参与其它种类的运算, 例如算术运算, 逻辑运算 等 。
[Return]
4.2 逻辑运算及其表达式
关系表达式只能描述单一条件,例如,x>=0”。如果
需要描述,x>=0”、同时,x<10”,就要借助于逻辑表达
式了。
4.2.1 逻辑运算及其优先次序
1.逻辑运算符及其运算规则
( 1) C语言提供三种逻辑运算符:
&& 逻辑与(相当于“同时”)
|| 逻辑或(相当于“或者”)
! 逻辑非(相当于“否定”)
例如,下面的表达式都是逻辑表达式:
(x>=0) && (x<10), (x<1) || (x>5), ! (x= =0),
(year%4==0)&&(year%100!=0)||(year%400==0)
( 2) 运算规则
1) &&:当且仅当两个运算量的值都为, 真, 时,
运算结果为, 真,, 否则为, 假, 。
2) ||,当且仅当两个运算量的值都为, 假, 时, 运
算结果为, 假,, 否则为, 真, 。
3) !,当运算量的值为, 真, 时, 运算结果为
,假, ;当运算量的值为, 假, 时, 运算结果为, 真, 。
例如, 假定 x=5,则 (x>=0) && (x<10)的值为, 真,,
(x<-1) || (x>5)的值为, 假, 。
2,逻辑运算符的运算优先级
( 1) 逻辑非的优先级最高, 逻辑与次之, 逻辑或最低,
即:
!(非) → &&(与) → ||(或)
( 2) 与其它种类运算符的优先关系
! → 算术运算 → 关系运算 → &&→ || → 赋值运算
4.2.2 逻辑表达式
1,逻辑表达式的概念
所谓逻辑表达式是指, 用逻辑运算符将 1个或多个表达
式连接起来, 进行逻辑运算的式子 。 在 C语言中, 用逻辑表
达式表示多个条件的组合 。
例如,(year%4==0)&&(year%100!=0)||(year%400==0)就
是一个判断一个年份是否是闰年的逻辑表达式。
逻辑表达式的值也是一个逻辑值 ( 非, 真, 即
,假, ) 。
2,逻辑量的真假判定 ──0和非0
C语言用整数, 1, 表示, 逻辑真,, 用, 0, 表示
,逻辑假, 。 但在判断一个数据的, 真, 或, 假, 时,
却以0和非0为根据:如果为0, 则判定为, 逻辑假, ;
如果为非0, 则判定为, 逻辑真, 。
例如, 假设 num=12,则,! num的值 =0, num>=1
&& num<=31的值 =1, num || num>31的值 =1。
3,说明
( 1) 逻辑运算符两侧的操作数, 除可以是0和非0
的整数外, 也可以是其它任何类型的数据, 如实型, 字
符型等 。
( 2) 在计算逻辑表达式时, 只有在必须执行下一个表
达式才能求解时, 才求解该表达式 ( 即并不是所有的表达
式都被求解 ) 。 换句话说:
1) 对于逻辑与运算, 如果第一个操作数被判定为
,假,, 系统不再判定或求解第二操作数 。
2) 对于逻辑或运算, 如果第一个操作数被判定为
,真,, 系统不再判定或求解第二操作数 。
例如, 假设 n1,n2,n3,n4,x,y的值分别为 1,2,3、
4,1,1,则求解表达式, (x=n1>n2)&&(y=n3>n4)”后, x
的值变为0, 而 y的值不变, 仍等于 1!
[Return]
4.3 if语句和条件运算符
4.3.1 if语句
[案例 4.1] 输入任意三个整数 num1,num2,num3,求三个数中的最
大值。
/*案例代码文件名,AL4_1.C。 */
/*功能:说明 if 语句的格式。 */
main()
{int num1,num2,num3,max;
printf("Please input three numbers:");
scanf("%d,%d,%d",&num1,&num2,&num3);
if (num1>num2)
max=num1;
else
max=num2;
if (num3>max)
max=num3;
printf("The three numbers are:%d,%d,%d\n",num1,num2,num3);
printf("max=%d\n",max);
}
[程序演示 ]
程序运行情况如下:
Please input three numbers:11,22,18↙
The three numbers are:11,22,18
max=22
本案例中的第 1个 if语句,可优化为如下不带 else子句
的形式:
max=num1;
if(num2>max) max=num2;
这种优化形式的基本思想是:首先取一个数预置为
max(最大值),然后再用 max依次与其余的数逐个比较,
如果发现有比 max大的,就用它给 max重新赋值,比较完
所有的数后,max中的数就是最大值。这种方法,对从 3
个或 3个以上的数中找最大值的处理,非常有效。请读者
仔细体会。
[案例 4.2]输入任意三个数 num1,num2,num3,按从小到大的顺序
排序输出 。
/*案例代码文件名,AL4_2.C。 */
main()
{int num1,num2,num3,temp;
printf("Please input three numbers:");
scanf("%d,%d,%d",&num1,&num2,&num3);
if (num1>num2) {temp=num1;num1=num2;num2=temp;}
if (num2>num3) {temp=num2;num2=num3;num3=temp;}
if (num1>num2) {temp=num1;num1=num2;num2=temp;}
printf("Three numbers after sorted,%d,%d,%d\n",num1,num2,num3);
} [程序演示 ]
程序运行情况如下:
Please input three numbers:11,22,18↙
Three numbers after sorted,11,18,22
1,if语句的一般格式
if(表达式 )
{语句组 1;}
[else
{语句组 2;} ]
( 1) if语句中的, 表达式, 必须用, (”和, )”括起来 。
( 2) else子句 ( 可选 ) 是 if语句的一部分, 必须与 if配对使用, 不
能单独使用 。
( 3) 当 if和 else下面的语句组, 仅由一条语句构成时, 也可不使
用复合语句形式 ( 即去掉花括号 ) 。
2,if语句的执行过程
( 1) 缺省 else子句时
当, 表达式, 的值不等于 0( 即判定为, 逻辑真, )
时, 则执行语句组 1,否则直接转向执行下一条 。 如图 4-
1(a)所示 。
( 2) 指定 else子句时
当, 表达式, 的值不等于 0( 即判定为, 逻辑真, )
时, 则执行语句组 1,然后转向下一条语句;否则, 执行
语句组 2。 如图 4-1(b)所示 。
3,if语句的嵌套与嵌套匹配原则
if语句允许嵌套 。 所谓 if语句的嵌套是指, 在, 语句
组 1”或 ( 和 ), 语句组 2”中, 又包含有 if语句的情况 。
if语句嵌套时, else子句与 if的 匹配原则,与在它上
面, 距它最近, 且尚未匹配的 if配对 。
为明确匹配关系, 避免匹配错误, 强烈建议,将内
嵌的 if语句, 一律用花括号括起来 。
[案例 4.3] 写一程序, 从键盘上输入 1年份 year( 4位十
进制数 ), 判断其是否闰年 。 闰年的条件是:能被 4整除,
但不能被 100整除, 或者能被 400整除 。
算法设计要点,
( 1) 如果X能被Y整除, 则余数为0, 即如果X %
Y的值等于0, 则表示X能被Y整除 !
( 2) 首先将是否闰年的标志 leap预置为 0( 非闰年 ),
这样仅当 year为闰年时将 leap置为 1即可 。 这种处理两种状
态值的方法, 对优化算法和提高程序可读性非常有效,
请读者仔细体会 。 参考程序如下,
/*案例代码文件名,AL4_3.C。 */
/*功能:说明 if语句的嵌套格式和用法 。 */
main()
{int year,leap=0; /* leap=0:预置为非闰年 */
printf("Please input the year:");
scanf("%d",&year);
if (year % 4==0) {if (year % 100 != 0) leap=1;}
else {if (year%400==0) leap=1; }
if (leap) printf("%d is a leap year.\n",year);
else printf("%d is not a leap year.\n",year);
} [程序演示 ]
利用逻辑运算能描述复杂条件的特点, 可将上述程序优化如下:
main()
{int year;
printf("Please input the year:");
scanf("%d",&year);
if ((year%4==0 && year%100!=0)||(year%400==0))
printf("%d is a leap year.\n",year);
else
printf("%d is not a leap year.\n",year);
}
4,说明
( 1) if后面的, 表达式,, 除常见的关系表达式或逻辑表达式外,
也允许是其它类型的数据, 如整型, 实型, 字符型等 。
( 2) if语句允许嵌套, 但嵌套的层数不宜太多 。 在实际编程时,
应适当控制嵌套层数 (2~ 3层 )。
( 3), 语句组 1”和, 语句组 2”,可以只包含一个简单语句, 也可
以是复合语句 。
务必牢记,不管是简单语句, 还是复合语句中的各个语句, 每个
语句后面的分号必不可少 !
例如, [案例 4.1]中的:
if (num1>num2) max=num1;
else max=num2;语句:
if行后面的赋值语句, max=num1;”分号不能省略 。 但不要误认为 if
和 else是 2个独立的语句, 它们都属于 if语句中的一部分, else是 if语句
的子句 。
4.3.2 条件运算符
1,一般格式,表达式 1? 表达式 2:表达式 3
条件表达式中的, 表达式 1”,,表达式 2”,,表达
式 3”的类型, 可以各不相同 。
2,运算规则
如果, 表达式 1”的值为非 0(即逻辑真 ),则运算结果
等于, 表达式 2”的值;否则, 运算结果等于, 表达式 3”的
值 。 如图 4-2所示 。
3,运算符的优先级与结合性
条件运算符的优先级, 高于赋值运算符, 但低于关
系运算符和算术运算符 。 其结合性为, 从右到左, ( 即
右结合性 ) 。
[例 4.4] 从键盘上输入一个字符, 如果它是大写字母,
则把它转换成小写字母输出;否则, 直接输出 。
/*案例文件名,AL4_4.C*/
main()
{ char ch;
printf("Input a character,");
scanf("%c",&ch);
ch=(ch>='A' && ch<='Z')? (ch+32), ch;
printf("ch=%c\n",ch);
} [程序演示 ]
[Return]
4.4 switch语句
C语言提供了 switch语句直接处理多分支选择。
[案例 4.5] 从键盘上输入一个百分制成绩 score,按下列原则输出其
等级,score≥90,等级为 A; 80≤score<90,等级为 B; 70≤score<80,
等级为 C; 60≤score<70,等级为 D; score<60,等级为 E。
/*案例代码文件名,AL4_5.C。 */
main()
{int score,grade;
printf(“Input a score(0~100):,);
scanf(“%d”,&score);
grade = score/10; /*将成绩整除 10,转化成 switch语句中的 case标号 */
switch (grade)
{case 10:
case 9,printf(“grade=A\n”); break;
case 8,printf("grade=B\n"); break;
case 7,printf("grade=C\n"); break;
case 6,printf("grade=D\n"); break;
case 5:
case 4:
case 3:
case 2:
case 1:
case 0,printf(“grade=E\n”); break;
default,printf(“The score is out of range!\n”);
}
} [程序演示 ]
程序运行情况如下:
Input a score(0~100),85↙
grade=B
1,switch语句的一般形式
switch(表达式 )
{ case 常量表达式 1:语句组; break;
case 常量表达式 2:语句组; break;
......
case 常量表达式n:语句组; break;
[default:语句组; [break; ]]
}
2,执行过程
( 1) 当 switch后面, 表达式, 的值, 与某个 case后面
的, 常量表达式, 的值相同时, 就执行该 case后面的语句
( 组 ) ;当执行到 break语句时, 跳出 switch语句, 转向执
行 switch语句的下一条 。
( 2) 如果没有任何一个 case后面的, 常量表达式,
的值, 与, 表达式, 的值匹配, 则执行 default 后面的语
句 ( 组 ) 。 然后, 再执行 switch语句的下一条 。
3,说明
( 1) switch后面的, 表达式,, 可以是 int,char和枚
举型中的一种 。
( 2) 每个 case后面, 常量表达式, 的值, 必须各不
相同, 否则会出现相互矛盾的现象 ( 即对表达式的同一
值, 有两种或两种以上的执行方案 ) 。
( 3) case后面的常量表达式仅起语句标号作用, 并
不进行条件判断 。 系统一旦找到入口标号, 就从此标号
开始执行, 不再进行标号判断, 所以必须加上 break语句,
以便结束 switch语句 。
思考题,如果去掉 [案例 4.5]程序中的所有 break语句,
且输入的成绩为 75,输出会如何?
( 4) 各 case及 default子句的先后次序, 不影响程序执
行结果 。
( 5) 多个 case子句, 可共用同一语句 ( 组 ) 。
例如, 在 [案例 4.5]中的, case 10:,和, case 9:,共用
语句, printf("grade=A\n"); break;”,,case 5:,~“case 0:,
共用语句, printf("grade=E\n"); break;”。
( 6) 用 switch语句实现的多分支结构程序, 完全可
以用 if语句或 if语句的嵌套来实现 。
[Return]
4.5 选择结构程序设计举例
[案例 4.6] 求一元二次方程 ax2+bx+c=0的解( a≠0)。
/*案例代码文件名,AL4_6.C。 */
/*功能:求一元二次方程的解。 */
#include "math.h"
main()
{float a,b,c,disc,x1,x2,p,q;
scanf(“%f,%f,%f”,&a,&b,&c);
disc=b*b-4*a*c;
if (fabs(disc)<=1e-6) /*fabs():求绝对值库函数 */
printf(“x1=x2=%7.2f\n”,-b/(2*a)); /*输出两个相等的实根 */
else
{ if (disc>1e-6)
{x1=(-b+sqrt(disc))/(2*a); /*求出两个不相等的实根 */
x2=(-b-sqrt(disc))/(2*a);
printf("x1=%7.2f,x2=%7.2f\n",x1,x2);
}
else
{p=-b/(2*a); /*求出两个共轭复根 */
q=sqrt(fabs(disc))/(2*a);
printf(“x1=%7.2f + %7.2f i\n“,p,q); /*输出两个共轭复根 */
printf(”x2=%7.2f - %7.2f i\n“,p,q);
}
}
} [程序演示 ]
说明,由于实数在计算机中存储时,经常会有一些
微小误差,所以本案例判断 disc是否为 0的方法是:判断
disc的绝对值是否小于一个很小的数(例如 10-6)。
思考题,如果将系数 a,b,c定义成整数,能否直接
判断 disc是否等于 0?
[案例 4.7] 已知某公司员工的保底薪水为 500,某月所接工程的利
润 profit( 整数 ) 与利润提成的关系如下 ( 计量单位:元 ),
profit≤1000 没有提成;
1000< profit≤2000 提成 10%;
2000< profit≤5000 提成 15%;
5000< profit≤10000 提成 20%;
10000< profit 提成 25%。
算法设计要点:
为使用 switch语句, 必须将利润 profit与提成的关系, 转换成某些
整数与提成的关系 。 分析本题可知, 提成的变化点都是 1000的整数倍
( 1000,2000,5000,…… ), 如果将利润 profit整除 1000,则当:
profit≤1000 对应 0,1
1000< profit≤2000 对应 1,2
2000< profit≤5000 对应 2,3,4,5
5000< profit≤10000 对应 5,6,7,8,9,10
10000< profit 对应 10,11,12,……
为解决相邻两个区间的重叠问题, 最简单的方法就是:利润
profit先减 1( 最小增量 ), 然后再整除 1000即可:
profit≤1000 对应 0
1000< profit≤2000 对应 1
2000< profit≤5000 对应 2,3,4
5000< profit≤10000 对应 5,6,7,8,9
10000< profit 对应 10,11,12,……
/*案例代码文件名,AL4_7.C。 */
main()
{long profit;
int grade;
float salary=500;
printf("Input profit,");
scanf("%ld",&profit);
grade= (profit – 1) / 1000; /*将利润 -1,再整除 1000,转化成
switch语句中的 case标号 */
switch(grade)
{ case 0,break; /*profit≤1000 */
case 1,salary += profit*0.1; break; /*1000< profit≤2000 */
case 2:
case 3:
case 4,salary += profit*0.15; break; /*2000< profit≤5000 */
case 5:
case 6:
case 7:
case 8:
case 9,salary += profit*0.2; break; /*5000< profit≤10000 */
default,salary += profit*0.25; /*10000< profit */
}
printf("salary=%.2f\n",salary);
} [程序演示 ]
[Return]
良好的源程序书写风格 ──注释
必要的注释,可有效地提高程序的可读性,从而提
高程序的可维护性。
在C语言源程序中,注释可分为三种情况,( 1) 在
函数体内对语句的注释;( 2)在函数之前对函数的注释;
( 3)在源程序文件开始处,对整个程序的总体说明。
函数体内的语句,是由顺序结构、选择结构和循环
结构等三种基本结构构成的。在什么地方加以注释的原
则是:如果不加注释,理解起来就会有困难,或者虽无
困难、但浪费时间。
( 1)顺序结构
在每个顺序程序段 (由若干条语句构成 )之前,用注释
说明其功能。除很复杂的处理外,一般没有必要每条语
句都加以注释。
( 2)选择结构
在 C语言中,选择结构是由 if语句和 switch语句来实现
的。一般地说,要在前面说明其作用,在每个分支条件
语句行的后面,说明该分支的含义,如下所示:
1) if语句
/*…… (说明功能) */
if(条件表达式 ) /*条件成立时的含义 */
{……}
else /*入口条件含义 */
{……}
2) switch语句
/*…… (说明功能) */
switch(表达式 )
{ case 常量表达式 1,/*该入口值的含义 */
语句组;
……
case 常量表达式 n,/*该入口值的含义 */
语句组;
default,/*该入口值的含义 */
语句组;
}
如果条件成立时(或入口值)的含义,已经很明确了,
也可不再加以注释。
[Return]