1、单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,化学工业出版社,第4章 程序的控制结构,在程序设计中,常常采用三种流程控制结构,分别是顺序结构,分支结构(又叫选择结构)和循环结构。流程控制结构是结构化程序设计的基本思想。一个复杂的问题一般可以转化为有限个顺序,分支或者循环结构来解决。,顺序结构是使用最为广泛的控制结构,程序从上往下顺序执行,即使是分支结构和选择结构,其内部也往往采用顺序结构。另外各个模块之间也是从上向下顺序执行的。,分支结构是指程序执行到某个地方之后有多个分支,程序需要根据某个条件来决定到底执行哪个分支的一种流程控制结构。正是因为有了分支
2、结构,程序和用户之间的交互能力才得以大大增强。在Delphi中提供了两种分支结构的语句,分别是If语句和Case语句。,如果在程序中需要重复执行某些语句和程序段。这时候往往使用循环结构来解决,循环结构可以避免我们重复书写相同的或者类似的程序代码,使得程序更加清晰明了,极大地简化了程序,提高了效率。在Delphi中提供了三种循环语句,分别是while语句、repeat语句和For语句。,4.1 分支结构,分支结构通过判断条件表达式,再根据结果进行不同的操作。条件表达式一般是逻辑表达式或者关系表达式,类型为Boolean型,其值为true或者false。Boolean类型是顺序型,false的序号
3、为0,true的序号为1。,4.1.1 if语句,if语句是最常见的分支结构的语句,if语句是这样操作的,如果所给条件成立(值为true)则执行,否则执行,其流程图如图4-1所示。,1if语句的语法格式,if语句的语法格式为:,if,then,else,说明:,(1)条件是关系表达式或者逻辑表达式,程序是这样判断的,如果条件成立(值为true),则执行,如果条件不成立(值为false)则执行。,(2)和都可以省略。,(3)如果或者是几个语句,则用begin和end括起来形成复合语句的形式。,(4)整个if语句看成一个语句,因此不能在if语句中间加分号。,例如:,if ab,then write
4、ln(a);/这个分号有错误,,else writeln(b);,再看下面:,if ab,then,begin,t:=a;,a:=b;,b:=t;/可以加分号,和Begin、End形成复合语句,end,/不可加分号,整个IfThenElse是一个语句,else,begin,writeln(1111);,writeln(2222);,end;,2if语句的应用,【例4-1】求3个数的最大值。,分析:可以使用if语句来编写程序,程序比较简单。程序如下:,program Project1;,$APPTYPE CONSOLE,uses,SysUtils;,var ma,a,b,c:real;,begi
5、n,write(a,b,c=?);,readln(a,b,c);,ma:=a;/假设a最大,if bma then ma:=b;/若bma,则最大为b,if cma then ma:=c;/若cma,则最大为c,writeln(最大数为,ma);,readln;,end.,【例4-2】简单的密码程序。,程序设计步骤:,(1)添加组件GroupBox、Edit、Button和Panel到窗体,设置组件的属性:GroupBox1的Caption设置为“输入口令”,Edit1的Passwordchar设置为“*”,设置Button1的Caption为“确定&E”,界面如图4-2(a)和4-2(b)所
6、示。,(2)编写Button1的OnClick事件过程如下:,procedure TForm1.Button1Click(Sender:TObject);,begin,if uppercase(edit1.Text)=ABCDEF /口令是“abcdef”,不分大小写,then panel1.Caption:=欢迎使用本系统,else,begin,edit1.Text:=;,edit1.SetFocus;/清空文本框并置焦点,panel1.Caption:=口令错误;,end;,end;,另外我们希望输入口令后按回车键也可以判断口令是否正确,因此编写Eidt1的OnKeyPress事件过程如下
7、:,procedure TForm1.Edit1KeyPress(Sender:TObject;var Key:Char);,begin,if key=#13 then /如果按了回车键,begin,if uppercase(edit1.Text)=ABCDEF,then panel1.Caption:=欢迎使用本系统,else,begin,edit1.Text:=;,edit1.SetFocus;,panel1.Caption:=口令错误;,end;,end;,end;,下面的Edit1的OnChange事件过程用于清除Panel1中的内容:,procedure TForm1.Edit1Ch
8、ange(Sender:TObject);,begin,panel1.Caption:=;,end;,(3)按F9键运行程序,运行程序的界面如图4-3(a)和4-3(b)所示。,3if语句的嵌套,如果在if语句中还有if语句就称之为if语句的嵌套。有时候if语句的嵌套会产生歧义性。例如:,if yuwen=60,then if yuwen=85,then writeln(优秀),else writeln(不及格);,我们本希望else子句属于前面一个if语句,但是实际上本例中的else子句属于后面一个if语句。Delphi规定:else子句总是属于与它最靠近的那个没有else子句的ifthen
9、语句。虽然如此,但是用户还是比较容易理解错误。因此,建议把上面的这个嵌套if语句写成如下形式:,if yuwen=60,then if yuwen=85,then writeln(优秀),else,else writeln(不及格);,或者:,if yuwen=60,then begin if yuwen=85,then writeln(优秀),end,else writeln(不及格);,这样就不容易理解错误了,另外建议书写程序的时候将程序行适当缩进,这样也可以避免对程序的错误理解。,【例4-3】修改上面的密码程序,允许用户3次出错,如果第3次密码仍然错误,则结束程序。请使用嵌套的if语句完
10、成。,只需要简单Button1的OnClick事件过程即可:,procedure TForm1.Button1Click(Sender:TObject);,begin,if uppercase(edit1.Text)=ABCDEF,then panel1.Caption:=欢迎使用本系统,else,begin,edit1.Tag:=edit1.Tag+1;/无需重新定义变量,if edit1.Tag=3 then,begin,messagedlg(3次密码错误,您无权使用本程序,mterror,mbok,1);,/显示错误信息,application.Terminate;/程序停止,end;,
11、edit1.Text:=;/此处无需加Else,edit1.SetFocus;,panel1.Caption:=口令错误;,end;,end;,别忘了将Edit1的OnKeyPress事件过程也做类似修改。此处省略。,4.1.2 case语句,if语句可以解决两路分支问题,而case语句可以解决多路分支问题,即从多个语句序列中选择一路语句序列执行。,1case语句的语法格式,case语句的语法格式为:,case,of,常量表1:语句序列1;,常量表2:语句序列2;,常量表3:语句序列3;,常量表n:语句序列1;,else 语句序列n+1;,end;,说明:,(1)表达式必须是顺序类型,如整型、
12、字符型、枚举、子界、布尔型等。,(2)各个常量表中的常量应该用逗号隔开,各个常量表中的常量不能够相同。,(3)如果语句序列是多个语句可以使用begin和end括起来形成复合语句。,(4)如果表达式的值与某个常量表中的某个常量值相等则程序就执行该语句序列,执行完毕,程序转到case语句之外执行其他余句;如果表达式的值与所有常量表中的常量的值都不相等,则程序执行else之后的语句序列n+1(如果有else部分的话)。,case语句的流程图如图4-4所示。,2case语句的应用,【例4-4】计算每个月的天数。,分析:根据常识1、3、5、7、8、10和12月每个月有31天,而4、6、9和11月每个月有
13、30天,2月份闰年有29天,平年有28天。符合下列情况之一就是闰年:I)年号能被400整除;II)年号能被4整除但是不能够被100整除。,建立Console Application应用程序如下:,program Cadays;,$APPTYPE CONSOLE,uses,SysUtils;,var year,month,days:integer;,begin,write(year,month=?);,readln(year,month);,case month of,1,3,5,7,8,10,12:days:=31;,4,6,9,11:days:=30;,2:if(year mod 400=0
14、)or(year mod 1000)and(year mod 4=0),then days:=29,else days:=28;,else writeln(Input year error!);,end;,writeln(year:4,年,month:1,月有,days:2,天。);,readln;,4.2 循环结构,Delphi提供了三种循环结构的语句,分别是While语句、Repeat语句和For语句,这三种语句分别在不同的环境条件下使用,一般情况下,它们是可以互相替代的。三种循环语句各有各的特色,其中While语句和Repeat语句用于循环次数未知的情况下,根据循环条件来控制循环次数,F
15、or语句用于循环次数已知的循环。在实际应用中用户可以选择合适的循环语句,对于有的问题,三种循环都可以实现。,4.2.1 while语句,while语句属于前测型循环语句。首先判断条件,根据条件来决定是否循环,如果条件成立则循环,否则不循环,也有可能一次也不循环。其流程图如图4-5(a)和图4-5(b)所示。,1while语句的语法格式,while语句的语法格式为:,while do,循环体;,说明:,(1)条件是这样判断的,如果条件成立(值为true),则执行循环体,如果条件不成立(值为false),则结束循环,执行循环体之后的语句。,(2)循环体可以是若干个语句,如果是一个以上的语句,可以使
16、用begin和end括起来,形成复合语句的形式。,(3)可以在循环体中添加continue语句,用if语句来控制continue,程序执行continue用于结束本次循环执行下一次循环。,(4)还可以在循环体中添加break语句,用if语句来控制break,程序执行break用于结束整个循环,执行循环体之后的语句,程序结束循环之前无需判断循环条件。,2while循环的应用,【例4-5】求s=1+2+3+100的值。,分析:可以使用变量n来作为加数,n的值从1一直计数到100变化,每一次将n的值加到s中,n都要自加1,s用来保存1+2+3+100的和,s的初始值赋值为0。根据分析流程图如图4-6
17、所示。,程序设计步骤,(1)添加组件到窗体,设置组件的属性,界面如图4-7所示。,(2)编写Button1的OnClick时间过程。,procedure TForm1.Button1Click(Sender:TObject);,var,s,n:integer;,begin,s:=0;n:=1;,while n=100 do,begin,s:=s+n;,n:=n+1;,end;,panel1.Caption:=s=1+2+3+.+100=+inttostr(s);,end;,(3)按F9键运行程序,运行程序界面如图4-8所示。,4.2.2 repeat语句,repeat,语句一般用于循环次数不确
18、定的循环。首先执行循环语句,然后再来判断循环条件来决定是否继续执行循环,因此repeat语句至少要执行一次循环语句。repeat语句的流程图如图4-9(a)和图4-9(b)所示。,1repeat语句的语法格式,repeat语句的语法格式为:,repeat,循环体;,until;,说明:,(1)repeat循环是后侧型循环,首先执行循环体,再判断循环条件。,(2)语句体可以是若干个语句,多条语句无需用begin和end括起来,用自身的repeat和until将其括起来。,(3)循环条件是这样判断的:如果条件为真则结束循环,转而执行循环体之后语句,如果循环条件为假则继续循环。一般循环条件在执行的过
19、程中是会改变的。,(4)可以在循环体中加入continue语句,一般用if来控制continue,continue语句可以让程序提前结束本次循环(无需判断循环条件),转而去执行下一次循环。,(5)还可以在循环体中加入break语句,一般使用if语句来控制break,break语句可以让程序结束整个循环(无需判断循环条件),转而去执行循环体之后的语句。,2repeat循环的应用,【例4-6】求的值,利用公式/41-1/3+1/5-1/7+求近似值。直到最后一项的绝对值小于0.0001为止。,分析:先计算出右边多项的和,然后再乘以4即为所求的近似的值。令右边各项之和的值为pi,右边每一项的分母分别
20、为奇数1、3、5,符号是一正一负的。可以使用n作为计数器,控制分母,fh用来控制正负,则每一项的值为fh/n,使用循环将每一项加到pi中就可以得到右边各项之和。最后乘以4即可得到近似的值。根据分析绘制出流程图如图4-10所示。,程序设计步骤,(1)添加组件到窗体,设置组件的属性,界面如图4-11所示。,(2)编写Button1的OnClick事件过程,如下:,procedure TForm1.Button1Click(Sender:TObject);,var,fh,pi,n:real;,begin,pi:=0;n:=1;fh:=1.0;,repeat,pi:=pi+fh/n;,n:=n+2;/
21、分母为奇数,fh:=-fh;/每项的符号是变化的,until 1/n=0.0001;,pi:=4*pi;,panel1.Caption:=+floattostr(pi),end;,(3)按F9键运行程序,运行程序界面如图4-12所示。,procedure TForm1.Edit1KeyPress(Sender:TObject;var Key:Char);,var,pn,fn:real;,begin,if key=#13 then /输入误差后按回车键,begin,pn:=sqrt(2);fn:=2/pn;/第一项的分母和第一项,repeat,pn:=sqrt(pn+2);/第n项的分母,fn:
22、=fn*2/pn;/n项乘积,再乘以2就是的近似值,until abs(2*(fn*2/pn)-2*fn)1000。另外本程序求和的时候没有包括3的倍数,所有3的倍数都排除在外,因此如果在加的过程中如果判断加数是3的倍数则结束本次循环,进入下一次循环。流程图如图4-17所示。,程序设计步骤如下:,(1)界面设置,属性设置。界面如图4-18所示。,(2)编写Button1的OnClick事件过程。,procedure TForm1.Button1Click(Sender:TObject);,var,s,i:integer;,begin,s:=0;,for i:=1 to 1000 do,begi
23、n,if i mod 3=0 then continue;,s:=s+i;,if s1000 then break;,end;,panel1.Caption:=1+2+4+5.+;,panel1.Caption:=panel1.Caption+inttostr(i)+=+inttostr(s);,end;,(3)按F9键运行程序,运行程序界面如图4-19所示。,4.2.4 多重循环,如果在循环中还有循环,就构成多重循环结构。常用的多重循环有二重循环和三重循环。可以使用相同的循环语句或者不同的循环语句来现实多重循环。,【例4-9】求100以内的素数。,分析:判断n是否为素数可以这样进行,先假设n
24、是素数,设一个标志flag的值为True;然后在2到之间寻找n的因子,只要能够找到n的因子(一个足够),就令flag的值为False;如果经过2到的循环flag的值仍然是True,说明n是素数,否则n不是素数;如果n是素数,则输出这个n。,由于1不是素数,让n从2到100循环,执行上面的操作,即可输出100以内所有的素数。本程序的循环次数已知,因此两个循环都用For语句来实现。,根据以上分析,不难画出本程序的流程图,如图4-20所示。,程序设计步骤如下:,(1)添加组件,属性设置省略,界面如图4-21所示。,(2)编写Button1的OnClick事件过程。,procedure TForm1.
25、Button1Click(Sender:TObject);,var,n,i:integer;,flag:boolean;,begin,for n:=2 to 100 do,begin,flag:=true;/假设n是素数,for i:=2 to trunc(sqrt(n)do,/在2到trunc(sqrt(n)之间寻找n的因子,/循环变量的初值和终值为整型,因此要取整,if n mod i=0 then flag:=false;,/i是n的因子,因此n不是素数,故修改flag为false,if flag then,listbox1.Items.Add(inttostr(n);/输出素数n,en
26、d;,end;,(3)按F9键运行,运行界面如图4-22所示。,【例4-10】验证歌德巴赫猜想,歌德巴赫认为一个非常大的偶数可以分解成为两个素数之和的形式。本程序要求输入一个较大的偶数n,将这个偶数n分解成为两个素数p和q相加的形式,例如,输入10,输出10=3+7和10=5+5。试编写程序。,分析:一个数n可以分解成p+q的形式:p从2到n/2循环,而q始终取值为n-p;现在只要满足p和q都是素数即可,如果p和q都是素数就输出p和q。判断p和q是否是素数,可以使用for循环,外加p从2到n/2的循环,这样使用二重循环即可解答本题。根据分析画出流程图如图4-23所示。,(2)编写Button1
27、的OnClick事件过程。,procedure TForm1.Button1Click(Sender:TObject);,var,n,p,q,i:integer;,flagp,flagq:boolean;,s:string;,begin,listbox1.Items.Clear;,n:=strtoint(inputbox(输入一个正整数n,输入n ,);,p:=1;,repeat,p:=p+1;q:=n-p;,flagp:=true;/假设p是素数,for i:=2 to trunc(sqrt(p)do,if p mod i=0 then flagp:=false;/p不是素数,flagq:=
28、true;/假设q是素数,for i:=2 to trunc(sqrt(q)do,if q mod i=0 then flagq:=false;/q不是素数,if flagp and flagq then,begin,s:=inttostr(n)+=+inttostr(p)+inttostr(q);,listbox1.Items.Add(s);,end;,/输出,until p=n/2;,end;,(3)按F9键运行程序,运行程序界面如图4-25所示。,在设计循环类程序时,一定要思路清晰,最好画出流程图,对于多重循环,应该注意以下几个问题:,(1)内外循环只能嵌套,不能交叉;,(2)不同层的循
29、环,不要使用相同的循环变量,并列的循环除外;,(3)注意程序的缩进格式,这样可以减少循环程序出错的概率。,4.3 小结,本章讲述了程序的控制结构,包括顺序结构、分支结构和循环结构。本章的各个控制结构都安排有典型的例题,通过这些例题,读者应该掌握这三种基本控制结构的用法,并能够在程序中灵活运用。,读者要注意iF语句和case语句的区别和适用场合;注意三种循环语句的特点和优点,在何种情况下适合使用哪种循环,这些读者都应该熟知,并灵活掌握和使用。多重循环是难点,读者要注意其中一些注意事项。,习题,1有下面一段代码:,a:=6;b:=20;,if a5,then if a4,then b:=10,el
30、se,else b:=15;,程序执行后,b的值为(),(A)20 (B)10 (C)15 (D)其他值,2有下面程序段:,year:=2008;month:=2;,case month of,1,3,5,7,8,10,12:days:=31;,4,6,9,11:days:=30;,2:Begin days:=28;,if year mod 400=0 then days:=29;,if(year mod 1000)and(year mod 4=0)then days:=29,end;,end;,程序执行后,days的值为(),(A)28 (B)29 (C)30 (D)31,3输入某个学生的成
31、绩,输出该生成绩的等次,已知85分或者85分以上为“优秀”,70分或者70分以上到85分为“良好”,60分或者60分以上到70分为“及格”,60分以下为“不及格”,试编写程序。,4输入某年、月、日,判断该年、月、日是这年的第几天。,5以1,2,3,4,5为边长,可以形成多少个三角形。假设三角形的三边为a、b、c,a=2、b=2、c=3和a=2、b=3、c=2以及a=3、b=2、c=2表示的是一个三角形。类似的情况,在统计的时候只能够按照一个三角形来计算。,提示:不妨令a=b=c,这样就不会出现把a=2、b=2、c=3和a=2、b=3、c=2以及a=3、b=2、c=2看成是一个三角形了。,6打印
32、如图4-26所示的图形。,7编写程序,求出等差级数a+2a+3a+na的值,n和a是由键盘输入的正整数。尝试用多种方法完成。,8.编写程序,判断一个数是否为完数,所谓完数,就是这个数刚好等于它的因子之和,如6的因子为1,2,3,而6=1+2+3,所以6为完数。,9输入两个正整数m,n,求m和n的最小公倍数和最大公约数。这个问题在本章中已经讲解,读者可以考虑使用多种方法。,提示:求m和n的最大公约数相当于求n和m mod n的最大公约数,而任何正整数和0的最大公约数就是这个正整数。,14两个乒乓球队进行比赛,各出3人。甲队为A、B、C三人,乙队为X、Y、Z三人。已抽签决定比赛对阵名单。有人向队员打听比赛名单,A说他不和X比赛,C说他不和X、Z比赛,试编写程序找出三队比赛选手。,15猴子吃桃问题。小猴子第一天摘下若干个桃子,当即吃掉一半,还不过瘾,又多吃了一个。第二天又将剩下的桃子吃了一半,并多吃了一个。以后每天都吃剩下的一半,并多吃一个。等到第10天早上猴子想吃桃子时发现只剩下一个桃子。问第一天小猴子共摘了多少桃子?,