程序的三种基本结构 if条件分支语句 switch多路开关语句 循环语句 循环嵌套 break,continue和goto语句 第三章 控制语句 程序的三种基本结构 if条件分支语句 switch多路开关语句 循环语句 循环嵌套 break,continue和goto语句
3.1程序的三种基本结构 C语句的类型 五类 三种基本结构 顺序、选择、循环 2
3.1.1 C语句的类型 1. 控制语句 ① if( )...else... (条件语句) ② switch (多分支选择语句) ③ for( )... (循环语句) ④ while( )... (循环语句) ⑤ do...while( ) (循环语句) ⑥ continue (结束本次循环语句) ⑦ break (中止执行switch或循环语句) ⑧ goto (转向语句) ⑨ return (从函数返回语句) 3
3.1.1 C语句的类型 2. 函数调用语句 函数调用语句由一个函数调用加一个分号构成。 例: getchar(); 3. 表达式语句 表达式语句由一个表达式加一个分号构成。 例: a = 3; i ++ ; x + y ; 4
3.1.1 C语句的类型 4. 空语句 5. 复合语句 空语句是只有一个分号的语句,不执行任何操作形式为: ; 空语句是只有一个分号的语句,不执行任何操作形式为: ; 5. 复合语句 把一些语句用{ }括起来称为复合语句(又称分程序),通常由多条语句构成,但在逻辑上可以看作一条语句。例: if(a > b) { t = a; a = b; b = t; } 5
3.1.2 三种基本结构 顺序结构 例3.1:从键盘输入一个学生的学号、姓名和成绩,并输出。 流程图 NS图 6
3.1.2 三种基本结构 2. 选择结构 指通过对特定条件的判断,来选择一个分支执行 NS图 流程图 7
3.1.2 三种基本结构 3. 循环结构 while型循环结构 (当型) do-while型循环结构(直到型) 在给定的条件下,重复执行某段程序,直到条件不满足为止 while型循环结构 (当型) 先判断条件,当条件为“真”时,重复执行某段程序,直到条件为“假”为止 do-while型循环结构(直到型) 先执行某段程序,然后再判断条件,当条件为“真”时,再重复执行这段程序,直到条件为“假”为止 流程图 NS图 8
3.2 if条件分支语句 if语句的三种流程 if语句嵌套 条件运算符 9
3.2.1 if语句的三种流程 1. 单分支if语句 if(表达式) 语句 例: if (100 == score) { cout << "最高分" << endl; } if (-1 == score) cout << "缺考" << endl; 10
3.2.1 if语句的三种流程 2. 双分支if语句 if(表达式) 例: 语句1 else 语句2 if ( score >= 60) { cout << “合格" << endl; } cout << “不合格" << endl; 11
3.2.1 if语句的三种流程 3. 多分支if语句 if(表达式1) 语句1 else if(表达式2) 语句2 语句3 ... ... else if(表达式m) 语句m else 语句m+1 12
3.2.1 if语句的三种流程 3. 多分支if语句 例: if (score > 89) { putchar('A'); } else if (score > 79) { putchar('B'); } else if (score > 69) { putchar('C'); } else if (score > 59) { putchar('D'); } else { putchar('E'); } 13
3.2.1 if语句的三种流程 4. 关于if语句的说明 3种形式的if语句都只是一条语句 常犯的逻辑错误: if(n = 10) { cout << "***" << endl; } 改为: if(10 == n) 14
3.2.2 if语句嵌套 if(表达式1) if(表达式2) 语句1 else 语句2 if(表达式3) 语句3 语句4 内嵌if 内嵌if 15
3.2.2 if语句嵌套举例 编程实现以下符号函数的功能: 算法分析: 16
3.2.2 if语句嵌套举例(编程实现) ...... int x, y; cout << "x = "; cin >> x; if(x > 0) // 如果x大于0 { y = 1; } else if (x < 0) // 如果x小于0 { y = -1; } else // 如果x等于0 { y = 0; } cout << "y = " << y << endl; 17
也能实现吗? 为什么? 3.2.2 if语句嵌套举例(编程实现) ...... int x, y; cout << "x = "; cin >> x; if(x > 0) // 如果x大于0 { y = 1; } else if (x < 0) // 如果x小于0 { y = -1; } else // 如果x等于0 { y = 0; } cout << "y = " << y << endl; 也能实现吗? 为什么? y = 0; if(x >= 0) if(x > 0) y = 1; else y = -1; 18
条件表达式:由条件运算符和操作数构成的表达式 格式:表达式1 ? 表达式2 : 表达式3 功能: 3.2.3 条件运算符 条件运算符: ? : 条件表达式:由条件运算符和操作数构成的表达式 格式:表达式1 ? 表达式2 : 表达式3 功能: 若表达式1成立,则求解表达式2,并将表达式2 的值作为整个表达式的值; 否则,求解表达式3,并将表达式3 的值作为整个表达式的值。 19
3.2.3 条件运算符 例:将x、y、z三个变量中最大的值赋值给变量max。 用if语句实现: 用条件运算符实现: if(x > y) if(x > z) max = x; else max = z; if(y > z) max = y; 用条件运算符实现: max = x > y ? (x > z ? x : z) : (y > z ? y : z); 20
3.3 switch多路开关语句 为什么使用? 怎样正确使用? 21
3.3 switch多路开关语句 基本格式: switch(表达式) { case 常量表达式1: 语句1; break; …… case 常量表达式n: 语句n; break; default: 语句n+1; } 22
3.3 switch多路开关语句 说明: switch后面表达式可以是C中整型、字符型或枚举型的合法表达式,求解其实际值,而非逻辑值; 每一个case后的常量表达式必须互不相同,否则在编译时系统会报错; break不是必不可少的; case和default的出现顺序不影响执行结果; 最后一个情况(无论是case还是default)之后可以不使用break,流程自动结束switch语句。 switch (score) { case >89 : grade='E'; break; case >79 : grade='G'; break; case <60 : grade='B'; break; default : cout<<"God knows\n"; } 23
3.3 switch多路开关语句 流程图: 24
switch语句完整形式的执行流程图 表达式的具体值 语句1 语句2 …… 语句n 语句n+1 T Y N F =常量表达式1的值? =常量表达式2的值? =常量表达式n的值? T 有break Y N
多路开关语句举例 根据学生的百分制分数值打出A~E等级。 switch(score / 10) { case 10: case 9: putchar('A'); break; case 8: putchar('B'); break; case 7: putchar('C'); break; case 6: putchar('D'); break; default: putchar('E'); } 26
多路开关语句举例 例3.3:在“学生选课系统”中,根据用户输入的编号,输出需要调用的操作模块名称。 显示菜单 输入用户编号 根据用户编号进行输出 27
3.4 循环语句 while语句 do-while语句 for语句 28
3.4.1 while语句 基本格式: while(表达式) { 语句(组); } 说明: NS图 基本格式: while(表达式) { 语句(组); } 说明: while后面的表达式可以是C中任意类型合法的表达式,先求其实际值,进一步求得其逻辑值; 若表达式的值一开始就为0,则循环体将一次也不执行; 当循环体由多个语句组成时,必须用{ }把它们括起来,使它们形成复合语句; 为了使循环最终能够结束,而不至于产生“死循环”,每执行一次循环体,表达式的值都应该有所变化。 29
3.4.1 while语句举例 利用以下公式计算π的值,要求精度控制在10-6内。 算法分析: 每次得到新的一项,并累加。 关键:如何得到新项? 30
3.4.1 while语句举例 NS图: 当前项分子num初始化为1 当前项分母den初始化为1 当前项item初始化为1 pi初始化为0 累加当前项pi = pi + item 计算当前项的分子num = -num 计算当前项的分母den = den + 2 计算新的当前项item = num / den pi = pi * 4 输出pi 31
3.4.1 while语句举例(编程实现) 当前项分子num初始化为1 当前项分母den初始化为1 当前项item初始化为1 pi初始化为0 while(当前项绝对值大于0.000001) 累加当前项pi = pi + item 计算当前项的分子num = -num 计算当前项的分母den = den + 2 计算新的当前项item = num / den pi = pi * 4求pi的值 输出pi ...... int num = 1; // 分子 int den = 1; // 分母 double item = 1.0; // 当前项 double pi = 0.0; // 存储pi while(fabs(item) > 1e-6) { // 当前项绝对值大于误差限时循环 pi = pi + item; // 累加当前项 num = -num; // 求分子 den = den + 2; // 求分母 item = (double)num / den; } pi = pi * 4; cout << "pi = " << pi << endl; 32
3.4.2 do-while语句 基本格式: do { 语句(组); }while(表达式) ; 说明: NS图 基本格式: do { 语句(组); }while(表达式) ; 说明: 在while后必须有一个“;”,表示语句结束; 由于do-while语句是先执行循环体语句再判断表达式的值, 所以无论一开始判断表达式的值为“真”还是“假”,循环体 中的语句都至少被执行一次; 如果do-while语句的循环体部分是由多个语句组成的,则必 须用花括号{ }括起来,使它们形成复合语句。 33
3.4.2 do-while语句举例 算法分析: 将用户输入的一个正整数倒序输出。例如,输入1234,则输出4321。 如何求得正整数的某一位? 如何倒序输出? 34
3.4.2 do-while语句举例(编程实现) ...... int n; cout << "请输入一个正整数:"; cin >> n; cout << "倒序结果:"; do { cout << n % 10; n = n / 10; }while(n > 0); cout<<endl; 35
3.4.3 for循环语句 基本格式: for(表达式1; 表达式2; 表达式3) { 循环体语句; } 说明: 三个表达式之间必须用分号间隔; 任何一个表达式都可以省略,但其中的分号一定要保留; 若循环体部分由多个语句组成,则必须用花括号{}括起来, 使它们形成复合语句; 表达式1和表达式3既可以是一个简单表达式,也可以是由逗 号连接的多个表达式。 36
3.4.3 for循环语句举例 由键盘输入全体考生的C语言成绩,并求平均分。 算法分析: 利用循环依次输入每一位考生的成绩,并将其累加起来。若考生人数确定(即循环次数确定),选用for循环更为方便。 37
3.4.3 for循环语句举例(编程实现) ...... int i = 0; // 循环变量 int num = 0; // 考生人数 double score = 0; // 考生成绩 double sum = 0; // 总成绩 double avg = 0; // 平均成绩 cout << "请输入考生人数:"; cin >> num; cout << "请逐一输入各位考生的成绩:" << endl; for(i = 1; i <= num; i++) { cin >> score; // 输入当前考生成绩 sum = sum + score; // 累加 } avg = sum / num; // 求平均值 cout << "平均分是" << avg << endl; 38
3.4.4 while,do-while和for语句的比较 ① 一般情况下,三种循环语句是可以互换的; ② 一般来说,for语句用于循环次数明确的情况,而while和 do-while语句用于循环次数不确定但循环条件明确的情况; ③ 用for循环时,循环变量的初始化可以由表达式1来实现, 而用while和do-while循环时,循环变量的初始化需要在语句 之前完成。 ④ for循环更加灵活。 for(i=1, j=1; i < 10; i++) { j ++; } for (i=1, j=1; i < 10; i++, j++) ; 39
3.5 循环嵌套 一个循环体内又包含另一个完整的循环结构,称为循环的嵌套。 40
3.5 循环嵌套 while() { … { … } } while() { … do { … } while(); } while() { for( ; ; ) { … } } 41
3.5 循环嵌套 do { … { … } while(); } while(); do { … while() { … } for ( ; ; ) { … } } while(); 42
3.5 循环嵌套 for( ; ; ) { … do { … } while(); } for( ; ; ) { … while() 43
3.5 循环嵌套举例 例:请输出九九乘法表。 算法分析: 可使用循环依次输出九九表的各行,表每行的输出又需要一个循环——双重循环 外层循环变量i代表被乘数 内层循环变量j代表乘数 外层循环依次处理各行,内层循环中依次输出当前行的每一个乘法口诀 for(i = 1; i <= 9; i++) 依次处理行 for(j = 1; j <= 9; j++) 输出乘法表的当前项i * j 输出换行符 44
3.5 循环嵌套举例(编程实现) 请输出九九乘法表。 ...... int i = 0; // 循环变量,控制行 int j = 0; // 循环变量,控制列 for(i = 1; i <= 9; i++) // 依次处理各行 { for(j = 1; j <= 9; j++) // 依次处理各列 cout << i << "*" << j << "=" << i * j << " "; } cout << endl; // 结束本行 45
3.6 break,continue 和goto语句 46
3.6.1 break语句 用法:只能用在switch语句和循环语句中。 作用: 用在switch语句中控制分支的出口。 用在循环体中,使流程从循环体内跳出,从而提前结束循环。 47
3.6.1 break语句举例1 例:编程计算1×2×3×…×n ,n=10。 #include <iostream> using namespace std; int main() { int prod=1, n=1; while (1) prod=prod*n; n++; if (n>10) break; } cout<<"1*2*…*“<<n-1<<"=“<<prod<<endl; return; 用常量1作判断表达式,好像形成了一个无限循环…… 当循环终止条件满足时,用break语句结束循环。 48
3.6.2 continue语句 用法:只能用在循环语句中。 作用:结束本次循环,立即开始执行下一次循环。 49
3.6.2 continue语句举例 例3.9 编程计算1~100之间所有偶数的和。 ...... int n = 0; // 循环变量,当前要累加的数 int sum = 0; // 累加和,初始化为0 for(n = 1; n <= 100; n++)// 对1~100中每个数进行循环 { if(n % 2 != 0) // 如果n不是偶数 continue; // 跳过累加 } sum = sum + n; // 累加当前数字 cout << "2+4+…+100 = " << sum <<endl; 50
3.7 程序举例 51
例3.11 某次面试有若干位专家为面试者打出百分制分值,计算面试者最后得分的方法是:去掉一个最高分,去掉一个最低分,取剩余成绩的平均分。编写程序,输入一位面试者的若干成绩,以-1作为输入结束标记,计算其最终得分。 算法分析: 在循环中完成输入评分、累加成绩、求最高及最低分等操作。循环完成后,将总成绩减去最高分和最低分,除以计分专家的人数即可得到平均分。 因为专家数不定,故循环需以“当前成绩是-1”为结束条件。 如何求一系列数字中的最大值和最小值?可以设一个变量maxScore存储最大值,其初值很小,如0;在循环中,如果当前评分大于maxScore,则将maxScore更新为当前评分;这样循环结束后,maxScore的值就是所有评分中的最大值。同理可得最小值。 52
例3.11(编程实现) 定义变量,提示输入成绩 循环输入成绩,并计算成绩之和及成绩个数 计算并输出最终成绩 53
程序举例1 :题目及分析 例:求 Fibonacci 数列的前40个数。该数列满足递推公式 f1= 1 , f2 = 1 ; fn = fn-1 + fn-2 分析: 题目需要计算累加,应该用到循环语句。 用那种循环语句呢?根据题目考虑用for语句比较合适。 怎么循环?我们把前40个数的递推过程写一下: f1=1 f2=1 f3=f2+f1 f4=f3+f2 f5=f4+f3 …… 可见,在已知f1和f2的时候,从第3个数据开始,每个数据都只与前面相邻的两个数据有关。 比如:当根据 f1+f2=f3 求出 f3 后,再求 f4 时,原来 f1 变量中的数据不再有用,所以如果把 f2 的值放到 f1 中,把 f3 的值放到 f2 中,那么计算 f4 的表达式 f3+f2 就变成了 f2+f1 ,结果又可以放到 f3 中,依此类推就形成了循环。
程序举例1 :算法 f3 = f2 + f1 f3 = f2 f1 (f3) (f2) + f4 = f3 + f2 (f4) 算法:每循环一次求出一个新的数据 f3 = f2 + f1 f3 = f2 f1 (f3) (f2) + f4 = f3 + f2 (f4) f5 = f4 + f3 (f5) 第1次循环: 第2次循环: 第3次循环:
程序举例1:实现方案 #include <iostream> using namespace std; int main() { int f1 = 1 , f2 = 1, f3; int n; cout<<f1<<"\t"<<f2; for (n = 3; n <= 40; n++) f3 = f1 + f2 ; cout<<f3<<"\t"; if (n % 5 == 0) cout<<endl; f1 = f2 ; f2 = f3 ; } return 0; 每次循环求出一个新的数据并输出 使每行只输出5个数据 实现循环递推算法的关键
已知三个人说的是真话,一个人说的是假话。现在要根据这些信息,找出做了好事的人。 程序举例2 :谁做的好事? 川大附小有四位同学中的一位做了好事,不留名,表扬信来了之后,校长问这四位是谁做的好事。 A说:不是我。 B说:是C。 C说:是D。 D说:他胡说。 已知三个人说的是真话,一个人说的是假话。现在要根据这些信息,找出做了好事的人。
程序举例2 :谁做的好事? 下面,我们把四个人说的四句话写成关系表达式。在声明变量时,让thisman表示要找的人,定义他是字符变量 A说:不是我。写成关系表达式为(thisman!='A') B说:是C。 写成关系表达式为(thisman=='C') C说:是D。 写成关系表达式为(thisman=='D') D说:他胡说。写成关系表达式为(thisman!='D')
程序举例2 :谁做的好事? 思路: 1.如何找到该人,一定是“先假设该人是做好事者,然后到每句话中去测试看有几句是真话”。“有三句是真话就确定是该人,否则换下一人再试”。 比如,先假定是A同学,让thisman='A'; 代入到四句话中 A说:thisman!='A'; 'A'!='A' 假,值为0。 B说:thisman=='C'; 'A'=='C' 假,值为0。 C说:thisman=='D'; 'A'=='D' 假,值为0。 D说:thisman!='D'; 'A'!='D' 真,值为1。 显然,不是‘A’做的好事(四个关系表达式值的和为1) 然后,我们再分别用B、C、D去试,看他是否是做好事的人。 我们可以理出头绪,要用所谓枚举法,一个人一个人地去试,四句话中有三句为真,该人即所求。
程序举例2:谁做的好事? 2. 从编写程序的角度看,实现枚举最好用循环结构 for(thisman='A'; thisman<='D'; thisman++) { // 循环体,开始 sum = (thisman!='A')+ // 'A'的话是否为真 (thisman=='C')+ // 'B'的话是否为真 (thisman=='D')+ // 'C'的话是否为真 (thisman!='D'); // 'D'的话是否为真 if(sum==3) { cout<<thisman<<endl; } } // 循环体,结束
有了上述了解之后,我们来看解“谁做的好事”的程序框图 NS图 根据上述框图写出的程序 运行结果
3.8 本章小结 1. if 语句用于实现单路、两路和多路分支。 2. switch是多选一的分支语句,它是if 语句的一个补充(else if 结构),当用它编写程序时会增加可读性。 3. 循环是一组语句,计算机反复执行这组语句直到满足终止条件 为止。 4. while,do-while和for 三种循环语句可以相互转化。 5. for适用于循环次数已知的循环。 6. while先判定循环条件,可能一次都不执行循环体。 7. do-while后判定循环条件,至少保证执行一次循环体。 8. 正确使用break和continue语句,可以为编程带来方便。 62