程序的三种基本结构 if条件分支语句 switch多路开关语句 循环语句 循环嵌套 break,continue和goto语句 第三章 控制语句 程序的三种基本结构 if条件分支语句 switch多路开关语句 循环语句 循环嵌套 break,continue和goto语句
3.1程序的三种基本结构 C语句的类型 五类 三种基本结构 顺序、选择、循环
C程序结构
3.1.1 C语句的类型 1. 控制语句 ① if( )...else... (条件语句) ② switch (多分支选择语句) ③ for( )... (循环语句) ④ while( )... (循环语句) ⑤ do...while( ) (循环语句) ⑥ continue (结束本次循环语句) ⑦ break (中止执行switch或循环语句) ⑧ goto (转向语句) ⑨ return (从函数返回语句)
3.1.1 C语句的类型 2. 函数调用语句 例: getchar(); 3. 表达式语句 例: a = 3; i ++ ; x + y ; 函数调用语句由一个函数调用加一个分号构成。 例: getchar(); 3. 表达式语句 表达式语句由一个表达式加一个分号构成。 例: a = 3; i ++ ; x + y ;
3.1.1 C语句的类型 4. 空语句 5. 复合语句 空语句是只有一个分号的语句,不执行任何操作。形式为: ; 空语句是只有一个分号的语句,不执行任何操作。形式为: ; 5. 复合语句 把一些语句用{ }括起来称为复合语句(又称分程序),通常由多条语句构成,但在逻辑上可以看作一条语句。例: if(a > b) { t = a; a = b; b = t; }
3.1.2 三种基本结构 顺序结构 例3.1,从键盘输入一个学生的学号、姓名和成绩,并输出。
3.1.2 三种基本结构 2. 选择结构
3.1.2 三种基本结构 3. 循环结构
3.2 if条件分支语句 if语句的三种流程 if语句嵌套 条件运算符
3.2.1 if语句的三种流程 1. 单分支if语句 if(表达式) 语句 例: if (100 == score) { cout << "最高分" << endl; } if (-1 == score) { cout << "缺考" << endl; }
3.2.1 if语句的三种流程 2. 双分支if语句 if(表达式) 语句1 else 语句2 例: if ( score >= 60) { cout << “合格" << endl; } { cout << “不合格" << endl; }
3.2.1 if语句的三种流程 3. 多分支if语句 if(表达式1) 语句1 else if(表达式2) 语句2 语句3 ... else if(表达式m) 语句m else 语句m+1
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'); }
3.2.1 if语句的三种流程 4. 关于if语句的说明 3种形式的if语句都只是一条语句 常犯的逻辑错误: if( n = 10 ) { cout << "***" << endl; } 改为: if(10 == n )
3.2.2 if语句嵌套 if(表达式1) if(表达式2) 语句1 else 语句2 if(表达式3) 语句3 语句4 内嵌if if与else配对原则: else总是与它前面最近的未曾配对的if配对。 内嵌if
3.2.2 if语句嵌套举例 编程实现以下符号函数的功能: 算法分析:
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;
也能实现吗? 为什么? 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;
条件表达式:由条件运算符和操作数构成的表达式 格式:表达式1 ? 表达式2 : 表达式3 功能: 3.2.3 条件运算符 条件运算符: ? : 条件表达式:由条件运算符和操作数构成的表达式 格式:表达式1 ? 表达式2 : 表达式3 功能: 若表达式1成立,则求解表达式2,并将表达式2 的值作为整个表达式的值; 否则,求解表达式3,并将表达式3 的值作为整个表达式的值。
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);
3.3 switch多路开关语句 为什么使用? 怎样正确使用?
3.3 switch多路开关语句 流程图:
3.3 switch多路开关语句 基本格式: switch(表达式) { case 常量表达式1: 语句1; break; …… case 常量表达式n: 语句n; break; default: 语句n+1; }
3.3 switch多路开关语句举例 例3.3,在“学生选课系统”中,根据用户输入的编号,输出需要调用的操作模块名称。 根据学生的百分制分数值打出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'); }
3.3 switch多路开关语句 说明: switch(表达式) { case 常量表达式1: switch后面表达式可以是 case 常量表达式2: 语句1; break; …… case 常量表达式n: 语句n; break; default: 语句n+1; } 说明: switch后面表达式可以是 C中任意类型的合法表达式, 通常是整型或字符型,求解 其实际值,而非逻辑值; 每一个case后的常量表 达式必须互不相同,否则 在编译时系统会报错; break不是必不可少的; case和default的出现顺序不影响执行结果; 最后一个情况(无论是case还是default)之后可以不使用break,流程自动结束switch语句。
3.4 循环语句 while语句 do-while语句 for语句
3.4.1 while语句 基本格式: 说明: while(表达式) { 语句(组); } while后面的表达式可以是C中任意类型合法的表达式,先求其实际值,进一步求得其逻辑值; 若表达式的值一开始就为0,则循环体将一次也不执行; 当循环体由多个语句组成时,必须用{ }把它们括起来,使它们形成复合语句; 为了使循环最终能够结束,而不至于产生“死循环”,每执行一次循环体,表达式的值都应该有所变化。
3.4.1 while语句举例 利用以下公式计算π的值,要求精度控制在10-6内。 算法分析: 每次得到新的一项,并累加。 关键:如何得到新项?
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
3.4.1 while语句举例(编程实现) ...... double pi = 0.0; int num = 1; int den = 1; double item = 1.0; while(fabs(item) > 1e-6) { pi = pi + item; num = -num; den = den + 2; item = (double)num / den; } pi = pi * 4; cout << "pi = " << pi << endl;
3.4.2 do-while语句 基本格式: 说明: do { 语句(组); } while(表达式) ;
3.4.2 do-while语句举例 算法分析: 将用户输入的一个正整数倒序输出。例如,输入1234,则输出4321。 如何求得正整数的某一位? 如何倒序输出?
3.4.2 do-while语句举例(编程实现) ...... int n; cout << "请输入一个正整数:"; cin >> n; cout << "倒序结果:"; do { cout << n % 10; n = n / 10; }while(n > 0); cout<<endl;
3.4.3 for循环语句 基本格式: 说明: for(表达式1; 表达式2; 表达式3) { 循环体语句; } 三个表达式之间必须用分号间隔; 任何一个表达式都可以省略,但其中的分号一定要保留; 若循环体部分由多个语句组成,则必须用花括号{}括起来, 使它们形成复合语句; 表达式1和表达式3既可以是一个简单表达式,也可以是由 逗号连接的多个表达式。 for(表达式1; 表达式2; 表达式3) { 循环体语句; }
3.4.3 for循环语句举例 由键盘输入全体考生的C语言成绩,并求平均分。 算法分析: 利用循环依次输入每一位考生的成绩,并将其累加起来。若考生人数确定(即循环次数确定),选用for循环更为方便。
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;
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++) ;
3.5 循环嵌套 一个循环体内又包含另一个完整的循环结构,称为循环的嵌套。
3.5 循环嵌套 while() { … { … } } while() { … do { … } while(); } while() { for( ; ; ) { … } }
3.5 循环嵌套 do { … { … } while(); } while(); do { … while() { … } for ( ; ; ) { … } } while();
3.5 循环嵌套 for( ; ; ) { … do { … } while(); } for( ; ; ) { … while()
3.5 循环嵌套举例 请输出九九乘法表。 算法分析: 可使用循环依次输出九九表的各行,表每行的输出又需要一个循环——双重循环 外层循环变量i代表被乘数 内层循环变量j代表乘数 外层循环依次处理各行,内层循环中依次输出当前行的每一个乘法口诀 for(i = 1; i <= 9; i++) 依次处理行 for(j = 1; j <= 9; j++) 输出乘法表的当前项i * j 输出换行符
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; // 结束本行
3.6 break,continue 和goto语句
用法:只能用在switch语句和循环语句中。 作用: 3.6.1 break语句 用法:只能用在switch语句和循环语句中。 作用: 用在switch语句中控制分支的出口。 用在循环体中,使流程从循 环体内跳出,从而提前结束 循环。
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; } printf(“1*2*…*%d=%d\n”, n–1, prod); return; 用常量1作判断表达式,好像形成了一个无限循环…… 当循环终止条件满足时,用break语句结束循环。
将一个正整数分解质因数。例如:输入90,打印出90=2×3×3×5。 算法分析: 3.6.1 break语句举例2 将一个正整数分解质因数。例如:输入90,打印出90=2×3×3×5。 算法分析: 要将一个数n分解为质因数,可从质数2开始,判断其是否为n的因子。 如果是,则输出,再将n除以该因子,继续判断; 如果不是,则将因数的值增1继续判断。 本例可使用双重循环: 外层循环对n的可能因子i进行循环,n的因子最小可能是2,最大不能超过n本身; 在内层循环,如果i是n的因子,则输出i,然后将n除以i,继续判断i是否是n的因子,这样就可以将n进行完全分解了。
3.6.1 break语句举例2 将一个正整数分解质因数。例如:输入90,打印出90=2×3×3×5。
3.6.1 break语句举例2(编程实现) ...... int n; // 待分解的数 int i; // 外层循环的循环变量,表示n的因子 cout <<"请输入一个正整数:"; cin >> n; cout << n << " = " ;
3.6.1 break语句举例2 (编程实现) ...... for(i = 2; i <= n; i++) // 对n的所有可能正因子i进行循环 { while(n != i) // n不等于其正因子i时循环 if(n % i == 0) // 如果i是n的正因子 cout << i << "×" ; // 输出正因子i n = n / i; // n除以当前正因子 } else { break; } // i不是n的因子,跳出当前的while循环 cout << n <<endl; // 输出最后一个因子
3.6.2 continue语句 用法:只能用在循环语句中。 作用:结束本次循环,立即开始执行下一次循环。
3.6.2 continue语句举例 编程计算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;
3.6.3 goto语句 基本结构: goto 标识符; 作用: 优点: 缺点: 与条件判断相结合可以构成循环结构或跳出循环,但 非实现循环结构的专用语句。 优点: 灵活,尤其在多层循环嵌套的内层中跳出的情况下, goto语句可方便实现; 缺点: 可能会使程序流程无规律,可读性差。
3.6.3 goto语句举例 用逐个判别法求出2~50以内的所有质数。 算法分析: 可使用双重循环: 外循环对2~50的所有数i进行枚举; 内循环对i的所有可能正因子j进行枚举, 如果某个j能整除i,则转向对非质数处理的相应语句; 如果所有的j均不能整除i,则i是质数,输出即可。
3.6.3 goto语句举例 (编程实现) #include <iostream> // 包含输入输出接口文件 using namespace std; // 引用标准命名空间 int main() // 定义主函数 { int i = 0; // 循环变量,枚举所有的数 int j = 0; // 循环变量,枚举所有的正因子 int n = 0; // 质数的个数,初始为0 ......
3.6.3 goto语句举例 (编程实现) for(i = 2; i <= 50; i++) // 循环处理所有的数 { for(j = 2; j*j <= i; j++) // 循环处理i的所有可能正因子 if(i % j == 0) // 如果j是i的因子 { goto notPrime; } // 转向非质数处理语句 } cout << i << " "; // 输出当前质数i n++; // 质数个数增 if(n % 5 == 0) // 如果n是5的倍数,本行已输出5个数 { cout << endl; } // 输出换行符 notPrime: // 非质数处理语句 ; // 什么事也不做,但空语句不能省略 return 0;
3.7 程序举例
例3.11 某次面试有若干位专家为面试者打出百分制分值,计算面试者最后得分的方法是:去掉一个最高分,去掉一个最低分,取剩余成绩的平均分。编写程序,输入一位面试者的若干成绩,以-1作为输入结束标记,计算其最终得分。 算法分析: 在循环中完成输入评分、累加成绩、求最高及最低分等操作。循环完成后,将总成绩减去最高分和最低分,除以计分专家的人数即可得到平均分。 因为专家数不定,故循环需以“当前成绩是-1”为结束条件。 如何求一系列数字中的最大值和最小值?可以设一个变量maxScore存储最大值,其初值很小,如0;在循环中,如果当前评分大于maxScore,则将maxScore更新为当前评分;这样循环结束后,maxScore的值就是所有评分中的最大值。同理可得最小值。
例3.11(NS流图)
例3.11(编程实现) #include <iostream> // 包含输入输出接口文件 using namespace std; // 引用标准命名空间 int main() // 定义主函数 { float score = 0.0f; // 专家打分 float minScore = 100.0f; // 最低分 float maxScore = 0.0f; // 最高分 float sum = 0.0f; // 总分 int i = 0; // 专家数 cout << "输入专家评分,以-1结束:" << endl; cin >> score; // 输入第一个分数 minScore = minScore = score; // 设读入第一个分数为最高分和最低分 while(score != -1) i ++; // 专家数增 ......
例3.11(编程实现) ...... sum = sum + score; // 分数累加 if(score > maxScore) // 如果当前分数大于最高分 { maxScore = score; // 则将最高分更新 } if(score < minScore) //如果当前分数小于最低分 minScore = score; //则将最低分更新 cin >> score; // 输入下一个分数 sum = sum - maxScore - minScore; // 去掉一个最高分和最低分 cout << "最后得分:" << sum / (i - 2) << endl; return 0;
例3.13 算法分析: 写一个程序,打印输入中的单词,每行打印一个单词。(假定空格和制表位都是单词间的分隔符) 在一串字符中,一个新单词开始的特征是当前字符不是空白字符,而它的前一个字符是空白字符;在一个单词当中再次遇到空白字符时,意味着一个单词的结束。用变量inword来记录当前字符是否在一个单词中。
例3.13(编程实现) #include <iostream> using namespace std; const int YES = 1; // 字符状态,当前字符在单词中 const int NO = 0; // 字符状态,当前字符不在单词中 int main() // 定义主函数 { char c; // 当前字符c int inword = 0; // 标记当前字符是否在单词中 while((c = getchar()) != '\n') // 循环读入字符,至遇到回车符为止 if(c == ' ' || c == '\t') // 如果当前字符为单词分隔符 if(YES == inword) // 判断当前字符是否在单词中 { cout << endl; inword = NO; } } ......
例3.13(编程实现) ...... else if(NO == inword) // 处理新单词的第一个字符 { inword = YES; cout << c; } else // 处理单词中的字符 cout<< endl; return 0; } // 主函数结束
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语句,可以为编程带来方便。