程序控制结构.ppt
第4章 程序控制结构,4.3 选择控制,4.4 循环控制,小结,语句是程序的基本语法成分,C语言语句以分号结束。程序设计语言的语句按功能可以分成:1 表达式语句 描述对数据的处理 int x=5;int y;y=x-52 说明(申明)语句 变量、常量、函数的定义或申明 int NumOfStudent,4.1 C语言语句概述,4.1 C语言语句概述,3 复合语句(语句块):括住的若干条语句构成一个语句块称为复合语句。在语法上复合语句也是单语句。语句块内可以定义变量变量仅在定义它的语句块内(包括下层语句块)有效(scope.c)同一个语句块内的变量不可同名,不同语句块可以同名(homonym.c)各司其职、下层优先尽量不要在下层语句块内定义变量,也尽量不要定义同名变量复合语句可以用在任何可以使用语句的地方,4 控制语句 用于控制程序的执行流程。包括三种控制结构和转向语句所有程序都只能包含三种控制结构:顺序结构、选择结构和循环结构 转向语句 goto,break,continue,return 后面详细说明,4.1 C语言语句概述,已经证明,任何程序均可只用三种结构实现Bhm,Corrado,and Jacopini Guiseppe.Flow diagrams,Turing machines and languages with only two formation rules.Communication of ACM,9(5):366-371,May 1966.只用这三种结构的程序,叫结构化程序程序“必须”符合结构化规则,4.2 C语言的基本结构,4.2 C语言的基本结构,顺序结构,选择结构,循环结构,语句块,对给定的条件进行判断,并根据判断的结果选择不同的操作,4.3 选择语句,条件运算表达式根据判断条件,决定表达式的值不改变程序语句执行流程,1if 语句的形式和执行流程,if(表达式)语句 块;,4.3.1 if 语句,语句形式(1),语句形式(2),if(表达式)语句块1;else 语句块2;,1if 语句的形式和执行流程,4.3.1 if 语句,4.3.1 if 语句,2if 语句的嵌套,if 语句中的执行语句如果又是另一个if语句,称为嵌套if语句 if 与 else 的配对关系:C+规定,else 总是与它接近的if 配对,if(表达式1)语句块1;else if(表达式2)语句块2;else if(表达式3)语句块3;else语句块4;语句块5;else部分可以没有,2if 语句的嵌套,应用举例,(1)把输入字符转换为小写字母。对输入字符进行判断,如果是大写字母,则转换为小写字母;否则,不转换。,/例#include void main()char ch;cout ch;if(ch=A,输入的是大写字母,计算ASCII码偏移值,应用举例,把输入字符转换为小写字母。对输入字符进行判断,如果是大写字母,则转换为小写字母;否则,不转换。,/例#include void main()char ch;cout ch;if(ch=A,改写为条件表达式ch=(ch=A,(1)当条件表达式中包含&和|操作时,C+将进行短路求值。E1&E2 当表达式 E1 的值为 0 时,不对 E2 求值E1|E2 当表达式 E1 值为非 0 时,不再对 E2 求值,int a=3;int b=10;int c=0if(a2|b/c10).,由于a3这个表示式计算结果为0,所以后面的表达式不再计算,即使出现了除0错误;如果没有短路求值,则发生”除0错误”,由于a2这个表示式计算结果为1,所以后面的表达式不再计算,if 语句的的注意事项,if 语句的的注意事项,(2)不可将浮点变量用“=”或“!=”与任何数字比较。无论是float还是double类型的变量,都有精度限制。所以一定要避免将浮点变量用“=”或“!=”与数字比较,应该设法转化成“=”或“=”形式。,if(x=-EPSINON)&(x=EPSINON)其中EPSINON是允许的误差(即精度)。,多分支选择语句;将表达式的值与常量比较,如果与某一常量相等,则执行该常量后语句;如果与所有常量均不相等,则执行默认语句(default),无默认语句,则什么也不做。,switch(表达式)case 常量1:语句块1;break;case 常量2:语句块2;break;case 常量n:语句块n;break;default:语句块n+1;break;,语句标记,4.3.2 switch语句,swith语句执行流程,4.3.2 switch语句,switch使用注意事项:(1)switch后面括号内的“表达式”,允许为任何类型。(2)case后可以是常量表达式或者整数值;常量表达式样值只能是整型、字符型、枚举型,不能是其他类型(3)每一个case表达式的值必须互不相同,否则就会出现互相矛盾的现象(对表达式的同一个值,有两种或多种执行方案)。,4.3.2 switch语句,(4)各个case和default的出现次序不影响执行结果。例如,可以先出现“default:”,再出现“case D:”,然后是“case A:”。(5)执行完一个case子句后,流程控制转移到下一个case子句继续执行。“case常量表达式”只是起语句标号作用,并不是在该处进行条件判断.直到遇到break或者switch结束为止。,4.3.2 switch语句,#include using namespace std;int main(void)int day;cin day;switch(day)case 0:cout Sunday endl;break;case 1:cout Monday endl;break;case 2:cout Tuesday endl;break;case 3:cout Wednesday endl;break;case 4:cout Thursday endl;break;case 5:cout Friday endl;break;case 6:cout Saturday endl;break;default:cout Day out of range Sunday.Saturday endl;break;,例:4-3,4.3.2 switch语句,switch(int(E1)case 1:S1;break;case 0:S2;,if 与 switch 语句互换,if(E1)S1;else S2;,2.1.2 switch 语句,4.3.2 switch语句,if 与 switch 语句互换,switch(int(a b)case 1:max=a;break;case 0:max=b;,if(a b)max=a;else max=b;,2.1.2 switch 语句,4.3.2 switch语句,if 语句switch 语句 形成分支控制流程 不形成程序控制流程 用于复杂条件判断 表达式的值为数值集合时作多分支控制,可读性较好,与 if 语句比较:,2.1.2 switch 语句,为解决某一问题,或求取某一计算结果,特定的条件下,程序中反复地按某一模式进行操作。,循环概念,4.4 循环控制,为了锻炼身体,我要每天晚上在操场在跑10圈,两种典型循环结构,4.4 循环控制,4.4 循环控制,循环的组成部分循环体循环变量循环终止条件设计循环时应考虑的因素循环体的算法是什么?循环变量是什么?循环终止条件是什么如何改变循环变量C+的三种循环结构while语句先判断条件型do语句后判断条件型for语句先判断条件型,4.4.1 while语句,语句形式,while(表达式 e)循环体 s;,逻辑表达式不管表达式形式如何,结果都作为逻辑值,重复执行的操作直至表达式的值为false(0),执行流程,#include void main()int i=1,sum=0;while(i=100)sum=sum+i;i+;cout sum=sum endl;,想一想:循环条件是什么?循环结束条件是什么?哪一个语句修改循环条件?,一个简单的循环跟踪:求,4.4.1 while语句,求两个正整数 m 和 n 的最大公约数,例如:m=24,n=924 和 9 的最大公约数等于(24%9)=6 和 9 的最大公约数;9 和 6 的最大公约数等于(9%6)=3 和 6 的最大公约数;6 和 3 的最大公约数等于(6%3)=0 和 3 的最大公约数;所以,24 和 9 的最大公约数等于 3。,辗转相除法:当 m n,m 与 n 的最大公约数等于 n 和 m%n 的最大公约数;当 n=0,m 和 n 的最大公约数等于 m。,a=m,b=n,r=b;while(r!=0)把 a%b 的值赋给 r;用 b 的值替换 a 的值;用 r 的值替换 b 的值;a 是最大公约数,辗转相除法:当 m n,m 与 n 的最大公约数等于 n 和 m%n 的最大公约数;当 n=0,m 和 n 的最大公约数等于 m。,24%9,求两个正整数 m 和 n 的最大公约数,a=m,b=n,r=b;while(r!=0)把 a%b 的值赋给 r;用 b 的值替换 a 的值;用 r 的值替换 b 的值;a 是最大公约数,辗转相除法:当 m n,m 与 n 的最大公约数等于 n 和 m%n 的最大公约数;当 n=0,m 和 n 的最大公约数等于 m。,求两个正整数 m 和 n 的最大公约数,a=m,b=n,r=b;while(r!=0)把 a%b 的值赋给 r;用 b 的值替换 a 的值;用 r 的值替换 b 的值;a 是最大公约数,辗转相除法:当 m n,m 与 n 的最大公约数等于 n 和 m%n 的最大公约数;当 n=0,m 和 n 的最大公约数等于 m。,求两个正整数 m 和 n 的最大公约数,9%6,a=m,b=n,r=b;while(r!=0)把 a%b 的值赋给 r;用 b 的值替换 a 的值;用 r 的值替换 b 的值;a 是最大公约数,辗转相除法:当 m n,m 与 n 的最大公约数等于 n 和 m%n 的最大公约数;当 n=0,m 和 n 的最大公约数等于 m。,求两个正整数 m 和 n 的最大公约数,a=m,b=n,r=b;while(r!=0)把 a%b 的值赋给 r;用 b 的值替换 a 的值;用 r 的值替换 b 的值;a 是最大公约数,辗转相除法:当 m n,m 与 n 的最大公约数等于 n 和 m%n 的最大公约数;当 n=0,m 和 n 的最大公约数等于 m。,求两个正整数 m 和 n 的最大公约数,a=m,b=n,r=b;while(r!=0)把 a%b 的值赋给 r;用 b 的值替换 a 的值;用 r 的值替换 b 的值;a 是最大公约数,辗转相除法:当 m n,m 与 n 的最大公约数等于 n 和 m%n 的最大公约数;当 n=0,m 和 n 的最大公约数等于 m。,求两个正整数 m 和 n 的最大公约数,6%3,a=m,b=n,r=b;while(r!=0)把 a%b 的值赋给 r;用 b 的值替换 a 的值;用 r 的值替换 b 的值;a 是最大公约数,辗转相除法:当 m n,m 与 n 的最大公约数等于 n 和 m%n 的最大公约数;当 n=0,m 和 n 的最大公约数等于 m。,求两个正整数 m 和 n 的最大公约数,a=m,b=n,r=b;while(r!=0)把 a%b 的值赋给 r;用 b 的值替换 a 的值;用 r 的值替换 b 的值;a 是最大公约数,辗转相除法:当 m n,m 与 n 的最大公约数等于 n 和 m%n 的最大公约数;当 n=0,m 和 n 的最大公约数等于 m。,求两个正整数 m 和 n 的最大公约数,a=m,b=n,r=b;while(r!=0)把 a%b 的值赋给 r;用 b 的值替换 a 的值;用 r 的值替换 b 的值;a 是最大公约数,辗转相除法:当 m n,m 与 n 的最大公约数等于 n 和 m%n 的最大公约数;当 n=0,m 和 n 的最大公约数等于 m。,求两个正整数 m 和 n 的最大公约数,3 是 24 和 9 的最大公约数,a=m,b=n,r=b;while(r!=0)把 a%b 的值赋给 r;用 b 的值替换 a 的值;用 r 的值替换 b 的值;a 是最大公约数,辗转相除法:当 m n,m 与 n 的最大公约数等于 n 和 m%n 的最大公约数;当 n=0,m 和 n 的最大公约数等于 m。,求两个正整数 m 和 n 的最大公约数,#include void main()int m,n,a,b,r;cout m;cout n;if(m n)a=m;b=n;else a=n;b=m;r=b;while(r!=0)r=a%b;a=b;b=r;cout m and n maximal common divisor is:a endl;,求两个正整数 m 和 n 的最大公约数,提示输入数据,将最大数赋给a,初始余数,求新的余数,循环条件更改,4.4.2 do_while语句,语句形式,do 循环体 while(表达式);,4.4.2 do_while语句,表达式后的分号不能缺少。适用于循环至少执行一次的情况,例如,用do_while语句的求和式 的程序,#include void main()int i=1,sum=0;do sum+=i;i+;while(i=100);cout sum=sum endl;,4.4.2 do_while语句,4.4.2 do_while语句,4.4.2 do_while语句,#include void main()int i=1,sum=0;do sum+=i;i+;while(i=100);cout sum=sum endl;,while(i=100)sum=sum+i;i+;,例如,用do_while语句的求和式 的程序,4.4.2 do_while语句,例 输入二进制数字串,转换成十进制正整数。,二进制数bnbn-1b2b1b0有转换为十进制Dec的公式:Dec=bn2nbn-12n-1b222b121b020,输入 移位 转换,0,1,1,1,1,0,0,0,输入串,4.4.2 do_while语句,例输入二进制数字串,转换成十进制正整数。,二进制数bnbn-1b2b1b0有转换为十进制Dec的公式:Dec=bn2nbn-12n-1b222b121b020,输入 移位 转换,0,1,1,1,1,0,0,0,输入串,+=0,0,0,4.4.2 do_while语句,例输入二进制数字串,转换成十进制正整数。,二进制数bnbn-1b2b1b0有转换为十进制Dec的公式:Dec=bn2nbn-12n-1b222b121b020,输入 移位 转换,1,1,1,1,0,0,0,输入串,2,0,0,0,*=2,0,4.4.2 do_while语句,例输入二进制数字串,转换成十进制正整数。,二进制数bnbn-1b2b1b0有转换为十进制Dec的公式:Dec=bn2nbn-12n-1b222b121b020,输入 移位 转换,1,1,1,1,0,0,0,输入串,0,+=1,0,1,1,4.4.2 do_while语句,例输入二进制数字串,转换成十进制正整数。,二进制数bnbn-1b2b1b0有转换为十进制Dec的公式:Dec=bn2nbn-12n-1b222b121b020,输入 移位 转换,1,1,1,0,0,0,输入串,0,1,0,0,1,2,*=2,2,4.4.2 do_while语句,例输入二进制数字串,转换成十进制正整数。,二进制数bnbn-1b2b1b0有转换为十进制Dec的公式:Dec=bn2nbn-12n-1b222b121b020,输入 移位 转换,1,1,1,0,0,0,输入串,0,0,1,+=0,2,0,4.4.2 do_while语句,例输入二进制数字串,转换成十进制正整数。,二进制数bnbn-1b2b1b0有转换为十进制Dec的公式:Dec=bn2nbn-12n-1b222b121b020,输入 移位 转换,1,1,1,0,0,输入串,0,0,1,0,0,1,0,2,*=2,4,4.4.2 do_while语句,例输入二进制数字串,转换成十进制正整数。,二进制数bnbn-1b2b1b0有转换为十进制Dec的公式:Dec=bn2nbn-12n-1b222b121b020,输入 移位 转换,1,1,1,0,0,输入串,0,0,1,0,+=1,5,1,4.4.2 do_while语句,例输入二进制数字串,转换成十进制正整数。,二进制数bnbn-1b2b1b0有转换为十进制Dec的公式:Dec=bn2nbn-12n-1b222b121b020,输入 移位 转换,1,1,0,0,输入串,1,0,1,0,1,1,0,0,0,2,*=2,10,4.4.2 do_while语句,例输入二进制数字串,转换成十进制正整数。,二进制数bnbn-1b2b1b0有转换为十进制Dec的公式:Dec=bn2nbn-12n-1b222b121b020,输入 移位 转换,1,1,0,0,输入串,0,1,0,0,1,+=1,11,1,4.4.2 do_while语句,例输入二进制数字串,转换成十进制正整数。,二进制数bnbn-1b2b1b0有转换为十进制Dec的公式:Dec=bn2nbn-12n-1b222b121b020,输入 移位 转换,1,0,0,输入串,1,1,0,0,1,0,2,*=2,22,4.4.2 do_while语句,例输入二进制数字串,转换成十进制正整数。,二进制数bnbn-1b2b1b0有转换为十进制Dec的公式:Dec=bn2nbn-12n-1b222b121b020,输入 移位 转换,1,0,0,输入串,0,0,1,0,1,1,+=0,22,0,4.4.2 do_while语句,例输入二进制数字串,转换成十进制正整数。,二进制数bnbn-1b2b1b0有转换为十进制Dec的公式:Dec=bn2nbn-12n-1b222b121b020,输入 移位 转换,1,0,输入串,0,0,1,0,1,1,0,2,*=2,44,4.4.2 do_while语句,例输入二进制数字串,转换成十进制正整数。,二进制数bnbn-1b2b1b0有转换为十进制Dec的公式:Dec=bn2nbn-12n-1b222b121b020,输入 移位 转换,1,0,输入串,0,0,1,0,1,1,0,+=0,44,0,4.4.2 do_while语句,例输入二进制数字串,转换成十进制正整数。,二进制数bnbn-1b2b1b0有转换为十进制Dec的公式:Dec=bn2nbn-12n-1b222b121b020,输入 移位 转换,1,输入串,0,0,1,0,1,1,0,0,2,*=2,88,4.4.2 do_while语句,例输入二进制数字串,转换成十进制正整数。,二进制数bnbn-1b2b1b0有转换为十进制Dec的公式:Dec=bn2nbn-12n-1b222b121b020,输入 移位 转换,1,输入串,0,1,0,1,1,0,0,0,+=1,89,1,4.4.2 do_while语句,例输入二进制数字串,转换成十进制正整数。,二进制数bnbn-1b2b1b0有转换为十进制Dec的公式:Dec=bn2nbn-12n-1b222b121b020,输入 移位 转换,输入串,0,1,1,1,1,0,0,0,4.4.2 do_while语句,例输入二进制数字串,转换成十进制正整数。,二进制数bnbn-1b2b1b0有转换为十进制Dec的公式:Dec=bn2nbn-12n-1b222b121b020,DEC=0 CHAR=当前字符;NCHAR=下一个字符循环 直到当前字符是0或者1 DEC=DEC+当前字符转换后的数字 如果下一个字符为0或者1 DEC=DEC*2 否则 输入的字符串完成 当前字符=下一字符 重新读入新的下一个字符,程序的伪代码是,getche():从控制台读取一个字符,把该字符显示在屏幕上,也就是回显.getchar():从控制台读取一个字符,并回显,它和getche()的不 同在于,它等到输入一个回车才结束,就算你输入了 一个字符串,它也只取其中的第一个字符.,从输入流中读取一个字符的函数(conio.h),/例输入二进制数字串,转换成十进制正整数#include#include void main()int Dec=0;char ch;coutInput binary number:n;cout.flush();do ch=getche();while(ch!=0,4.4.2 do_while语句,一直到输入的第1个字符是0或1才开始,计算输入的字符是0还是1并累加,如果后一个字符是0或者1,则,累加值*2,一直到最后一个输入的字符是0或者1之外的其他字符,4.4.3 for语句,4.4.3 for语句,语句形式,for(表达式1;表达式2;表达式3)循环体;,初始表达式,循环控制逻辑表达式,循环后置表达式,执行流程,4.4.3 for语句,例如,用 for 语句的求和式 的程序,#include void main()int i,sum=0;for(i=1;i=100;i+)sum+=i;cout sum=sum endl;,4.4.3 for语句,4.4.3 for语句,(1)i=1;/缺省表达式1 for(;i=n;i+)sum=sum+i;,(2)for(i=1;i+)sum=sum+i;if(i n)break;/缺省表达式2,(3)for(i=1;i=n;)sum=sum+i;i+;/缺省表达式3,(4)for(i=1;i=n;sum+=i+);/缺省循环体,4.4.3 for语句,for语句中的三个表达式中任一个或全部均可省略,但分号必须保留;但是需要在程序中保证循环能正常终止.,4.4.3 for语句,(5)for(i=1;sum+=i+,i=n;);/缺省表达式3和循环体,(6)i=1;for(;)sum+=i+;if(i n)break;/缺省全部 for 的表达式,注意逗号表达式,4.4.3 for语句,Fibonacci 数列:0,1,1,2,3,5,8,13,21,34,f0=0f1=1fn=fn-1+fn-2(n=2),#include iostream.hint main()int n,i,a0,a1;cout n;a0=0;a1=1;/初始值cout a0 t a1 t;/显示初始值,输入 显示菲波那契数列的个数,显示第1个和第2个菲波那契数,例 求菲波那契数列的前 n 项(每10个数显示一行),从第3个菲波那契数 开始,for(i=2;i(i-1)*2)cout a0+a1 endl;return 0;,每次计算两个数据,所以循环次数是n/2,计算并显示两个菲波那契数,显示10个数据后输出换行符,如果要显示的个数是奇数,则显示最后一个菲波那契数,例 求菲波那契数列的前 n 项(每10个数显示一行),4.4.4 循环的嵌套,一个循环语句的循环体内又包含循环语句,称为嵌套循环 各种循环语句都可以互相嵌套,/例2-22 测试循环执行次数#includevoid main()cout i t j n;for(int i=1;i=3;i+)/外循环 cout i;for(int j=1;j=3;j+)/内循环 cout t j endl;,ij112321233123,2.2.4 循环的嵌套,例 求2-1000之间的素数,整数 m 是素数的条件:除 1 和 m 外,没有其它因数。,从定义出发,采用穷举法逐个数据测试:,判定整数m是否素数,穷举法 是一种重复型算法。基本思想是:对问题的所有可能状态一一测试,直到找到解 或将全部可能状态都测试过为止。,2.2.4 循环的嵌套,从定义出发,采用穷举法逐个数据测试:,以 i=2 m-1 作除数,只要有一个 i 是 m 的因数,则 m 不是素数。for(int i=2;i m;i+)if(m%i=0)break;if(m=i)m 是素数;else m 不是素数;,2.2.4 循环的嵌套,例 求2-1000之间的素数,1,2肯定是素数,所以先输出头两个素数,从3开始判断每个数是否是素数。由于偶数肯定不是素数,所以每次加2.(外循环),如果m能被2到m-1中的任何一个数整除,则m肯定不是素数.内循环,#includeiostream.husing namespace std;int main()cout 1t2t;/输出1,2,3 for(int m=3;m=1000;m+=2)for(int i=2;i m;i+)if(m%i=0)break;if(m=i)coutit;if(m%10=0)cout endl;/每行输出10个数 coutendl;return 0;,显示10个数据后输出换行符,程序运行结果,存在的问题:效率不高,循环了77191次;如果更改为10000以内的素数,循环次数高达5766453次,改进后的算法,若 m 不是素数,有:m=i*j,i=,double sqrtm=sqrt(double)m);/函数sqrt是double类型 for(int i=2;i=sqrtm;i+)if(m%i=0)break;if(sqrtm i)cout mt;,平方根函数,使用时需要加上CMath.H这个头文件,程序运行结果,效率比较高,循环了4457(77191)次;如果更改为10000以内的素数,循环次数为1087457(5766453)次,循环语句选择的一般思路:,如果循环次数已知,用for如果循环次数未知,用while如果循环体至少要执行一次,用do-while只是思路,不是定律,循环需要注意循环变量和循环终止条件的初始化。在for和while语句之后没有分号。有分号表示循环体就是分号之前的内容,即循环体不存在while(i 100);i+;for(i=0;i 100;i+);couti;for通常有一个循环变量控制循环的次数,不要在循环体内改变这个变量,循环语句注意事项:,循环语句-死循环,永远不会退出的循环为死循环for(;)while(1)do while(1)除非确实需要死循环,否则不要使用这样的形式。它们使循环的中止条件变得不明朗一般情况下,要极力避免死循环绝大多数程序不需要死循环。如果出现,往往都是bug时间过长的循环会造成“假死”现象,也要考虑解决,break语句 无条件地结束switch语句,或循环语句,转向执行语句块的后续语句 continue语句 用于循环体中,终止当前一次循环,4.4.5 转向语句,break 与 continue 语句比较,while(E1)语句 1 if(E2)break;语句 2,while(E1)语句 1 if(E2)continue;语句 2,break,continue,4.4.5 转向语句,goto语句 无条件转向语句,与标号语句配合使用,一般形式为:goto 标号;标号:语句;,4.4.5 转向语句,break和continue少用为妙它们增加了循环执行的分支,break更增加了循环的出口它们可以用来处理程序异常,而尽量不要用来处理正常流程,4.4.5 转向语句,尽量少使用或者不使用goto任何程序都可以不用goto就实现其功能。但在某些情况下,使用goto可以让程序更清晰,C+构成选择结构的条件语句有if语句和switch语句。if 语句适用于条件判断比较复杂的分支结构。嵌套if语句采用就近匹配的原则。用括号 改变复合语句结构,可以改变if与else的匹配关系。switch语句根据一个表达式的不同可能值决定选择执行,适用于条件判断比较简单的多路选择。,小结,小结,循环结构有whlie语句、do_while 语句和 for 语句。while语句和do_while语句主要用于条件循环。for语句是C+中很灵活的循环语句,既可以用于控制次数循环,也可以用于条 件循环。转向语句是程序的流程控制的补充机制。C+的转向语句主要有:break、continue和goto语句。,