1、第三章 程序的流程控制 语句,本章内容,流程控制概述 顺序控制 选择控制 循环控制 无条件转移控制 程序设计风格,流程控制概述,表达式构成了数据处理的基本单位。 当程序中有多个表达式时,就会面临: 先计算哪一个表达式 根据不同的情况计算不同的表达式 一个或几个表达式需要重复计算多次 语句实现对程序执行流程的控制,包括: 顺序控制:按书写次序执行。 选择控制:根据条件选择执行。 循环控制:重复执行。,C+语句的分类,顺序控制,按书写次序,从左到右、从上到下顺序执行。 实现顺序控制的C+语句有: 表达式语句 复合语句 空语句,表达式语句,在C+表达式的后面加上一个分号“;”就可以构成表达式语句,其
2、格式为: ; 例如: a + b * c; a b ? a: b; a+; x = a | b 连续的多个表达式语句按它们的书写次序依次执行。,较常使用的表达式语句,赋值 自增/自减 无返回值的函数调用,等 输入/输出 例如 x = a+b; /赋值 x+; /自增 f(a); /函数调用 cin a; /输入 cout b; /输出,复合语句,复合语句是由一对花括号括起来的一条或多条语句,又称为块(block)。语法上,复合语句可看作是一个语句。其格式为: 中的语句可以是任何的C+语句,其中包括数据定义和声明语句。 复合语句中的语句序列一般按照书写次序执行。 复合语句一般作为函数体和结构语句
3、的成分语句。,复合语句举例, int a,b;cin a b;int max;if (a = b) /选择语句max = a; else max = b;cout max endl; ,空语句,根据程序设计的需要,在程序中的某些地方有时需要加上一些空操作,以方便其它流程控制的实现。 空语句的格式为:; 空语句不做任何事情,其作用是用于语法上需要一条语句的地方,而该地方又不需做任何事情。空语句常常作为结构语句的子句。,例如: . goto end; /转向下面由语句标号end标识的空语句end: ; /空语句 其中,在“end: ;”中,end是一个语句标号,“;”是一个空语句。再例如: int
4、 i,sum; for (sum=0, i=1; i=100; sum+=i,i+) ; 其中,循环体为一条空语句,选择控制,在程序中,常常需要根据不同的情况来从一组语句中选择一个来执行(分支),这是通过选择语句来完成的。 选择语句包括: if语句 switch语句,if 语句,if语句(又称条件语句)是根据一个条件满足与否来决定是否执行某个语句或从两个语句中选择一个语句执行。if语句有两种格式: if () if () else 其中的、必须是一个语句!(复合语句算一个语句。),if语句的含义,第一种格式,第二种格式,例子:从键盘输入三个整数,计算其中的最大值并将其输出,#include u
5、sing namespace std; int main() int a,b,c,max;cout a b c;if (a b)max = a;elsemax = b;if (c max) max = c;cout “最大者为:“ max endl;return 0; ,if语句的锯齿格式,为了提高程序的易读性,在写if语句时,最好采用“锯齿”格式,即把成分语句往后缩进几列。 当if语句的成分语句也是if语句时,如果嵌套层次很深,“锯齿”格式将会使得程序正文严重偏向右边,从而带来对程序编辑、查看带来困难。为了减少文本的缩进量,可以把这样的if语句按下面的格式书写:,if (.). else i
6、f (.). else if (.). else if (.). else.,if (.). else if (.).else if (.).else if (.).else.,等价于:,例子:从键盘输入一个三角形的三条边,判断其为何种三角形,#include using namespace std; int main() int a,b,c;cin a b c;if (a+b = c | b+c = a | c+a = b)cout “不是三角形“;else if (a = b ,避免不必要的测试,if (score = 90)cout = 80 ,if 语句的歧义问题,下面的if语句的含义
7、是什么?if () if () else if () if () else if () if () else C+规定:else子句与它前面最近的、没有else子句的if配对。因此,上面的if语句解释为: if () if () else 若要按2来解释,则需要加上花括号(复合语句): if () if () else ,switch 语句,程序中有时需要从两个(组)以上的语句中选择一个(组)来执行。 C+提供了一条多路选择语句:switch语句(又称开关语句), 它能根据某个表达式的值在多组语句中选择一组语句来执行。 每一组语句的最后一个语句往往是break语句。,switch语句的格式,s
8、witch () case : case : :case : default: ,例子、从键盘输入一个星期的某一天(0:星期天;1:星期一;.),然后输出其对应的英语单词,#include using namespace std; int main() int day;cin day;switch (day) case 0: cout “Sunday“; break;case 1: cout “Monday“; break;case 2: cout “Tuesday“; break;case 3: cout “Wednesday“; break;case 4: cout “Thursday“;
9、 break;case 5: cout “Friday“; break;case 6: cout “Saturday“; break;default: cout “Input error“;cout endl;return 0; ,switch语句中使用break语句,在执行switch语句的某个分支时,需要用break语句结束该分支的执行。 在switch语句的一个分支的执行中,如果没有break语句(最后一个分支除外),则该分支执行完后,将继续执行紧接着的下一个分支中的语句序列。 在其它一些语言(如:Pascal)的多路选择语句中,一个分支执行完后将自动结束多路选择语句的执行。 C+中的s
10、witch语句比其它一些语言中的多路选择语句更具有灵活性。当若干个分支具有部分重复功能时,C+的switch语句可以节省代码量。,switch (.) .case :Acase :Bcase :Cbreak;. 上面的语句中,分支1执行A、B和C;分支2执行B和C;分支3执行C。(假设A、B中没有break语句),循环控制,如何编程计算n!(n是变量)? n!=n*(n-1)*(n-2)*.*2*1 表达式中不允许有“.” 上面的问题需要用重复操作控制来解决:对相同的操作重复执行多次,每一次操作的数据有所不同。 f=1,对i=2n,重复执行:f=f*i; 循环语句为解决重复操作提供了一种途径。
11、 循环一般由四个部分组成: 循环初始化 循环条件 循环体 下一次循环准备。,C+提供了三种实现重复操作的循环语句: while语句 do-while语句 for语句,while 语句,while语句具有如下的格式:while () ,用while语句求n!,#include using namespace std; int main() int n;cin n;int i=2,f=1; /循环初始化while (i = n) /循环条件 f *= i;i+; /下一次循环准备 /循环体cout “factorial of “ n “ = “ f endl;return 0; ,do-while
12、 语句,do-while语句的格式如下:do while ();,用do-while语句求n!,#include using namespace std; int main() int n;cin n;int i=1,f=1; /循环初始化do /循环体 f *= i;i+; /下一次循环的准备 while (i = n); /循环条件cout “factorial of “ n “ = “ f endl;return 0; ,for 语句,for语句的格式如下:for (;) ,#include using namespace std; int main() int n,i,f;cin n;
13、for (i=2,f=1 /循环初始化; i=n /循环条件;i+) /下一次循环准备f *= i; /循环体cout “factorial of “ n “ = “ f endl;return 0; ,用for语句求n!,循环的种类,计数控制的循环 循环前就知道循环的次数,循环时重复执行循环体直到指定的次数 事件控制的循环 循环前不知道循环的次数,循环的终止是由循环体的某次执行导致循环的结束条件得到满足而引起的,三种循环语句的使用原则,三种循环语句在表达能力上是等价的,在解决某个具体问题时,用其中的一种可能会比其它两种更加自然。 一般来说, 计数控制的循环一般用for语句; 事件控制的循环一
14、般用while或do-while语句,其中,如果循环体至少要执行一次,则用do-while语句。 由于for语句能清晰地表示“循环初始化”、“循环条件”以及“下一次循环准备”,因此,一些非计数控制的循环也用for语句实现。,例 :计算从键盘输入的一系列整数的和,要求首先输入整数的个数。(计数控制的循环),#include using namespace std; int main() int n;cout n;cout a;sum += a; cout “输入的“ n “个整数的和是:“ sum endl;return 0; ,例:计算从键盘输入的一系列整数的和,要求输入以-1结束。(事件控制
15、的循环 ),#include using namespace std; int main() int a,sum=0;cout a;while (a != -1) sum += a; cin a;cout “输入的整数的和是:“ sum endl;return 0; ,例:从键盘接收字符,一直到输入了字符y(Y)或n(N)为止。 (事件控制的循环 ),#include #include using namespace std; int main() char ch;do cout ch;ch = tolower(ch); while (ch != y ,例:求第n个费波那契(Fibonacci
16、)数,/1,1,2,3,5,8,13,. #include using namespace std; int main() int n;cin n;int fib_1=1; /第一个Fibonacci数int fib_2=1; /第二个Fibonacci数for (int i=3; i=n; i+) int temp=fib_1+fib_2; /计算新的Fibonacci数fib_1 = fib_2; /记住新的前一个Fibonacci数fib_2 = temp; /记住新的Fibonacci数cout “第“ n “个费波那契数是:“ fib_2 endl;return 0; ,fib_2
17、= fib_1 + fib_2; /计算和记住新的Fibonacci数 fib_1 = fib_2 - fib_1; /记住前一个Fibonacci数,循环优化问题,算法的优化:减少循环次数 避免在循环中重复计算不变的表达式,#include using namespace std; int main() int n;cout n; /从键盘输入一个正整数for (int i=2; in; i+) /循环:分别判断2、3、.、n-1是否为素数 int j=2;while (j i 注意:1、上面的for循环中,偶数没有必要再判断它们是否为素数;2、上面的while循环没有必要到i-1,只需要到
18、:sqrt(i),例:编程求出小于n的所有素数(质数),#include #include using namespace std; int main() int n;cin n; /从键盘输入一个数if (n sqrt(i) /i是素数cout i “,“;cout endl;return 0; 注意:上面程序中的sqrt(i)被重复计算!, int j = 2,k=sqrt(i); while ( j k) /i是素数。注意:对有些循环优化,编译器能实现!,无条件转移控制,除了有条件的选择语句(if和switch)外,C+还提供了无条件的转移语句: goto break continue
19、return,goto语句,goto语句的格式如下:goto ; 为标识符,其定义格式为: goto的含义是:程序转移到带有的语句,用goto语句求n!,#include using namespace std; int main() int n;cin n;int i=1,f=1; loop: f *= i;i+;if (i = n) goto loop;cout “factorial of “ n “=“ f endl;return 0; ,在使用goto语句时,应该注意: 不能用goto语句从一个函数外部转入该函数的内部(函数体),也不能用goto语句从一个函数的内部转到该函数的外部。
20、允许用goto语句从内层复合语句转到外层复合语句或从外层复合语句转入内层复合语句。 goto语句不能掠过带有初始化的变量定义。,void f() goto L1; /Errorwhile (.) int x=0;L1: .goto L2; /Error.int y=10;L2: ,break语句,break语句的格式:break; break语句的含义有两个: 结束switch语句的某个分支的执行 退出包含它的最内层循环语句(由于循环可以嵌套) 在循环体中只要执行了break语句,就立即跳出(结束)循环,循环体中跟在break语句后面的语句将不再执行,程序继续执行循环之后的语句。 在循环体中,
21、break语句一般作为某个if语句的子句,用于实现进一步的循环控制。,用goto语句实现break语句的功能,while (.) . break; 上述程序等价于: while (.) . goto L; L: .,例如,判断i是否为素数的循环也可写成:j = 2; k = sqrt(i); while (j = k) if (i%j = 0) break; /退出循环j+; 或 for (j=2,k=sqrt(i); j=k; j+)if (i%j = 0) break;,continue语句,continue语句的格式如下:continue; continue语句只能用在循环语句的循环体中
22、,其含义是:立即结束当前循环,准备进入下一次循环。 对于while和do-while语句,continue语句将使控制转到循环条件的判断; 对于for语句,continue语句将使控制转到:先计算,然后计算,并根据的计算结果来决定是进入下一次循环还是结束循环。,用空语句和goto语句实现continue语句的功能,while (.) . continue; 上述程序等价于: while (.) . goto end; end:; ,例:从键盘输入一些非零整数,然后输出其中所有正数的平方根。,#include #include using namespace std; int main() in
23、t n;double square_root;cout n; n!=0; cinn) if (n 0) continue; /准备进入下一次循环square_root = sqrt(n);cout n “的平方根是:“ square_root endl;return 0; ,程序设计风格,程序设计风格通常是指对程序进行静态分析所能确认的程序特性,它涉及程序的易读性。 采用一致/有意义的标识符为程序实体(如:变量、函数等)命名。 使用符号常量 为程序书写注释 采用代码的缩进格式,等 除此之外,结构化程序设计就是一种良好程序设计风格的典范。,结构化程序设计,结构化程序设计(Structured P
24、rogramming,简称SP)是指“按照一组能够提高程序易读性与易维护性的规则进行程序设计的方法” SP不仅要求所编出的程序结构良好,而且还要求程序设计过程也是结构良好的,后者是前者的基础。 对程序设计过程而言,“结构良好”是指 采用分解和抽象的方法来完成程序设计任务, 具体体现为:“自顶向下、逐步精化”的程序设计过程。 对程序而言,“结构良好”是指: 每个程序单位应具有单入口、单出口的性质。 不包含不会停止执行的语句,程序在有限时间内结束。 程序中没有无用语句,程序中所有语句都有被执行的机会。,结构化程序设计(续),结构化程序设计通常可用三种基本结构来实现,(顺序),(选择),(循环),上面三种结构都具有单入口、单出口的性质。,关于goto语句,goto语句会使得程序的静态结构和动态结构不一致,导致程序难以理解、可靠性下降和不容易维护。有时会导致程序效率的下降。 从结构化程序设计的角度讲, goto语句会破坏程序中的每一个结构所具有的单入口/单出口的性质。 实际上,goto语句的使用可以分成两类: 向下的转移(forward)(可用分支结构实现) 往回的转移(backward)(可用循环结构实现) 尽量不要使用goto语句。,