1、第三章 程序控制结构第三章 程序控制结构通过第二章的学习,我们已经可以设计简单的C+程序了。之所以说它简单,是因为所举的例程都是按照语句书写的顺序依次执行的。而实际的程序并不都是按我们的设想顺序执行。比如学生成绩管理系统,有时需要根据学生的成绩来决定下一步是否给予奖励,有时又需要用同一种方案重复统计每个学生的总分。从软件设计的角度说,程序的运行过程存在可选性和重复性。这种语句执行的秩序规则称之为程序控制结构。C+作为一种面向对象的高级程序设计语言,同样支持结构化的程序设计,它提供了顺序结构、选择结构和循环结构等三种基本的程序控制结构。从本章开始,我们将通过学习这三种控制结构,逐步进入软件设计的
2、核心算法设计。3.1顺序结构所谓顺序结构,就是按照语句出现的先后顺序依次执行各条语句。在+中,顺序结构主要是由数据输入和输出语句、表达式语句、空语句、复合语句等语句构成。图3.1给出了一个顺序结构的执行流程,整个程序只有一个入口和一个出口。程序执行时,依次执行语句1和语句2。图3.1 顺序结构执行流程图例3.1 在学生管理系统的系统菜单中,包括输入学生成绩、修改学生成绩、删除学生成绩、计算每个学生的总分、计算每个学生的平均分、按学号或姓名查询学生成绩、按班级查询学生成绩、成绩排序、按班级统计学科总分和按班级统计平均分等子菜单,这里只是列出该系统的部分菜单。思路分析:输出菜单就是输出若干选项,供
3、用户选择。因此,可以采用顺序结构,依次输出各个选项(带有编号),具体各个选项的功能实现在以后章节逐步讲解。编写程序如下:#includevoid main()cout 学生管理系统endl;coutendl;cout =endl;coutendl;cout 1.输入学生成绩endl; cout 2.修改学生成绩endl;cout 3.删除学生成绩endl;cout 4.计算每位学生的总分endl;cout 5.计算每位学生的平均分endl;cout 6.按学号或姓名查询学生成绩endl;cout 7.按班级查询学生成绩endl;cout 8.成绩排序endl;cout 9.按班级统计学科总分,
4、平均分等endl;coutendl;程序执行时,依次输出各个菜单项,程序执行后,运行结果如图3.2所示。图3.2 例3.1的运行结果例3.2 输入两个学生的成绩cj1和cj2,交换后输出。思路分析:变量的交换不能直接互相赋值,这样会导致其中一个变量值丢失。实现二个的变量交换有二种方法。方法一:借助第三变量t实现交换。交换过程如图3.3所示。图 3.3 借助中间变量的交换示意图具体程序代码如下:#include iostream.hvoid main()int cj1,cj2,t;cout输入第一个学生的成绩:cj1;cout输入第二个学生的成绩:cj2;cout交换前:endl;cout第一个
5、学生的成绩为:cj1endl;cout第二个学生的成绩为:cj2endl;t=cj1; cj1=cj2;cj2=t; cout交换后:endl;cout第一个学生的成绩为:cj1endl;cout第二个学生的成绩为:cj2endl;方法二:不使用第三个变量实现交换。#include iostream.hvoid main()int cj1,cj2;cout请输入两个学生的成绩:endl;cout第一个学生的成绩为:cj1;cout第二个学生的成绩为:cj2;cout交换:endl;cout第一个学生的成绩为:cj1endl; cout第二个学生的成绩为:cj2endl; cj1=cj1+cj2
6、; cj2=cj1-cj2; cj1=cj1-cj2; cout交换后:endl;cout第一个学生的成绩为:cj1endl;cout第二个学生的成绩为:cj2endl;对比分析:第一种方法使用了附加的一个内存单元,增加了空间开销;而第二种方法通过简单的加、减运算来实现,增加了时间开销。二种方法的效果是相同的。例3.3 输入一个三位整数x,输出各个位的数字,比如输入123,输出1 2 3。分析:本题主要是考察取整运算符“/”和求余运算符“%”的使用。具体步骤为:用100整除x得到百位数,用10求余x得到个位数,用100求余x得到中间数y,然后再用10整除y得到个位数。#include iost
7、ream.hvoid main()int x,a,b,c;coutx;a=x/100; /百位数c=x%10; /个位数y=x%100;b=y/10; /十位数cout百分位数:aendl;cout十分位数:bendl;cout个位数:cendl;提示:(1)该题目可以有多种解法,比如求解十位数的时候,可以先用10整除x得到由百位数、十位数组成的两位数,然后再用10求余这个二位数就得到十位数。(2)该题目的算法可以用于同类其它问题的求解。例如,水仙花数的求解。所谓水仙花数是指一个三位数,它的每位数字的立方之和等于该数。例如,因为153=13+53+33,所以153是水仙花数。该题目可以取出各个
8、位的数字,然后计算判断就可以了。大家自己编写求水仙花的程序。思考:如果是任意多位数该如何实现呢?3.2选择结构所谓选择结构,即对给定的条件进行测试判断,并根据结果选择不同的操作。构成选择结构的语句称为条件语句。3.2.1 if语句if语句有三种基本形式:单分支if、双分支if语句以及多分支if语句。1单分支if语句单分支if语句的一般形式如下:if (表达式)语句;“表达式”是给定的条件,if语句首先计算“表达式”的值,如果结果为非0,则“语句”被执行,否则不执行。“语句”可以是简单语句,也可以是复合语句或其它结构语句。执行流程如图3.4所示。图3.4单分支if语句执行流程例如当两个数相除的时
9、候,我们需要检查分母是否为0:if (count != 0)average = sum / count;当多个语句依赖于同一个条件时,必须用一对花括号将它们括起来,使之相当于一个语句,我们称之为复合语句:if (count != 0) average = sum / count;cout average;例3.4 输入两个学生的成绩,输出其最大值。分析:定义变量cj1、cj2分别用于保存两个学生的成绩。再定义第三变量max用于保存最大值。先把第一个学生的成绩cj1的值赋给max,然后比较max和cj2的值,如果cj2比max大,则将max的值更新为cj2的值。此法俗称擂台法。编写程序如下:#i
10、nclude iostream.hvoid main() int cj1,cj2,max; cout第一个学生的成绩为:cj1; cout第二个学生的成绩为:cj2; max=cj1; if(cj2max)max=cj2; cout最高成绩为:maxc)& (a+bc)& (a+bc)s=(a+b+c)/2.0;area=sqrt(s*(s-a) *(s-b) *(s-c) ;cout”area=”areaendl;else cout”不能构成三角形。”c)& (a+bc)& (a+bc)的值,若为真,则按顺序执行花括号内的三个语句;否则,输出字符串“不能构成三角形。”。例3.4中是使用单分支
11、if语句结构实现的,这里我们可以用双分支if语句直接输出最高成绩。程序如下:#include iostream.hvoid main()int cj1,cj2;coutcj1cj2;if(cj1cj2)cout最高成绩为:cj1endl;elsecout最高成绩为:cj2endl;例3.5 计算下面的分段函数。分析:y的取值有两种情况,主要由x的值决定。对此可以使用双分支的if语句,实现程序的二选一执行流程。由此编写程序如下:#include void main()double x,y;coutx;if (x=0)y=1;elsey=-1;coutyendl;下面看一个实例。在“学生成绩管理系
12、统”中,需要输入学生的性别“ST_Sex”信息。由于性别是bool型变量,不能直接输入或输出,必须经过适当的转换:cout temp_Sex;if(temp_Sex = =1)ST_Sex =true;else if(temp_Sex = =0)ST_Sex =false; (3) if_else if语句(多分支)现实生活中的各种条件是很复杂的,在一定的条件下,又需要满足其它的条件才能确定相应的动作。为此,C+提供了if语句的嵌套功能,即一个if语句能够出现在另一个if语句或if-else语句里。这种形式的if语句的执行流程如图3.6所示。图3.6多分支if语句执行流程需要说明的是,不管有多
13、少分支,程序执行一个分支后,就不再执行其余的分支。如果有多个分支的条件都为true时,也仅执行第一个匹配的语句。因此,要在编写程序时要注意各表达式的书写次序。例如:if (ch = 0 & ch = A & ch = a & ch = 0 & ch = A & ch = a & ch 0,则有两个不等的实根;否则,有两个共轭复根。根据上述各种情况,可以采用嵌套的if语句对各种情况做判断。具体代码请读者自行编写、调试。3.2.2 switch语句在实际的工程应用中往往会遇到很多多分支选择的情况,这当然可以使用多分支if语句来解决。但+还提供了专门处理多分支结构的语句switch语句,该语句根据一
14、个表达式的不同取值决定程序的走向。采用这个语句会使程序的结构更加清晰、明了。switch语句的一般形式如下:switch (表达式)case常量表达式1:语句;.case常量表达式n:语句;default:语句;switch语句的执行过程是这样的:首先计算“表达式”的值,然后,其结果值依次与每一个常量表达式的值进行匹配。如果匹配成功,则执行该常量表达式后的语句系列。当遇到break时,则立即结束switch语句的执行,否则,顺序执行到花括号中的最后一条语句。default情形是可选的,如果没有常量表达式的值与“表达式”的值匹配,则执行default后的语句系列。需要注意的是,“表达式”的值的类
15、型必须是字符型或整型。switch语句的执行流程如图3.7所示。图3.7switch多分支语句执行流程例如,switch (operator)case +: result = operand1 + operand2;break;case -: result = operand1 - operand2;break;case *: result = operand1 * operand2;break;case /: result = operand1 / operand2;break;default: cout unknown operator: ch n;break;从上例我们可以看到:swit
16、ch语句中的每一个case的结尾通常有一个break语句,它停止switch语句的继续执行,而转向该switch语句的下一个语句。但是,我们有时也有意不加break语句。例如,我们修改上面的例子,以允许x作为乘法运算符,则可将上面的程序修改为:switch (operator) case +: result = operand1 + operand2;break;case -: result = operand1 - operand2;break;case x:case *: result = operand1 * operand2;break;case /: result = operand
17、1 / operand2;break;default: cout unknown operator: ch n;break;因为case x没有break语句,所以case x与case *执行相同的语句系列,也就是说,把x扩展成为乘法运算符了。很显然,switch语句可以写成if-else语句的形式。例如,上面的语句,我们可以写为:if (operator = +)result = operand1 + operand2;else if (operator = -)result = operand1 - operand2;else if (operator = x | operator =
18、*)result = operand1 * operand2;else if (operator = /)result = operand1 / operand2;elsecout unknown operator: ch n;但是,使用switch语句比用if-else语句简洁得多,可读性也好得多。遇到多分支选择的情形,我们应当尽量选用switch语句,避免采用嵌套较深的if-else语句。下面用switch语句重做例3.6。#include void main() int x; coutx;switch(x/10) case 10: case 9: cout优endl; break; ca
19、se 8: cout良endl;break; case 7: cout中endl;break; case 6: cout及格endl;break; default: cout不及格endl;同样的程序,即可以用多分支的if语句实现,也可以用switch语句实现,二者有什么异同呢?(1)一般来说,可以用switch语句实现的功能,用多分支if语句一定能实现,而反过来则未必。if语句的每个分支的条件可以是范围,而switch语句中个case语句不能是范围,只能是常量表达式。所以if语句转换成swich语句时,必须把if语句的范围转换成常量表达式。如上述例题要把成某范围的成绩通过整除转换成整数。(2
20、)switch语句的执行流程中,可以是几个分支执行同一个语句。一般来说,如果两个语句都可以则,使用switch语句会使程序的结构更清晰些。例3.7输入年份和月份,输出该月的天数。分析:该题有三种情况:1、3、5、7、8、10、12月份有31天;4、6、9、11有30天;2月份若是润年则有29天,否则是28天。可以使用switch语句设计程序。#include void main() int year, month,days ;cout year;cout month;switch( month) case 1:case 3:case 5:case 7:case 8:case 10:case 1
21、2:days =31 ;break ;case 4:case 6:case 9:case 11:days= 30;break ;case 2: if(year%4=0&year%100!=0)|(year%100 =0)days =29 ;else days =28 ;coutdays: daysendl ;例3.8 输入“学生成绩管理系统”中的体育成绩ST_Gym。因为ST_Gym是枚举类型,不能只能输入或输出,也要经过变换。enum ENUMExcellence,Good,Middling,Pass,Flunk;ENUM st_sport;cout temp_Gym;switch(temp
22、_Gym)case 1:st_sport=Excellence;break;case 2:st_sport=Good;break;case 3:st_sport=Middling;break;case 4:st_sport=Pass;break;case 5:st_sport=Flunk;break;3.3循环结构现在我们看一个问题:求s=1+2+3+100。按前面的方法,应该定义相关的变量进行数据输入、累加和输出。但这样至少需要定义101个变量,显然不现实,也不科学。要完成求和功能,可以按以下步骤操作:(1)定义整形变量s和i,并赋初值:s=,i=1;(2)若i100,则s=s+i;(3)令
23、i增加1,即i=i+1;(4)重复(2),直到i100;(5)输出s的的值,即为结果。可见,(2)、(3)二步是重复执行的,称为“循环体”。C+为解决循环问题提供了专门的控制语句,称为循环语句。3.3.1 while语句while语句的一般形式如下:while (表达式)语句;其中,“表达式”称为循环条件,可以是任何表达式,其值为真(非)或者为假();“语句”称为循环体,可以是一条简单语句,也可以是复合语句。while语句的执行过程如下:首先计算“表达式”的值,如果为真,则执行“语句”。这个过程重复进行,直至“表达式”的值为假即结束循环。While语句的执行过程如图3.8所示。图3.8whil
24、e语句执行流程对上面的求和问题可以用下面的程序来实现:#includevoid main() int i=1, sum = 0 ;while (i =100 )i+;sum += i ;cout sum = sum endl ;思考题:如果求100!=123100该如何求解?例3.9sinx=x/1-x3/3!+x5/5!-x7/7!+,设计一个程序,输入x的值,通过累加所有绝对值大于等于0.000001的项来计算sinx的值。分析:程序是求若干项和的问题,又不知道项的数目,可以用while语句。编写程序如下:#include #include void main( )double x;cou
25、t x ;double i=1.0,n=x,d=1.0,s=0,s0;while(fabs(s0=n/d)0.000001)s+=s0;i+;n*=(-x*x);d*=(i*i-2)*(2*i-1);cout sn;(2)令m除以n,得余数为r;(3)若r=0,则n即为最大公约数,结束;否则执行(4);(4)令m=n,n=r,转到第(2)步。从算法中可以看出,求最大公约数需要通过循环来实现,终止循环的条件是余数r为0。程序如下:#include void main()int m, n, t, r ;cout 输入m和n的值:n;cout m ;cout n ;if ( m n) t = m ;
26、 m = n ; n=t;while (r = m % n)!= 0 )m = n ;n = r ;coutm和n的最大公约数是:nendl;提示:(1)如何判断两个数是否为互质数?所谓互质数就是最大公约数是1。这样用该例题的方法求出最大公约数,如果最大公约数是1,则二者就是互质数。(2)对最小公倍数的求解,大家也可以参考该算法。(3)利用该算法大家可以求解其它类似问题。例3.11从键盘输入一串字符,将其中的英文字母加密后输出。分析:所谓加密,是指将英文字母变成其后的第4个字母。例如,输入China,加密后为lmre。当输入“”时程序结束。编写程序如下:#include #includevoi
27、d main()char ch;while(ch=getchar()!=#)if(ch=a & ch=A & chz|chZ & ch=Z+4 )ch=ch-26;coutch;cout n;cout n * n n;while (n != 0);上面的求s=1+2+3+100,用dowhil语句可以写为:s=0;i=1;do s+=i;i+;while(i=100 );while语句是“当型循环”,是“先判断后执行”,即当条件满足时执行循环体。因此,如果条件一开始就不满足,可能一次也不执行;而dowhile语句是“直到型循环”,是“先执行后判断”,即首先执行循环体,直到条件不满足时才结束循环
28、。因此dowhile循环至少执行一次。一般情况下,while语句和dowhile语句可以互换使用。#include void main() int sum=0,i;couti;while(i=10)sum=sum+i;i+;coutsum的值为:sumendl;执行程序如下:输入:1sum=55再次执行程序:输入:11sum=0#include void main() int sum=0,i;couti;dosum=sum+i;i+;while(i=10);coutsum的值为:sumendl;执行程序如下:输入:1sum=55再次执行程序:输入:11sum=11下面的程序可用来测试while
29、和dowhile的差别。可以看出:当输入i的值小于等于10的时候,二者结果相同。当i大于10的时候结果就不同了。这是因为,此时对while来说,循环一次也不执行,而对dowhile则要执行一次。由此可以得到结论:当while后面的表达示的第一次的值为“真”时,两种循环得到的结果相同,否则二者结果不同。例3.12 计算sin(x)在0,2上的积分。分析:求定积分可以直接利用定义求解。sin(x)在0,2上的积分就是sin(x)在0,2上的面积,把sin(x)化分成若干个梯形,这些梯形的和就是sin(x)在0,2上的积分。我们把0,2分成360份,求解每个点的sin(x)值,把相邻的sin(x)值
30、作为梯形的上、下底,高是2*/360。根据该思路编写程序如下:#include#include#define SIZE 361#define PI 3.14159void main()double s=0;int i=0;dos=s+sin(2*i*PI/360);i+;while(iSIZE);s=s*(2*PI/360);coutsendl;例3.13 用牛顿迭代法求解方程f(x)=x32x210x20=0 在x0=0附近的根。分析:由数值计算方法可知,牛顿迭代公式为:xn+1=xn-f(xn)/f(xn),其中n=0,1,2,3根据题目要求有:f(x)=x32x210x20f (x)=3
31、x24x+10算法描述如下:(1)令n=0,任意给定一个x0的值,由牛顿迭代公式求得x1= x0- f(x0)/f(x0),判别| x1- x0|是否小于给定的精度。若是,则迭代过程结束,x1作为方程的近似根,否则,执行下一步。(2)令n=,由迭代公式得x2= x1- f(x1)/f(x1),然后判别| x2- x1|是否小于。若是,则迭代过程结束,x2作为方程的近似根,否则由x2计算x3。如此迭代,直到| xi- xi+1|为止,i=0,1,2,。由于每一步当前值只需要用前两次迭代值xi+1和xi进行计算,所以在编写程序的时候,只需要x0和x两个变量来存放前两次迭代的值。编写程序为:#inc
32、lude #include void main() double x0, x, epson ; cout x0 ; cout epson ; do x = x0 ; x0 = x-(pow(x, 3)+2*pow(x,2)+10*x-20)/(3*pow(x,2)+4*x+10 ); while(fabs(x0-x)epson); cout 该方程的根是: x0 endl ;3.3.3 for语句for语句的一般形式如下:for (表达式1; 表达式2; 表达式3) 语句;for语句执行过程如下:首先计算“表达式1”(循环初值),且仅计算一次。每一次循环之前计算“表达式2”(循环条件),如果其
33、结果为真,则执行“语句”(循环体),并计算“表达式3”(循环增量)。否则,循环终止。for语句的执行流程如图图3.10所示。图3.10dowhile语句执行流程for循环通常用于有确定次数的循环。例如,下面的for循环语句用于计算整型数1n的和:sum = 0;for (i = 1; i = n; +i)sum += i;本例中,i通常称为循环变量,它并不在循环体内。C+也允许for语句的“表达式1”是一个变量定义。例如,上面的循环语句我们可以表示为:for (int i = 1; i = n; +i)sum += i;for语句中三个表达式中任一个均可以省略。例如,省略第一和第三个表达式:f
34、or (; i != 0;) / 等价于: while (i != 0)语句;如果把三个表达式都省略,则循环条件为1,循环无限次地进行,即死循环。for (;) /等价于: while (1)语句;for循环可以有多个循环变量,此时,循环变量的表达式之间用逗号隔开:for (i = 0, j = 0; i + j n; +i, +j)语句;循环语句能够在另一个循环语句的循环体内,即循环能够被嵌套。例如:for (int i = 1; i = 3; +i)for (int j = 1; j = 3; +j)cout ( i , j )n;本段程序运行结果如下:(1,1) (1,2) (1,3)图
35、3.11 运行结果(2,1) (2,2) (2,3)(3,1) (3,2) (3,3)例3.14循环变量的测试。大家分析以下的程序:#includevoid main()for ( int i =1; i=3; i+ );cout循环结束后i的值:iendl;执行程序,输出结果如图3.11所示。从输出结果可以看出,for循环结束后,循环控制变量的值是终值加1。这可以用于程序执行情况的判定,循环控制变量的值是终值加1,则说明循环是正常循环结束。否则,就是中间终止执行。图3.12 运行结果例3.15循环变量的控制。#includevoid main()int count=0;int x;for(i
36、nt i=1;ix;if(x=0) i-;cout循环次数为:countendl;执行程序,结果如图3.12所示。从for循环的初始值、终值以及循环变量的变化来看,循环应该进行9次,因为输入一个“0”值,执行了i-,致使循环多循环一次。由此可以看出,循环的次数除了for语句本身可以控制以外,也可以人为的控制循环的次数。这点在工程应用中有很重要的作用。在以后的例题中,大家将会看到“人为”控制循环次数的重要意义。例3.16猴子吃桃问题。猴子第一天摘下若干桃子,当即吃了一半,还不过瘾,又多吃了一个。第二天早上又将剩下的桃子吃掉一半,又多吃一个。以后每天早上都吃掉前一天剩下的一半零一个。到第10天早上想在吃的时候,就只剩下一个桃子了
版权声明:以上文章中所选用的图片及文字来源于网络以及用户投稿,由于未联系到知识产权人或未发现有关知识产权的登记,如有知识产权人并不愿意我们使用,如有侵权请立即联系:2622162128@qq.com ,我们立即下架或删除。
Copyright© 2022-2024 www.wodocx.com ,All Rights Reserved |陕ICP备19002583号-1
陕公网安备 61072602000132号 违法和不良信息举报:0916-4228922