1清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础乔 林计算机程序设计基础
Email,qiaolin@cic.tsinghua.edu.cn
Tel,62792961
2清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础第三章 程序控制结构
学习目标
– 了解结构化程序设计的一般概念
– 熟悉顺序结构、分支结构与循环结构等三种程序流程控制结构
– 掌握 C 语言实现分支结构的 if 语句与 switch 语句,能熟练应用 if 语句与 switch 语句编写程序
– 掌握 C 语言实现循环结构的 while 语句,for 语句与 do-while 语句,能熟练应用这三种循环控制结构编写程序
– 了解三种循环结构的关系,掌握在循环结构中控制程序流程转移的方法
3清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
3.1 C 语言结构化程序设计基础
程序的控制结构(黑箱)
– 单入口单出口的控制结构易于理解
– 三种基本控制结构:顺序、分支、循环
– 控制结构可以嵌套,以构成更复杂的控制结构
程序的结构化
– 三种基本控制结构可以构造任何复杂的结构化算法
– 结构化程序设计原则,自顶向下,逐步求精
– 结构化程序设计过程:首先对任务进行功能分解,然后使用结构化程序设计思想逐一解决各个子问题,最后构造原始问题的解
– 好处:逻辑性强,可读性好,维护方便
4清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
3.2 顺序结构
顺序结构的含义
– 由一组顺序执行的处理块组成,每个处理块可能包含一条或一组语句,完成一项任务
– 顺序结构是最基本的算法结构
A B
入口 出口顺序结构
语句与复合语句(语句块)
– 三种语句结构:单语句( 表达式 ;)、空语句( ;)、复合语句( {语句序列 })
5清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础顺序结构程序示例
分别输入两个复数的实部与虚部,计算两个复数的和、差、积、商并输出结果
#include <stdio.h>
int main()
{
float a,b,c,d,real,imaginary;
printf(?Input reals and imaginaries of two complexes\n?);
scanf(?%f,%f,%f,%f?,&a,&b,&c,&d);
printf(?Sum,%f + %fi\n?,a + c,b + d);
printf(?Difference,%f + %fi\n?,a – c,b – d);
real = a * c – b * d; imaginary = a * d + b * c;
printf(?Product,%f + %fi\n?,real,imaginary);
real = (a*c + b*d) / (c*c + d*d); imaginary = (b*c – a*d) / (c*c + d*d);
printf(?Quotient,%f + %fi\n?,real,imaginary);
return 0;
}
实际需要输入 4个实数
6清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
3.3 分支结构
分支结构(选择结构)的含义
– 根据某一条件的判断结果,确定程序的流程,即选择哪一个程序分支中的处理块去执行
– 最基本的分支结构是二路分支结构
– 以条件判断为起点,如果判断结果为真,则执行 A处理块的操作,否则执行 B处理块的操作入口分支结构真假出口
A
B
条件
7清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
if-else 语句
语句格式,if(表达式 ) 语句 1 else 语句 2
表达式必须位于括号内,一般为关系或逻辑表达式
先计算表达式值,若为真则执行语句 1,否则执行语句 2
语句 1与语句 2可以为复合语句
语句 1与语句 2只能有一个被执行
如果仅仅用于确定某条语句是否执行,else分支可以省略
8清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
if-else 语句示例一
输入一个字符,判断它是否为 0~9之间的数字
#include <stdio.h>
int main()
{
char c;
printf(?Input a character,?);
c = getchar();
if(c >= 48 && c <= 57)
printf(?It is a number.\n?);
else
printf(?No,it is not a number.\n?);
return 0;
}
因:字符以 ASCII码值存储且数字的 ASCII码值 48~57
故:比较 ASCII码值
9清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
if-else 语句示例二
输入一个整数,输出其绝对值
#include <stdio.h>
int main()
{
int n,abs;
printf(?Enter integer,?);
scanf(?%d?,&n);
abs = n;
if(abs < 0)
abs = –abs;
printf(?Original integer,%d,absolute value,%d\n?,n,abs);
return 0;
}
入口单分支结构真假出口
A
条件
10清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
if-else if-else 语句
语句格式
– if(表达式 1) 语句 1 else if(表达式 2) 语句 2 < else 语句 n
入口 复杂分支结构真假出口真假假语句 1
表达式 1
表达式 2
语句 2
...
语句 n
11清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
if-else if-else 示例
根据百分制成绩给出优秀、通过或不通过成绩
#include <stdio.h>
int main()
{
float score;
printf(?Input score,?);
scanf(?%f?,&score);
if(score >= 85 && score <= 100) printf(?Excellent.\n?);
else if(score >= 60 && score < 85) printf(?Pass.\n?);
else if(score >= 0 && score < 60) printf(?No pass.\n?);
else printf(?Error score.\n?);
return 0;
}
12清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础条件分支的嵌套
条件语句的嵌套格式
– 当年龄大于 50岁时,若工资小于 500,则长 200,
否则长 300 if(age > 50)
if(sal < 500)
sal += 200;
else
sal += 300;
– 若年龄大于 50岁且工资小于 500,长 200;
若年龄不大于 50岁,
则长 300
语法规定,else与离它最近的 if配对
嵌套的条件语句可以实现复杂的逻辑判断
else
if(age > 50)
{
if(sal < 500)
sal += 200;
}
else
sal += 300;
13清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础条件分支嵌套示例
求方程 ax2 + bx + c = 0 的根
#include <stdio.h>
#include <math.h> // 由于用到平方根函数,要用此头文件
int main()
{
float a,b,c,x1,x2,p,q,m; // 定义实型变量
printf(?Enter 3 coefficients,?) ;
scanf(?%f,%f,%f?,&a,&b,&c); // 从键盘读入方程的三个系数
if( a == 0.0 && b == 0 && c == 0 ) // 分支 1:三个系数全为 0
printf(?any value\n?);
else if( a == 0 && b != 0 ) // 分支 2:系数 a为 0,解一元一次方程
printf(?x1 = x2 = %f\n",– c / b);
else // 分支 3:解一元二次方程的两个根
{
m = b * b – 4.0 * a * c;
<
14清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础条件分支嵌套示例
if( m >= 0 )
{ // 解实根
x1 = ( –b + sqrt(m) ) / ( 2.0 * a );
x2 = ( –b – sqrt(m) ) / ( 2.0 * a );
printf(?x1 = %f\n?,x1 ); // 输出两个实根
printf(?x2 = %f\n?,x2 );
}
else
{ // 解虚根
p = –b / ( 2.0 * a );
q = sqrt(–m) / ( 2.0 * a );
printf(?x1 = %f + %fi\n?,p,q);
printf(?x2 = %f – %fi\n?,p,q);
}
}
return 0;
}
15清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
switch 分支语法
计算过程
– 先计算表达式的值
– 依次与一组常量比较
– 若相同则执行该分支
– 否则转向 default分支
– 退出 switch语句
说明
– switch后面的表达式必须为整型、字符型或枚举型
– case后面必须为常量表达式,则各个 case值必须不同
– 如果没有 default子句,且没有 case子句匹配,则不执行
– case分支中的语句可以有多条,不需要花括号
switch( 表达式 )
{
case 常量表达式 1,语句组 1
case 常量表达式 2,语句组 2

case 常量表达式 n,语句组 n
default,语句组
}
16清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
switch 分支流程图入口
s witc h 分支结构
c as e
出口语句组 1 语句组 2
...
s witc h 表达式
c as e 值 2值 1
语句组 n
c as e 值 n
语句组
d ef au lt
17清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
switch 分支示例一
根据输入的成绩等级,打印相应分数段
#include <stdio.h>
int main()
{
char grade; printf(?Input the grade(A,B,C,D,E):?); scanf(?%c?,&grade);
switch( grade )
{
case ‘A‘,printf(?90-100\n?); break;
case ‘B‘,printf(?80-89\n?); break;
case ‘C‘,printf(?70-79\n?); break;
case ‘D‘,printf(?60-69\n?); break;
case ‘E‘,printf(?0-59\n?); break;
default,printf(?Error\n?);
}
return 0;
}
18清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
switch 分支示例一
根据输入的成绩等级,打印相应分数段
#include <stdio.h>
int main()
{
char grade; printf(?Input the grade(A,B,C,D,E):?); scanf(?%c?,&grade);
switch( grade )
{
case ‘A‘,printf(?90-100\n?);
case ‘B‘,printf(?80-89\n?);
case ‘C‘,printf(?70-79\n?);
case ‘D‘,printf(?60-69\n?);
case ‘E‘,printf(?0-59\n?);
default,printf(?Error\n?);
}
return 0;
}
break的目的是终止 switch语句的执行。如果没有 break语句,则程序会从指定的 case分支开始,并在该分支结束后继续执行下去。除非
switch语句结束,后面的其他 case
分支或 default分支中的语句都会得到执行
19清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
switch 分支示例二
根据输入的成绩等级,打印是否通过信息
#include <stdio.h>
int main()
{
char grade; printf(?Input the grade(A,B,C,D,E):?); scanf(?%c?,&grade);
switch( grade )
{
case ‘A‘:
case ‘B‘:
case ‘C‘:
case ‘D‘,printf(?Pass\n?); break;
case ‘E‘,printf(?Fail\n?); break;
default,printf(?Error\n?);
}
return 0;
}
如果逻辑上确实如此,则不同的 case分支可以使用同一个语句组,这也许是特意不在某些 case分支中使用 break
的唯一正当理由
20清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
3.4 循环结构
循环结构的含义
– 根据某一条件的判断结果,反复执行某一处理块的过程
– 最基本的循环结构是当循环
– 进入循环结构,判断循环条件,如果循环条件的结果为真,则执行 A处理块的操作,即循环一次,然后再次判断循环条件,当循环条件为假时,循环结束入口循环结构真假出口
A
条件
21清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
while 循环
while 循环格式,while(表达式 ) 循环体
while 循环流程
– 先判断后执行:表达式为真时,执行一遍循环体(一次迭代),返回重新计算表达式的值以确定是否重复执行循环体;若表达式为假,则终止循环
– 为保证循环终止,循环体内应有能改变表达式值的语句 入口
wh ile 循环真假出口循环体表达式
22清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
while 循环示例
使用 while 循环求两个正整数的最小公倍数
#include <stdio.h>
int main()
{
int m,n,result;
printf(?Input two positive integers m,n:?);
scanf(?%d,%d?,&m,&n);
if(m > 0 && n > 0)
{
result = m < n? n,m;
while(result % m != 0 || result % n != 0) result++;
printf(?The least common multiple of m and n is %d.\n?,result);
}
else printf(?the number m or n is not a positive integer.\n?);
return 0;
}
23清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
do-while 循环
do-while 循环格式,do{ 循环体 }while(表达式 );
do-while 循环流程
– 先执行后判断:先执行一遍循环体(一次迭代),计算表达式的值,表达式为真时重复执行循环体,否则终止循环(循环体至少执行一次,这与 while循环不同)
– 为保证循环终止,循环体内应有能改变表达式值的语句入口
d o -wh ile 循环真假出口循环体 表达式
24清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
do-while 循环示例
反复求两个正整数的最小公倍数,直到输入的两个数均为 1时结束
#include <stdio.h>
int main(){
int m,n,result;
do{
printf(?Input two positive integers m,n:?); scanf(?%d,%d?,&m,&n);
if(m > 0 && n > 0){
result = m < n? n,m;
while(result%m!= 0 || result%n != 0) result++;
printf(?The least common multiple of m and n is %d.\n?,result);
}
else printf(?the number m or n is not a positive integer.\n?);
}while(m != 1 || n != 1);
return 0;
}
25清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
for 循环
for 循环格式
– for(表达式 1; 表达式 2; 表达式 3) 循环体
for 循环流程
– 先判断后执行:先执行表达式 1(循环初始化),再计算表达式 2以根据其结果决定是否执行一遍循环体(为真时执行),计算表达式 3的值(循环再次“初始化”),返回重新计算表达式 2的值以确定循环是否终止入口
for 循环真假出口循环体表达式 2
表达式 3
表达式 1
26清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
100
2
1k
k
for 循环示例一
计算
#include <stdio.h>
int main()
{
int result,k;
result = 0; // 累加器变量,设置初始值(本例设为 0)
for( k = 1; k <= 100; k++ ) // 循环计算
result += k * k; // 累加
printf(?The result,%d\n?,result);
return 0;
}
27清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础三种循环结构的比较
三种循环结构可以互换使用
for 循环与 while 循环常见,do-while 循环少见
while 循环常用于不需要或很少需要初始化的场合
for 循环常用于需要简单初始化和通过递增递减运算控制循环体执行的场合
for 循环将所有循环控制因素都放在循环头部,循环结构最清晰
通过省略循环头部的一个或多个表达式,for 循环也可能非常复杂
28清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
for 循环示例二
程序读入一个字符串,然后反向打印输出
#include <stdio.h>
#include <string.h>
int main( )
{
char s[50],c;
int i,j;
printf(?Input a string,?); scanf(?%s?,s);
for( i = 0,j = strlen(s) – 1; i < j; i++,j– –){
c = s[i]; s[i] = s[j]; s[j] = c;
}
printf(?%s\n?,s);
return 0;
}
29清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
for 循环示例三
打印九九乘法表
#include <stdio.h>
int main(){
int i,j,k;
for( i = 1; i <= 9; i++ ){
for( j = i; j <= 9; j++ ){
k = i * j;
printf(?%d× %d = %d\t?,i,j,k);
}
printf(?\n?) ;
}
return 0;
}
如果一个循环体内包含另一个循环则称循环嵌套或多重循环三种循环都可以嵌套,但嵌套时内外层循环不能发生交叉发生嵌套时,内层循环经常需要使用外层循环的某些值作为控制条件
30清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础循环控制转移,break 语句
输出 5行、每行 10个随机数,若随机数大于 20,000,
本行输出结束
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main(){
int i,j,r;
srand( time(NULL) );
for( i = 1; i <= 5; i++ ){
for( j = 1; j <= 10; j++ ){
r = rand(); printf(?%6d\t?,r); if(r > 20000) break; }
printf(?\n?); }
return 0;
}
srand(),设置随机数种子的函数
time(),获取时间的函数
rand(),产生随机数的函数
break终止当前循环的执行,在存在循环嵌套的场合,它并不能终止外层循环的执行
31清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础循环控制转移,continue 语句
输入一串字符,以回车结束输入,程序统计并输出其中小写字母的个数
#include <stdio.h>
int main(){
char c;
int num = 0;
printf(?Enter a string,\n?);
while( (c = getchar()) != ‘\n‘ ){
if(c < 97 || c > 122) continue; // 非小写字母,本次循环结束
num++;
}
printf(?%d\n?,num);
return 0;
}
continue终止的是当前循环的当前一次迭代,而不是整个循环,当前循环的下一次迭代仍会执行
32清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础结构化程序设计注意事项
要保证结构的完整性
– 不允许结构层次间的交叉!
要保证操作的完整性
– 一个基本结构就是一个完整的操作单元,程序只能从入口进出口出
– 程序最好不要有多入口多出口,尤其不能从外部进入循环或条件分支内部正确的结构嵌套 错误的结构交叉
33清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
3.5 结构化程序设计应用示例一
打印小于 n的所有个位不等于 9的素数,n的具体值由用户输入,要求分行输出,每行输出 10个数
#include <stdio.h>
int main(){
int i,j,n,line = 0;
printf(?Please input n:?); scanf(?%d?,&n);
if(n <= 1){ printf(?No number to output!\n?); return 1; }
for(i = 2; i <= n; i++){ // 逐一取出待查数据
for( j = 2; j < i; j++) if(i % j == 0) break; // 该数非素数,终止内层循环
if(i == j && i % 10 != 9){ // 若该数为素数且个位不等于 9,打印输出
printf(?%d,?,i); line++; if(line == 10){ printf(?\n?); line = 0; }
}
}
printf(?\n?);
return 0;
}
使用 for循环
34清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
3.5 结构化程序设计应用示例一
#include <stdio.h>
int main()
{
int i,j,n,line = 0;
printf(?Please input n:?); scanf(?%d?,&n);
if(n <= 1){ printf(?No number to output!\n?); return 1; }
i = 2;
while(i <= n){ // 逐一取出待查数据
j = 2;
while(j < i && i % j != 0) j++; // 求该数的约数
if(i == j && i % 10 != 9){ // 若该数为素数且个位不等于 9,打印输出
printf(?%d,?,i); line++; if(line == 10){ printf(?\n?); line = 0; }
}
i++;
}
printf(?\n?);
return 0;
}
使用 while循环
35清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
3.5 结构化程序设计应用示例二
百元买百鸡(穷举):已知公鸡每只 5元,母鸡每只 3元,小鸡 1元 3只,可买公鸡、母鸡、小鸡几只
#include <stdio.h>
int main()
{
int x,y,z;
for(x = 0; x <= 100; x++)
for(y = 0; y <= 100; y++)
for(z = 0; z <= 100; z++)
if( x + y + z ==100 && 15 * x + 9 * y + z == 300)
printf(?x = %d,y = %d,z = %d\n?,x,y,z);
}
设 x,y,z分别表示可买的公鸡、母鸡、小鸡的个数,有不定方程组:
100x y z
15 3 10 0
3x y z1 5 9 3 0 0x y z
36清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
3.5 结构化程序设计应用示例二
百元买百鸡(穷举):已知公鸡每只 5元,母鸡每只 3元,小鸡 1元 3只,可买公鸡、母鸡、小鸡几只
#include <stdio.h>
int main()
{
int x,y,z;
for(x = 0; x <= 20; x++)
for(y = 0; y <= 33; y++)
for(z = 0; z <= 100; z++)
if( x + y + z ==100 && 15 * x + 9 * y + z == 300)
printf(?x = %d,y = %d,z = %d\n?,x,y,z);
}
设 x,y,z分别表示可买的公鸡、母鸡、小鸡的个数,有不定方程组:
100x y z
1 5 9 3 0 0x y z
2 0 ; 3 3 ; 1 0 0x y z
<= 100; x++)
<= 100; y++)
37清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
3.5 结构化程序设计应用示例三
输出裴波那契数列前 30项值(递推)
#include <stdio.h>
int main()
{
int n1,n2,n,count;
n1 = 0; n2 = 1;
printf(?%10d%10d?,n1,n2);
for(count = 3; count <= 30; count++)
{
n = n1 + n2;
printf(?%10d?,n);
if(count % 5 == 0) printf(?\n?); // 控制每行输出 5个数
n1 = n2; n2 = n;
}
printf(?\n?);
}


00
11
1 2 1
n
F n n
F n F n n



38清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
3.5 结构化程序设计应用示例四
设计一个简单的菜单程序
– 运行时,首先显示一个菜单画面用以提示输入操作选择
– 操作员从菜单上选择一个操作(即输入相应的代码,例如 1,2等),程序接收选择后调用相应的函数完成操作
– 假设系统提供 select(),insert(),update()和 del()
函数,分别用以实现选择、插入、更新与删除等相应操作
39清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
3.5 结构化程序设计应用示例四
#include <stdio.h>
void insert();
void select();
void del();
void update();
int main()
{
/* generate menu */
char op;
printf(?\n********************************?);/*生成菜单 */
printf(?\n* Menu Options *?);
printf(?\n* 1,Insert *?);
printf(?\n* 2,Select *?);
printf(?\n* 3,Delete *?);
printf(?\n* 4,Update *?);
printf(?\n* 5,Exit *?);
printf(?\n********************************?);
40清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
3.5 结构化程序设计应用示例四
/* selection operation */
while(1)
{
printf(?\nPlease enter selection,?); scanf(?%d?,&op);
switch(op)
{ /* 根据输入,选择分支走向 */
case ‘1‘,insert(); break;
case ‘2‘,select(); break;
case ‘3‘,del(); break ;
case ‘4‘,update(); break;
case ‘5‘,break;
default,printf(?\nSelection error!?); break;
}
if(op == ‘5’) break; /* 退出循环 */
}
} // 结束主函数
41清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础作 业
第 71-72页:第二题(填空题)
– 第 8,9,11小题
第 72-73页:第三题(编程题)
– 第 2,4小题