第3 章
程序的控制结构
在第2章中介绍如何编写最基本的C语言程序,所编程求解的问题一般是按顺序
逐步执行的,这种程序结构称为顺序结构,顺序结构就像一条流水线,将程序的语句逐
一执行。计算机的程序也可以判断特定的条件,根据判断的结果,决定下一步要执行
的命令,即程序产生了分支;还有一些工作需要重复很多次才能完成,需要对某条语句
或某段程序重复执行多次。若实现这两类问题,就要用到本章介绍的分支结构和循环
结构。
3.1 关系运算与逻辑运算
人们在工作生活中经常需要进行判断“某个事件是否发生”。用计算机程序进行“某个
事件是否发生”的判断就是所谓的关系运算,也就是比较运算。某个事件是否发生,可能只
有一个条件,也可能有多个条件。对于某一条件,有时需要采用其成立(或不成立)的反过
程,也就是对条件“求反”。对于多个条件,有时要求多个条件只要成立一个即可,是一种
“或”的连接关系;有时要求其同时成立,是一种“并且”的连接关系。这种“求反”和对多个条
件“或”“并且”进行连接的运算称为逻辑运算。掌握关系运算和逻辑运算对于正确编写分支
程序和循环程序是非常重要的。
3.1.1 关系运算
【问题描述3.1】 猜数字游戏,事先给出一个确定的数字(如123),让游戏者从键盘输
入他猜想的数字,如果游戏者猜对了则显示Right,如果猜错了则显示Wrong。
分析:本问题的关键是将游戏者猜的数字与给出的数字进行比较。在计算机程序中进
行这种比较需要将事件符号化。假设程序设定的数字为123,所猜的数字放入变量guess, 
判断猜测的数字是否正确,就是比较guess的值是否等于123,这就是所谓关系运算。关系
运算是对两个表达式进行比较,并产生运算结果。
1.关系运算符
C语言提供的关系运算符有6种,如表3.1所示。
3-1关系运算

程序设计基础(C语言)( 第3版) 

表3.

1C 
语言中的关系运算符

74
运算符含义运算符含义
> 大于<= 小于或等于
>= 大于或等于== 等于
< 小于!= 不等于
2. 
关系表达式
(1)关系表达式:用关系运算符将两个表达式(算术、关系、逻辑、赋值表达式等)连接
起来所构成的表达式称为关系表达式。关系表达式的值是一个逻辑值,只有两种取值“真” 
或“假”。C语言没有逻辑型数据,关系运算的结果是int型,以1表示关系表达式成立,代表
“真”;0表示关系表达式不成立,代表“假”。
(2)关系运算的特点: 
①关系运算符都是双目运算符,并且都是从左向右结合。
②关系运算符的优先级比算术运算符低,但都比赋值运算符高。在关系运算符内部, 
>、>= 、<、<= 运算符的优先级相同;== 和!=两种运算符的优先级相同,且低于其他4 
种关系运算符。
例如: 
c>a+b 等价于c>(a+b) 关系运算符的优先级低于算术运算符。
a>b==c 等价于(a>b)==c > 优先级高于== 。
a==b<c 等价于a==(b<c)<优先级高于== 。
a=b>c 等价于a=(b>c) 关系运算符的优先级高于赋值运算符。
为了结构清晰易读,在程序设计中建议采用加括号方式。


1.逻辑运算
3.2 
平常所说的“求反”“或”“并且”分别对应逻辑非、逻辑或、逻辑与。

3-2逻辑1. 
逻辑运算符
运算C语言中的逻辑运算符有3种,如表3.

2所示。

表3.

2C 
语言中的逻辑运算符

运算符含义
&& 逻辑与
|| 逻辑或
! 逻辑非

2. 
逻辑表达式
逻辑表达式:用逻辑运算符(逻辑与、逻辑或、逻辑非)将关系表达式或逻辑量连接起
来,构成逻辑表达式。

逻辑表达式的值是一个逻辑量“真”或“假”。C语言编译系统在给出逻辑运算结果时, 
以1代表“真”,以0代表“假”,但在判断一个表达式的结果是否为“真”时,以0代表“假”,以


程序的控制结构

非
0 
代表“真”(即认为一个非0的数值是“真”)。
在一个逻辑表达式中如果包含多个逻辑运算符,则优先顺序如下。

(1)!( 非)→&&(与)→||(或),! 是三者中最高的。
(2)逻辑运算符中的&& 和|| 的优先级低于关系运算符,而! 不仅高于关系运算符, 
而且高于算术运算符。
例如: 
a>b&&x>y 等价于(a>b)&&(x>y) 
a==b||x==y 等价于(a==b)||(x==y)
!a||a>b 等价于(!a)||(a>b) 
逻辑运算的真值表如表3.

3所示。

表3.逻辑运算的真值表

3 

a b 
!
a 
!
b 
a&&
b 
a||
b 
非0 非0 0 0 1 1 
非0 0 0 1 0 1 
0 非0 1 0 0 1 
0 0 1 1 0 0 

在逻辑表达式的求解中,并不是所有的逻辑运算符都被执行,只是在必须执行下一个逻
辑运算符才能求出表达式的解时,才执行该运算符。

(1)“ 与”表达式:a&&b&&c,只要a、b、c有一个为“假”则整个表达式的值就为假。
因此,只有a为真,才需要判别b的值;只有a、b都为真,才需要判别c的值。只要a为假, 
此时整个表达式已经确定为假,就不必判别b和c;如果a为真,b为假,则不必判断c。
设a=1,b=2,c=3,d=4,m=n=1,则执行表达式(m=a>b)&&(n=c>d)后,m、
n的值是多少? 
说明:因a>b 为假(0), 所以m=0,赋值表达式m=a>b 的值为0,又因整个表达式是
“与”表达式,所以不需要再计算n=c>d,n保持原值1未变,而整个表达式的结果就是0。

(2)“ 或”表达式:a||b||c,只要a、b、c有一个为“真”则整个表达式的值就为真。因此, 
只要a为真,整个表达式就可以确定为真,就不必判断b和c;只有a为假,才需要判断b;当
a、b都为假时,才需要判断c。
【问题描述3. 
是指符合下面两个条件之一:

2】判断某一年是否为闰年。所谓闰年, 

①能被4整除,但不能被100 整除;②能被4整除,又能被400 整除。
分析:对于条件①,能被4整除写作year%4==0,不能被100 整除写作year%100!= 
0。要求两者同时满足,内部是一个“逻辑与”的关系,可合并为year%4==0&&year% 
100!=0。

对于条件②,因为能够被400 整除一定能被4整除,所以第二个条件可以简化为能够被
400 整除,写作year%400==0。

条件①和条件②满足任何一个都是闰年,两者之间是“逻辑或”的关系。因此,判断闰年
条件的逻辑表达式表示为((year%4==0)&&(year%100!=0))||(year%400==0)。表
达式为“真”,闰年条件成立,是闰年;否则,不是闰年。

第
章

75

程序设计基础(C 语言)(第3 版) 
7 6 
【练习3.1】 输入3条边长,判断这3条边是否能构成一个三角形。假设用3个变量
x、y、z存放3条边的边长,以下哪一个表达式是正确的? 
A.x+y>z B.x+y>z,x+z>y,y+z>x 
C.x+y>z&&x+z>y&&y+z>x D.x+y>z||x+z>y||y+z>x 
3.2 分支结构
在生活中经常要做出选择,例如填报大学志愿时,有非常多的大学和非常多的专业,需
要根据自己的高考分数、自己的兴趣爱好等很多因素综合做出选择。根据一定的条件做出
不同的选择,在C语言中是用分支结构来实现的。
3.2.1 单分支结构
【例3.1】 编写一个程序,判断某一年是否为闰年。
分析:判断闰年的表达式已在问题描述3.2中给出,如果表达式值为真,则是闰年,输
出“xxxx年是闰年”;否则,不输出。
这类问题是根据条件是否成立来决定是否执行相应的命令,其执行过程如图3.1所示。
C语言提供了单分支选择结构解决上述问题,其一般形式: 
if (表达式) 
语句; 
图3.1 单分支选择结构条件语句执行过程
表达式是判断条件,只要表达式的值不为0,就认为条件成立。
例3.1的参考程序如下。 
1. #include <stdio.h> 
2. int main( ) 
3. { 
4. int Year; 
5. printf("Input year:"); 
6. scanf("%d", &Year); 
7. if (((Year%4==0)&&(Year%100!=0))||(Year%400==0)) //判断是否为闰年
8. printf("%d 年是闰年\n",Year); //条件成立,执行输出语句
9. return 0; 
10. } 
说明:表达式结果非0,执行printf语句,否则程序结束。
3-3单分支if

程序的控制结构
第3章
7 7 
【例3.2】 简单的字符加密,输入一个小写字母字符,按a→d,b→e,…,x→a,y→b,z→ 
c的加密规则对这个字符加密,然后输出加密后的字符。
分析:对于a~w这23个字母,加密方法很简单,直接对字符数据加3即可。关键是最
后3个字母x、y、z怎么处理。x+3后对应的ASCII码字符是{,怎么才能让它变成a呢? 
字母就26个,并且是连续的,是不是减掉26就可以回到起始的字母a了? 另外,还要注意
怎样表示字母的范围,这里就用到了上面讲到的关系运算与逻辑运算。
例3.2的参考程序如下。 
1. #include <stdio.h> 
2. int main() 
3. { 
4. char ch; 
5. scanf("%c", &ch); 
6. if(ch>='a' && ch<='w') printf("%c\n", ch+3); 
7. if(ch>='x' && ch<='z') printf("%c\n", ch-23); 
8. return 0; 
9. } 
想一想:第6行的条件是否可以写成if(a' '<=ch<='w' ),这样能否得到正确的输出? 
【练习3.2】 输入两个数,求最大数并输出,测试数据如下。 
输入:12 35 
输出:35 
【例3.3】 输入3个数x1、x2、x3,按从小到大的顺序输出这3个数。
分析:实际这就是一个排序的问题。为实现顺序输出,可以把最小数放到x1。如果
x1>x2,则交换两个数,同理x1和x3比较,x2和x3比较。这样经过交换,3个数按从小到
大的顺序分别存储在x1、x2、x3中。
交换两个数一般需要一个中间变量,可用3条赋值语句实现: 
temp=x1; 
x1=x2; 
x2=temp; 
if条件成立时,应该执行这3条语句,为此需要使用复合语句。
例3.3的参考程序如下。 
1. #include <stdio.h> 
2. int main( ) 
3. { 
4. int x1,x2,x3,temp; 
5. scanf("%d%d%d",&x1,&x2,&x3); 
6. if (x1>x2) 
7. { temp=x1; x1=x2; x2=temp; } //括号部分构成复合语句
8. if (x1>x3) 
9. { temp=x1; x1=x3; x3=temp; } //经过两次交换,x1 为三者中最小的
10. if (x2>x3) 
11. { temp=x2; x2=x3; x3=temp; } 
12. printf("%d,%d,%d", x1,x2,x3); 
13. return 0; 
14. }

程序设计基础(C 语言)(第3 版) 
7 8 
想一想:第7、9、11行的代码如果去掉花括号“{}”,对程序结果会不会造成影响? 
3.2.2 双分支结构
【例3.4】 编写一个密码判断程序,如果密码正确则给出正确提示,否则给出错误提示。
分析:根据密码正确与否,需要分别执行不同的语句,其执行过程见图3.2。
图3.2 双分支选择结构条件语句执行过程
C语言解决这类双分支选择结构的语句形式: 
if (表达式) 
语句1; 
else 
语句2; 
说明:if语句中的“表达式”一般为关系表达式或逻辑表达式,但不限于这两种表达式。
是执行语句1,还是执行语句2,取决于“表达式”运算的结果。
如果表达式的值不为0,则执行语句1;否则,执行语句2。同样,语句1和语句2既可以
是单语句,也可以是复合语句。
例3.4的参考程序如下。 
1. #include <stdio.h> 
2. int main() 
3. { 
4. int key; 
5. printf("请输入密码"); 
6. scanf("%d", &key); 
7. if(key==110) printf("密码正确,欢迎使用!\n"); 
8. else printf("对不起,密码错误!\n"); 
9. return 0; 
10. } 
【练习3.3】 一个整数,判断它的奇偶性,若是奇数则输出odd,若是偶数则输出even, 
测试数据如下。
测试数据1 测试数据2 
输入: 输入: 
23 32 
输出: 输出: 
odd even 
3-4双分支if

程序的控制结构
第3章
7 9 
【练习3.4】 输入3个整数,求最大数并输出,测试数据如下。 
输入:12 35 24 
输出:35 
3.2.3 多分支结构
表3.4 成人BMI指标
状态中国标准
偏瘦BMI<18.5 
正常18.5≤BMI<24 
偏胖24≤BMI<28 
肥胖BMI≥28 
【问题描述3.3】 身体质量指数(BodyMassIndex,BMI)简
称体指数,是目前国际相对常用的一种衡量人体胖瘦程度以及健
康状况的指标,计算公式是:体指数=体重(kg)÷身高(m)2。
例如,若体重=55.8kg,身高=1.70m,则BMI=55.8÷ 
(1.70)2=19.31。
成人BMI指标分为4种状态,对应的中国标准如图3.4所示。
如果编程实现BMI的判断,会发现这里分了4种状态,一
个if…else…是不够用的,所以需要用到多分支的选择结构。
多分支结构的语句形式: 
if (表达式1) 
语句1; 
else if (表达式2) 
语句2; 
else if (表达式3) 
语句3; 
. 
else if (表达式n) 
语句n; 
else 
语句n+1; 
多分支选择结构的功能是,按顺序求各表达式的值。如果某一表达式的值为真(非0), 
那么执行其后相应的语句,执行完后整个if语句结束,其余语句则不被执行;如果没有一个
表达式的值为真,那么执行最后的else语句,执行过程如图3.3所示。
问题描述3.3的计算体指数的参考程序如下。 
1. #include<stdio.h> 
2. int main( ) 
3. { 
4. double w, h, b; //w 表示体重,h 表示身高,b 表示BMI 
5. scanf("%lf%lf", &w, &h); 
6. b=w/(h*h); 
7. printf("BMI=%.2lf\n", b); 
8. if (b<18.5) printf("偏瘦!\n"); 
9. else 
10. if (b<24) printf("正常!\n"); 
11. else 
12. if (b<28) printf("偏胖!\n"); 
13. else 
14. printf("肥胖!\n"); 
15. return 0; 
16. } 
3-5多分支
结构

程序设计基础(C 语言)(第3 版) 
8 0 
图3.3 多分支选择结构条件语句执行过程
想一想:第6行,如果去掉小括号,写成b=w/h*h;,那么计算结果还对吗? 
第10行,if的条件为什么不写成if(b>=18.5&&b<24)? 
第12行,类似的问题,为什么不写或if(b>=24&&b<28)? 
第13行,为什么else后不写或if(b>=28)? 
再来看一个多分支结构在数学问题上的应用。
【例3.5】 设有分段函数如下,编写程序,输入x,计算并输出y值。
y= 
-e2x+1+3 x<-2 
2x-1 -2≤x≤3 
3lg(3x+5)-11 x>3 
ì
.
í
.. 
.. 
分析:需要对输入的x值进行判断,若x﹤-2,则计算y=-e2x+1+3,程序结束;否则, 
若x≤3(此处不用判断x是否大于或等于-2,为什么?),则计算y=2x-1;否则,计算y= 
3lg(3x+5)-11。在这里,涉及多个条件的判断,并根据判断结果选择不同的公式计算y 
值,因此需要使用多分支结构。
例3.5的参考程序如下。 
1. #include <stdio.h> 
2. #include<math.h> //包含数学函数的头文件
3. int main( ) 
4. { 
5. double x, y; 
6. printf("Input x:"); 
7. scanf("%lf", &x); //这里需用%lf,因x 是double 型
8. if (x<-2) y=-exp(2*x+1)+3; // exp 是以e 为底的指数函数
9. else if (x<=3) y=2*x-1;

程序的控制结构
第3章
8 1 
10. else y=3*log10(3*x+5)-11; / /log10 是以10 为底的对数函数,即lg 
11. printf("y=%.2lf\n", y); 
12. return 0; 
13. } 
说明:在本例中用到exp和log10两个数学函数,分别是以e为底的指数函数和以10 
为底的对数函数,它们都只有一个参数,计算结果均为double型。这两个函数是系统提供
的,为了使用这些数学函数,需要包含头文件math.h,该文件还包含了许多常用的数学函
数,具体可参见附录C.2中的math.h头文件。
【例3.6】 某公园的票价是每人10元,一次购票满30张,每张票可以少收1元,试编写
一个自动计费程序。
分析:该问题根据购票数是否大于或等于30计算相应的费用。设购票数用number表
示,金额用money表示。若购票数少于30,money=number×10;否则,money=number×9,这
可以用分支语句实现。但是,若购29张票,money=number×10=290元,若购30张,money= 
30×9=270元。显然,这时购30张票更省钱。因此number<30时,需要考虑人数少于30人
的情况下,number×10是否大于270,若money>270,则应按30张票收费,这时需要再次进行
判断。为了完善功能程序功能,增强实用性,应计算出实收金额与门票的差额。
例3.6的参考程序如下。 
1. #include <stdio.h> 
2. int main( ) 
3. { 
4. int iNumber, iSum, iMoney, iBalance; 
5. printf("Input the number of entering park:"); 
6. scanf("%d",&iNumber); 
7. if (iNumber>=30) iMoney=iNumber*9; 
8. else if (10*iNumber<270) iMoney=10*iNumber; 
9. else { iMoney=270; iNumber=30; } 
10. printf("cost:%d yuan\n", iMoney); 
11. printf("Input Money:"); 
12. scanf("%d", &iSum); 
13. iBalance=iSum-iMoney; 
14. printf("Tickets Money Cost Balance\n"); 
15. printf("%d,%d,%d,%d\n", iNumber, iSum, iMoney, iBalance); 
16. return 0; 
17. } 
【例3.7】 编程计算个人所得税。目前我国实施的个人所得税率征收规定:个税起征
点为5000元,适用7级超额累进税率,具体税率如表3.5所示。
应纳税所得额的计算公式: 
应纳税所得额=月度收入-5000元(起征点)-专项扣除(三险一金等)- 
专项附加扣除-依法确定的其他扣除
三险一金是指养老保险、医疗保险、失业保险和住房公积金。
为了编程计算简单,可以对公式进行简化:

程序设计基础(C 语言)(第3 版) 
8 2 
应纳税所得额=月度收入-5000元
个税=应纳税所得额×税率-速算扣除数
表3.5 个人所得税税率表
应纳税额税率/% 速算扣除数/元
① 不超过3000元的部分3 0 
② 超过3000元至12000元的部分10 210 
③ 超过12000元至25000元的部分20 1410 
④ 超过25000元至35000元的部分25 2660 
⑤ 超过35000元至55000元的部分30 4410 
⑥ 超过55000元至80000元的部分35 7160 
⑦ 超过80000元的部分45 15160 
分析:由于个人所得税采取分段税率,逐段叠加,因此可以从最高税率段开始计算,采
用if的多分支结构实现。为了简化,在程序中暂时忽略三险一金,只输入工资,若工资小于
或等于5000元,则不交税,可以直接结束程序;若工资大于5000元,则用工资减去5000,得
到应纳税所得额,然后根据表3.5进行计算。
例3.7的参考程序如下。 
1. #include <stdio.h> 
2. int main() 
3. { 
4. double fIncome, fTax; int k; 
5. printf("请输入你的工资:"); 
6. scanf("%lf",&fIncome); //double 型数据用%lf 输入
7. if(fIncome<=5000) 
8. { printf("免征个人所得税!\n"); return 0; } //直接结束main 函数
9. else fIncome=fIncome-5000; //工资减5000 后的金额为应纳税额
10. if(fIncome>80000) fTax=fIncome*0.45-15160; 
11. else if(fIncome>55000) fTax=fIncome*0.35-7160; 
12. else if(fIncome>35000) fTax=fIncome*0.30-4410; 
13. else if(fIncome>25000) fTax=fIncome*0.25-2660; 
14. else if(fIncome>12000) fTax=fIncome*0.20-1410; 
15. else if(fIncome>3000) fTax=fIncome*0.10-210; 
16. else fTax=fIncome*0.3; 
17. printf("你应交个人所得税为:%.2lf\n", fTax); 
18. return 0; 
19. } 
【例3.8】 在学生成绩管理中,成绩经常要在百分制与等级制之间进行转换。90分以
上为A 等,80~89分为B等,70~79分为C等,60~69分为D等,其余为E等。编写程序, 
根据输入的百分制,输出对应的等级。
分析:设用变量fscore表示成绩,而等级是依据fscore的值变化的,共有5种情况,如
表3.6所示。

程序的控制结构
第3章
8 3 
表3.6 百分制成绩对应等级的判断方法
成 绩等 级判断方法
fscore>=90 A fscore/10=10或9 
80<=fscore<90 B fscore/10=8 
70<=fscore<80 C fscore/10=7 
60<=fscore<70 D fscore/10=6 
fscore<60 E fscore/10=其他值 
很明显这是一个多分支问题,利用多分支if语句完全可以解决这类问题。但是,如果
if…else…语句过多,则会令人眼花缭乱。幸运的是,C 语言提供了另一种多分支语句
switch语句。
switch语句的基本格式: 
switch(表达式) 
{ 
case 常量表达式1:语句组1;[break;] 
case 常量表达式2:语句组2;[break;] 
… 
case 常量表达式n:语句组n;[break;] 
[ default: 语句组n+1 ] 
}
说明:①switch后圆括号中的表达式,只能是整型、字符型或枚举型表达式。其中枚
举数据类型在以后学习。
② 当表达式的值与某个case后面的常量表达式的值相等时,就执行此case后面的语
句。执行完后,流程控制转移到下一个case(包括default)中的语句继续执行。如果不想继
续执行,就需要使用break语句使流程跳出switch结构,即终止switch语句的执行,最后一
个分支可以不用break语句。这里的[]表示该项是可选项,可以不写。
③ 如果表达式的值与所有常量表达式都不匹配,就执行default后面的语句。如果没
有default就跳出switch,执行switch语句后面的语句。
④ 各个常量表达式的值必须互不相同,否则会出现矛盾。
⑤case后面允许有多条语句,且可以不用花括号“{}”括起来。
例3.8的参考程序如下。 
1. #include <stdio.h> 
2. int main( ) 
3. { 
4. int iScore, temp; 
5. printf("Input score of student:"); 
6. scanf("%d",&iScore); 
7. temp=iScore/10; 
8. switch(temp)

程序设计基础(C 语言)(第3 版) 
8 4 
9. { case 10: 
10. case 9: printf("A"); break; 
11. case 8: printf("B"); break; 
12. case 7: printf("C"); break; 
13. case 6: printf("D"); break; 
14. default: printf("E"); 
15. } 
16. return 0; 
17. } 
说明:本例中,temp=10和temp=9都输出A,共用输出语句printf("A");,所以case 
10:后面不使用break语句,就会继续向下执行,直到遇到break语句终止,达到了共用
prinft("A")的目的。由于以后的语句不再共享,每次输出后,都必须使用break终止。否
则,程序将继续执行下面的语句。
另外,default可以放在switch语句中的任意位置,但要注意,如果default不是放在最
后,则它后面也要写上break语句。上例中的switch语句也可以写成以下形式。 
switch(temp) 
{ default: printf("E"); break; //这里需要写上break 语句 
case 10: 
case 9: printf("A"); break; 
case 8: printf("B"); break; 
case 7: printf("C"); break; 
case 6: printf("D"); break; 
} 
3.2.4 if语句的嵌套
【例3.9】 编程实现一个猜数游戏。程序给出一个数字,如果游戏者猜对了则显示You 
areright!,否则显示Youarewrong!,并提示游戏者是猜大了还是猜少了。
分析:该问题与前面几个问题的不同之处在于,如果条件不成立,先显示提示信息,然
后再判断猜大了还是猜少了。也就说,第二个判断是嵌在第一个判断条件不成立语句中,这
是一种if语句的嵌套形式。
所谓if语句的嵌套,是指if语句的if块或else块中又包含一个完整的if语句。
if语句的嵌套的一般形式: 
if (表达式1) 
if (表达式2) 语句1; 
else 语句2; 
else 
if (表达式3) 语句3; 
else 语句4; 
对于嵌套结构,必须注意else与if的配对关系。C语言规定else总是与它前面最近的, 
而且没有与其他else配对的if进行配对。特别是if…else子句数目不一样时(if的数量只
会大于或等于else的数量)。例如: 
3-6if语句
的嵌套

程序的控制结构
第3章
8 5 
if (表达式1) 
if (表达式2) 语句1; 
else 语句2; 
根据C语言规定,上面else应与第二个if配对。如果希望else与第一个if配对,可以
将第二个if用一对花括号“{}”括起来,即写成下面的形式: 
if (表达式1) 
{ if (表达式2) 语句1; } 
else 语句2; 
例3.9的参考程序如下。 
1. #include <stdio.h> 
2. int main() 
3. { 
4. int iOrigNum=555, iInputNum; //iOrigNum 表示要猜的数,初始设定为555 
5. printf("Please input a integer number:\n "); 
6. scanf("%d",& iInputNum); //输入游戏者猜的数
7. if (iInputNum ==iOrigNum) //判断是否相等
8. printf("You are right!\n"); 
9. else //else 表示两个数不相等,即猜错了
10. { printf("You are wrong!\n"); 
11. if (iInputNum > iOrigNum) printf("Your number is bigger!\n"); 
12. else printf("Your number is smaller!\n"); 
13. } 
14. return 0; 
15. } 
一元二次方程求根是初中数学知识,现在可以用C语言编程来进行求解。
【例3.10】 求一元二次方程ax2+bx+c=0的根,a、b、c由键盘输入。
分析:对于一元二次方程,有以下几种可能。
如果a=0,不是二次方程,不需要求解。
如果a!=0,是二次方程,求根又分为以下3种情况: 
b2-4ac=0,有两个相等的实根; 
b2-4ac>0,有两个不等的实根; 
b2-4ac<0,有两个共轭复数根。
该问题有多个条件,这就涉及条件语句的嵌套问题;另外,由于该问题涉及开平方运算, 
有可能出现无限小数,为此需要设置一个最小值,小于或等于该值就认为是0。这里使用C 
语言提供的开平方函数sqrt、取绝对值函数fabs,所以在程序开始必须包含math.h头文件。
因为实数在内存中是不精确表示的,所以一般不用==判断一个实数是否等于0。常
用的方法是判断一个实数是否小于一个足够小的数(如0.000001,即1E-6),若是,即可认定
该实数等于0。用N-S图描述的求解二元一次方程的算法如图3.4所示。
例3.10的参考程序如下。 
1. #include <stdio.h> 
2. #include <math.h> //包含数学函数头文件

程序设计基础(C 语言)(第3 版) 
8 6 
3. int main( ) 
4. { 
5. double a, b, c, disc, x1, x2, rpart, ipart; 
6. scanf("%lf%lf%lf", &a, &b, &c); 
7. if (fabs(a)<=1E-6) //如果a=0,则输出不是一元二次方程
8. printf("It isn't a quadratic.\n"); 
9. else //若a 不等于0,则计算方程的根
10. { disc=b*b-4*a*c; // 计算disc 
11. if (fabs(disc)<=1E-6) // 若disc 等于0,则输出两个相等的实根
12. printf("two equal roots: \n%.2lf\n", -b/(2*a)); 
13. else 
14. { if (disc>1E-6) //若disc 大于0,则输出两个不等的实根
15. { x1=(-b+sqrt(disc))/(2*a); 
16. x2=(-b-sqrt(disc))/(2*a); 
17. printf("two distinct real roots: \n%.2lf, %.2lf\n", x1, x2); 
18. } 
19. else //若disc 小于0,则输出两个不等的虚根
20. { rpart=-b/(2*a); 
21. ipart=sqrt(-disc)/(2*a); 
22. printf("two complex roots: \n%.2lf+%.2lfi, %.2lf-%.2lfi\n", 
23. rpart, ipart, rpart, ipart); 
24. } 
25. } 
26. } 
27. return 0; 
28. } 
图3.4 用N-S图描述的求解二元一次方程的算法
说明:在本例中,要特别注意花括号“{}”的使用,左括号“{”一定与最近的右括号“}” 
结合成一对,而不能交叉。if…else…在逻辑上是一条语句。另外,格式缩进规范很容易看
清楚if与else的配对关系,有利于减少出错概率。
程序运行输出: 
测试数据1 测试数据2 测试数据3 测试数据4 输入: 输入: 输入: 输入: 
1 2 1 1 0 -1 2 1 2 0 1 2 
输出: 输出: 输出: 输出: 
two equal roots: 
-1.00 
two distinct real roots: 
1.00, -1.00 
two complex roots: 
-0.25+0.97i, -0.25-0.97i It isn't a quadratic.

程序的控制结构
第3章
8 7 
3.2.5 条件运算符
条件运算在程序设计过程中经常遇到,有些if语句非常简单,可直接用条件运算来实
现。例如,两个数取最大数,用if语句可以写成如下形式。 
if (a>b) max=a; 
else max=b; 
对于这种非常简单的if语句,C语言提供了一种方便格式,即条件运算符。
条件运算符“? :”是if语句的缩写形式,是唯一的三目运算符。
条件表达式的一般形式: 
表达式1? 表达式2:表达式3 
条件表达式的功能是,先计算表达式1的值,若为真(非0),则取表达式2的值为整个
条件表达式的值;若表达式1的值为假(0),则取表达式3的值为整个条件表达式的值。其
执行过程如图3.5所示。
图3.5 条件运算符执行过程
若if语句中,在表达式为“真”和“假”时,都只执行一个赋值语句且给同一个变量赋值
时,可以使用简单的条件运算符来处理。
上面两个数取最大数的if语句可以用条件运算符写成: 
max=a>b? a:b; 
该式中,如果a>b成立,则max=a;否则,max=b。
说明:① 条件运算符的优先级高于赋值运算符,低于关系运算符和算术运算符。
例如,max=a>b? a:b等价于max=((a>b)? a:b)。
② 条件运算符的结合性为“自右向左”。
例如,a>b? a:c>d? c:d等价于(a>b)?a:((c>d)? c:d)。
③ 表达式2和表达式3不仅可以是数值表达式,还可以是赋值表达式或函数表达式。
例如,a>b? (a=100):prinf("%d\n",b)。
④ 表达式1、表达式2和表达式3的类型都可以不同。条件表达式值的类型是表达式
2和表达式3中类型较高的类型。
例如,x>y? 1:1.5,当x>y时条件表达式的值为double型数据1.0。
【例3.11】 输入一个字符,如果是大写字母则转换为小写,否则不转换。输出最后得到
3-7条件
运算符

程序设计基础(C 语言)(第3 版) 
8 8 
的字符。
分析:判断字符变量ch是否是大写字母,可以用ch>='A'&&ch<='Z'实现,若是大
写字母则需要转换,否则ch不变。大写字母转换为小写字母采用ch=ch+32。
例3.11的参考程序如下。 
1. #include<stdio.h> 
2. int main( ) 
3. { 
4. char ch; 
5. printf("请输入一个字符:\n"); 
6. ch=getchar(); 
7. ch= (ch>='A'&&ch<='Z') ?(ch+32):ch; 
8. printf("%c",ch); 
9. return 0; 
10. } 
说明:表达式ch= (ch>='A'&&ch<='Z')? (ch+32):ch中的圆括号可以不要,但
有圆括号程序看上去会更加清晰。
3.3 循环结构
3.3.1 循环的引出 
例3.9猜数游戏,只能猜一次,这样玩起来不过瘾。既然猜错时程序可以提示是猜大了
还是猜小了,我们多猜几次应该就可以猜对了,如果要实现只有猜对了才结束程序,那么程
序该如何编写? 先看看例3.9的程序代码: 
1. #include <stdio.h> 
2. int main() 
3. { 
4. int iOrigNum=555, iInputNum; //iOrigNum 表示要猜的数,初始设定为555 
5. printf("Please input a integer number:\n "); 
6. scanf("%d",& iInputNum); //输入游戏者猜的数
7. if (iInputNum ==iOrigNum) //判断是否相等
8. printf("You are right!\n"); 
9. else //else 表示两个数不相等,即猜错了
10. { printf("You are wrong!\n"); 
11. if (iInputNum > iOrigNum) printf("Your number is bigger!\n"); 
12. else printf("Your number is smaller!\n"); 
13. } 
14. return 0; 
15. } 
如果将程序重复写下去是可以的,但是我们不知道该写多少次,因为不知道多少次才会
猜对。即使知道,但这种方式显然也是不可取的,太麻烦了。事实上,每次猜数的操作都是
一样的,如果猜错了则回到程序的第5行再继续运行就可以了,如果猜对了则结束运行。
在解决实际问题的过程中,许多问题的求解都归结为重复执行的操作,例如数值计算中
的方程迭代求根、非数值计算中的对象遍历。重复执行就是循环,循环是计算机特别擅长的

程序的控制结构
第3章
8 9 
工作之一。循环并不是简单地重复,每次循环,操作的数据(状态、条件)都可能发生变化。
循环的动作是受控制的,例如满足一定条件才继续做,一直做到某个条件满足或者做多少次
才能结束。也就是说,重复工作需要进行控制———循环控制。C语言提供了3种循环控制
语句(不考虑goto和if构成的循环),构成了3种基本的循环结构。
(1)while循环:先判断条件,再执行循环体。
(2)do-while循环:先执行循环体,再判断条件。
(3)for循环:先判断条件,再执行循环体。
3.3.2 while循环
在第2章编程输出星号组成的图形,如一个星号矩形,那时写的程序是这样的,有没有
觉得这程序实在是“低级”。 
#include<stdio.h> 
int main( ) 
{ 
printf("******\n"); 
printf("******\n"); 
printf("******\n"); 
printf("******\n"); 
printf("******\n"); 
return 0; 
}
现在还是输出这个星号矩形,可以把程序写得“高级”一点。循环是重复做一件事,上面
这个程序中,printf("******\n");重复了5次,现在这个重复的语句只需要写一次,然后控
制它执行5次。为了控制5次,还需要一个计数器。计数器其实就是一个整型变量,每执行
一次星号输出,这个整型变量就加1,当计数器等于5时就可以结束循环。现在可以把上面
的程序改写如下。 
#include<stdio.h> 
int main( ) 
{ 
int i ; //i 就是计数器 
i=0; //i 初值赋为0 
while ( i<5 ) 
{ printf("******\n"); 
i=i+1; 
} 
return 0; 
}
虽然还没有讲while循环,但是这个代码也基本能看懂。while(i<5)就是当i<5成
立时,输出一行星号,然后计数器i加1;当i<5不成立时,就结束循环。
while循环的一般形式: 
while ( 表达式) 
语句; 
3-8while 
循环

程序设计基础(C 语言)(第3 版) 
9 0 
这里的表达式也称为“循环条件”,语句则称为“循环体”。
while循环的执行过程:先计算while后面表达式的值,如果其值为“真”(非0)则执行
图3.6 while的执行过程
循环体。执行完循环体后,再次计算while后面表达式的值,如果
值为“真”,则继续执行循环体,如果表达式值为“假”;则退出循
环。while的执行过程如图3.6所示。
使用while语句需要注意以下几点。
① while语句的特点是先计算表达式的值,然后根据表达式
的值决定是否执行循环体中的语句。因此,如果表达式的值一开
始就为“假”,那么循环体一次也不执行。
② 当循环体为多个语句组成时,必须用花括号“{}”括起来, 
构成复合语句。while(表达式)后面不能有分号“;”,因为分号代表一条空语句,这样写循
环体就成空语句了。
③ 在循环体中使用的语句一般应保证产生满足循环终止条件的结果,以避免“无限循
环”的发生。
下面是例3.9猜数游戏升级版的参考程序。 
1. #include <stdio.h> 
2. #include <stdlib.h> // 包 含 该 文件才能调用exit 函数
3. int main() 
4. { 
5. int iOrigNum=555, iInputNum; 
6. while (1) //while 的表达式为1,表示条件始终满足,即永真循环
7. { printf("Please input a integer number:\n "); 
8. scanf("%d", &iInputNum); 
9. if (iInputNum==iOrigNum) 
10. { printf("You are right!\n"); 
11. exit(0); //exit 函数的作用是退出程序,返回操作系统
12. } 
13. else 
14. { printf("You are Wrong!\n"); 
15. if (iInputNum>iOrigNum) printf("Your number is bigger!\n"); 
16. else printf("Your number is smaller!\n"); 
17. } 
18. } //end while 
19. return 0; 
20. } 
说明:本程序里使用了while(1)循环,循环条件直接用常数1,因为1就表示“真”,即循
环条件永远是成立的,因为这里我们不知道猜几次才能猜对,所以循环条件这里没法用具体
的次数来控制。但是一个程序不能永远循环下去,猜对时应该结束程序,这里用了一个退出
函数exit(0);直接结束程序。当然也可以直接用return0;语句,效果是一样的。
下面来看一个经典的例题,它“红”的程度不亚于“Helloworld!”程序。只要讲循环结
构,第一个例题基本都会用这个小学一年级的加法题目。
【例3.12】 编写程序计算:1+2+3+…+100。
分析:该程序是100个数的累加,加数每次增1,如果不采用等差数列求和公式来计算,

程序的控制结构
第3章
9 1 
可用循环结构来实现。设sum 的初值为0,加数i的初值为1,算法描述如下。
图3.7 求和运算N-S图
step1:sum=0,i=1(循环初值)。
step2:当i<=100时,重复执行sum=sum+i;i=i+1;(即
循环体语句);否则,结束循环。
step3:输出sum 的值(即1+2+…+100的结果)。
算法的N-S图表示如图3.7所示。
例3.12的参考程序如下。 
1. #include <stdio.h> 
2. int main( ) 
3. { 
4. int i=1, sum=0; 
5. while (i<=100) 
6. { sum=sum+i; 
7. i++; 
8. } 
9. printf("sum=%d\n",sum); 
10. return 0; 
11. } 
编写循环程序要注意以下几个问题。
① 遇到数列求和、求积这类问题,一般可以考虑使用循环解决。
② 注意循环初值的设置,一般对于累加器常设置为0,累乘器常设置为1。
③ 循环体中为需要重复做的工作,同时要保证使循环逐渐趋于结束。循环的结束由
while中的表达式(条件)控制。
从这个问题可以看出,循环给编程带来很大方便,对于例3.4密码检查程序,可以利用
循环修改,在密码输入错误时,给用户3次输入机会。对于例3.1的闰年判断程序、例3.6的
公园门票计算程序、例3.8的学生成绩分级程序,都可以利用循环实现多次运行。读者可以
自行改写这些程序。
3.3.3 do-while循环
do-while循环的一般形式: 
do 
{ 
语句; 
}while(表达式); 
这里的表达式称为“循环条件”,语句称为“循环体”。
do-while循环的执行过程:先执行do后面的循环体语句。然后计算while后面表达式
的值,如果其值为“真”(非0),则继续执行循环体;如果表达式的值为“假”(0),则退出循环。
do-while的执行过程如图3.8所示。
说明:①do-while循环与while循环十分相似,它们的主要区别是:while循环先判断
循环条件再执行循环体,循环体可能一次也不执行。do-while总是先执行一次循环体,然后
3-9do-while 
循环

程序设计基础(C 语言)(第3 版) 
9 2 
图3.8 do-while的
执行过程
再求表达式的值,因此,无论表达式是否为“真”,循环体至少执行一次。
② 当do-while语句的循环体语句中只有一条语句时也可不用花
括号,但是加上花括号可增加程序的可读性。
【例3.13】 编写程序计算:1+2+3+…+n,其中n是由键盘输
入的任意正整数。
分析:该题与例3.12相似,只是将100改成了n,而n的值由键盘
输入,这样具有更好的灵活性。这里对例3.12的代码进行一些修改, 
并使用do-while编程实现。
例3.13的参考程序如下。 
1. #include <stdio.h> 
2. int main( ) 
3. { 
4. int n, i=1, sum=0; 
5. printf("input n: "); 
6. scanf("%d", &n); 
7. do 
8. { sum=sum+i; 
9. i++; 
10. } while (i<=n); 
11. printf("sum=%d\n",sum); 
12. return 0; 
13. } 
【例3.14】 编写一个简单教学程序,训练小学生的加减法,能够随机产生两位数的加减法
测试题。若结果错误则提示练习者重新计算,若结果正确则给予表扬,并询问练习者是否继续。
分析:根据问题要求,首先需要使用随机数函数,利用随机数函数,产生100以内的两
个数;再产生2以内的一个随机数,当随机数为0时运算符为减号,随机数为1时运算符为
加号。在屏幕上输出加法或减法的算式,学生输入计算结果,判断学生计算结果是否正确, 
给出相应答复。询问是否继续做题,如回答y或Y 则进入下一次循环,否则退出。需要注
意的是,如果减数大于被减数,需要将两个数交换。该问题至少要进行一次运算才可以退
出,因此是一种直到型循环。
例3.14的参考程序如下。 
1. #include<stdio.h> 
2. #include<stdlib.h> //该头文件中有rand、srand、system 函数的函数声明
3. #include<time.h> //该头文件中有time 函数的函数声明
4. int main() 
5. { 
6. int x, y, comp, result, temp; 
7. char ch, choice; 
8. srand(time(0)); //获取系统时间作为随机数的种子
9. do 
10. { system("cls"); //调用系统命令———清除屏幕
11. x=rand()%100; //rand 函数产生一个0~32767 的随机整数
12. y=rand()%100; //通过取余运算可将产生的随机数控制在0~99