950 likes | 1.13k Views
第三章 基本控制结构程序设计. 结构化程序设计的特点是任何程序都可由 三种基本结构 及其组合来描述。本章将介绍 C++ 分支结构和循环结构的设计方法。还将介绍一些 常用算法 。. 第三章 基本控制结构程序设计. 3 . 1 分支结构程序设计. 3 . 2 循环结构 程序设计. 3 . 3 转向语句. 3 . 4 常用算法的应用实例. 3 . 5 枚举类型. 3 . 6 输入输出文件简介. 3.1 分支结构程序设计.
E N D
第三章 基本控制结构程序设计 结构化程序设计的特点是任何程序都可由三种基本结构及其组合来描述。本章将介绍C++分支结构和循环结构的设计方法。还将介绍一些常用算法。
第三章 基本控制结构程序设计 3.1 分支结构程序设计 3.2 循环结构程序设计 3.3 转向语句 3.4 常用算法的应用实例 3.5 枚举类型 3.6 输入输出文件简介
3.1 分支结构程序设计 对程序的运行流程进行控制,主要通过执行专门用来控制流程的语句来实现。流程控制语句也称为过程化语句。分支语句是三种基本流程控制语句之一。C++提供以下三种分支语句: • if 语句 • 条件运算符 “ ? : ” • swith 语句
3.1 分支结构程序设计 3.1.1 if语句 3.1.2 条件运算符“?:” 3.2.1 swich语句
3.1.1 if语句 if语句有两种基本格式为: 1、if (<表达式>) <语句1>; 2、if (<表达式>) <语句1> else <语句2>;
if 语句 【例3.1】 输入一个年份,判断是否闰年。 算法分析:假定年份为year, 闰年的条件是 : year%4==0&&year%100!=0||year%400==0。 #include <iostream.h> void main( ){ int year; cout<<"输入年份:"<<endl; cin>>year; if (year%4==0&&year%100!=0 ||year%400==0) cout<<year<<"是闰年"<<endl; else cout<< year<<"不是闰年"<<endl; } ok
if语句 【例3.2】 从键盘上输入三个整数,输出其中的最大数。 分析:读入三个数,先求出两个数中较大者,再将该大数与第三个数比较,求出最大数。 #include <iostream.h> void main(){ int a, b, c, max; cout<<"输入三个正数:"; cin>>a>>b>>c; cout<<"a="<<a<<'\t'<<"b="<<b<<'\t‘ <<"c="<<c<<endl; if(a>b) max=a; else max=b; if(c>max) cout<< “最大数为:”<<c<<endl; else cout<< “最大数为:”<<max<<endl; } ok
if 语句 if 语句中,如果内嵌语句又是if语句,就构成了嵌套if语句。if 语句可实现二选一分支,而嵌套if语句则可以实现多选一的多路分支情况。 嵌套有两种形式,第一种是嵌套在else分支中: if (<表达式1>) <语句1>; else if (<表达式2>) 语句2; else if … else <语句n>; 第二种是嵌套在if分支中为: if (<表达式1>) if (<表达式2>) <语句1>; else<语句2>;
if语句 【例3.3】用嵌套if语句完成【例3.2】的任务。 //方法1:采用if中嵌套形式 #include <iostream.h> void main(){ int a, b, c, max; cout<<"输入三个正数:"; cin>>a>>b>>c; cout<<"a="<<a<<'\t'<<"b="<<b <<'\t'<<"c="<<c<<endl; if(a>b) if(a>c) max=a; //a>b且a>c else max=c; //a>b且a<c else if(b>c) max=b; //a<=b且b>c else max=c; //a<=b且b<c cout<<"最大数max="<<max;} ok
if语句 //方法2:采用else中嵌套形式 #include <iostream.h> void main(){ int a,b,c,max; cout<<"输入三个正数:"; cin>>a>>b>>c; cout<<"a="<<a<<'\t'<<"b="<<b <<'\t'<<"c="<<c<<endl; if(a>b&&a>c) max=a; else if(b>a&&b>c) max=b; else max=c; cout<<"最大数为:max="<<max; } ok
要特别注意else和if的配对关系。C++规定了if和else的“就近配对”原则,即相距最近且还没有配对的一对if和else首先配对。按上述规定,第二种嵌套形式中的else应与第二个if配对。如果根据程序的逻辑需要改变配对关系,则要将属于同一层的语句放在一对“{}”中。如第二种嵌套形式中,要让else和第一个if配对,语句必须写成:要特别注意else和if的配对关系。C++规定了if和else的“就近配对”原则,即相距最近且还没有配对的一对if和else首先配对。按上述规定,第二种嵌套形式中的else应与第二个if配对。如果根据程序的逻辑需要改变配对关系,则要将属于同一层的语句放在一对“{}”中。如第二种嵌套形式中,要让else和第一个if配对,语句必须写成: if (表达式1) { if (表达式2) 语句1 ; } else 语句2 ; 第二种嵌套形式较容易产生逻辑错误,而第一种形式配对关系则非常明确,因此从程序可读性角度出发,建议尽量使用第一种嵌套形式。
请看以下两个语句: //语句1: if(n%3==0) if(n%5==0) cout<<n<<″是15的倍数″<<endl; else cout<< n<<″是3的倍数但不是5的倍数″ <<endl; //语句2: if(n%3==0){ if(n%5==0) cout<<n<<″是15的倍数″<<endl; } else cout<< n <<″不是3的倍数″ 两个语句的差别只在于一个“{}”,但表达的逻辑关系却完全不同。
if语句 【例3.4】 某商场优惠活动规定,某种商品单 价为80元,一次购买5件以上(包含 5件)10件以下(不包含10件)打9 折,一次购买10件以上(包含10件) 打8折。设计程序根据客户的购买量计 算总价。
算法 • 1、输入购买件数count,设置单价price=80(元) • 2、根据count值确定折扣discount; • 3、实际售价amount=price*count*discount; • 4、输出amount的值。 算法细化: • 2.1、if(count<5)discount=1; • 2.2、if(count>=5&&count<10)discount=0.9; • 2.3、if(count>=10)discount=0.8; ok
#include <iostream.h> void main(){ float price=80,discount,amount;//单价,折扣,总价 int count; //购买件数 cout<<"输入购买件数:"<<endl; cin>>count; if(count<5) discount=1; else if(count<10) discount=0.9; else discount=0.8; amount=price*count*discount; cout<<"购买件数:"<<count<<endl; cout<<"单价:"<<price<<'\t'<<"折扣:“ <<discount<<endl; cout<<"总价:"<<amount<<endl; } 请在VC++平台上运行,输入不同的件数,使程序所有分支都可以被执行一次。 ok
if语句 • 【例3.5】 求一元二次方程 • ax2+bx+c=0 的根。 • 其中系数a(a≠0)、b、c的值由键盘输入。 • 分析:输入系数a(a≠0)、b、c后,令delta= b2–4ac,结果有三种情况: • 若delta=0,方程有两个相同实根; • 若delta>0,方程有两个不同实根; • 若delta<0,方程无实根。
算法 • 1、输入系数a(a≠0)、b、c; • 2、令delta= b2–4ac; • 3、根据delta的值求方程的根; • 4、输出方程的根; 算法细化: • 3.1、 if(delta==0)方程有两个相同实根;计算… • 3.2、 if(delta>0)方程有两个不同实根;计算… • 3.3、 if(delta<0)方程无实根;计算… ok
求一元二次方程的根源程序 #include <iostream.h> #include <math.h> void main(){ float a,b,c; float delta,x1,x2; const float zero=0.0001;//定义一个很小的常数 cout<<"输入三个系数a(a!=0), b, c:"<<endl; cin>>a>>b>>c; cout<<"a="<<a<<'\t'<<"b="<<b<<'\t‘ <<"c="<<c<<endl; delta=b*b-4*a*c;
if(fabs(delta)<zero){ //绝对值很小的数即被认为是0 cout<<"方程有两个相同实根:"; cout<<"x1=x2="<<-b/(2*a)<<endl;} else if(delta>0){ delta=sqrt(delta); x1=(-b+delta)/(2*a); x2=(-b-delta)/(2*a); cout<<"方程有两个不同实根:"; cout<<"x1="<<x1<<'\t'<<"x2=“ <<x2<<endl;} else //delta<0 cout<<"方程无实根!"<<endl; } 请在VC++平台上运行,输入不同的系数,使程序所有分支都可以被执行一次。
3.1.2 条件运算符“?:” if语句在某些情况下可以用条件运算符“?:”来简化表达。“?:”是一个三元运算符,其构成的表达式格式为:<表达式1> ? <表达式2> : <表达式3> 执行逻辑:先计算表达式1,若其值为真(或非0),则计算表达式2(不计算表达式3),并将该值作为整个表达式的值;反之,即表达式1的值为假或为0,则计算表达式3(不计算表达式2),并将该值作为整个表达式的值。 例如:int a=6,b=7, min=a<b?a:b; //min=6 min=a<b?++a:++b; //min=7 a=7 b=7 min=a<b?a++:b++; //min=6 a=7 b=7 ok
3.1.3 switch语句 用嵌套if语句可以实现多选一的情况。另外C++中还提供了一个switch语句,称为开关语句,也可以用来实现多选一: switch (表达式) { case 常量表达式1: 《语句序列1》《break;》 …… case 常量表达式n:《语句序列n》《break;》 《default:语句序列》 }
switch语句格式 (1)各个case(包括default)分支出现的次序可以任意,通常将default放在最后。 (2)break语句可选,如果没有break语句,每一个case分支都只作为开关语句的执行入口,执行完该分支后,还将接着执行其后的所有分支。因此,为保证逻辑的正确实现,通常每个case 分支都与break语句联用。 (3)每个常量表达式的取值必须各不相同,否则将引起歧义。
(4)允许多个常量表达式对应同一个语句序列。(4)允许多个常量表达式对应同一个语句序列。 例如: char score; cin>>score; switch (score) { case ′A′: case ′a′: cout<<″excellent″; break; case ′B′: case ′b′: cout<<″good″; break; default: cout<<″fair″; } (5)从形式上看,switch语句的可读性比嵌套if语句好,但不是所有多选一的问题都可由开关语句完成,这是因为开关语句中限定了条件表达式的取值类型。 ok
switch语句例子 【例3.6】运输公司对所运货物实行分段计费。设运输里程为s,则运费打折情况如下: s<250 不打折扣 250<=s<500 2%折扣 500<=s<1000 5%折扣 1000<=s<2000 8%折扣 2000<=s<3000 10%折扣 3000<=s 15%折扣 设每公里每吨的基本运费为p,货物重量为w,折扣为d,则总运费f为:f=p*w*s*(1-d) 设计程序,当输入p、w和s后,计算运费f。
算法 1、输入每吨运费p、货物重量w、运输里程s; 2、根据运输里程s计算折扣d; 3、计算总运费f=p*w*s*(1-d); 4、输出计算结果; 算法细化: 2、根据运输里程s计算折扣d 分析:如果用switch语句,必须使表达式符合语法要求,分析发现,里程s的分段点均是250的倍数,因此,将里程s除以250,取整数商,便得到若干整数值。 ok
s<250 不打折扣 250<=s<500 2%折扣 500<=s<1000 5%折扣 1000<=s<2000 8%折扣 2000<=s<3000 10%折扣 3000<=s 15%折扣 switch(c=s/250) { case 0: d=0; break; case 1: d=0.02; break; case 2: case 3: d=0.05; break; case 4: case 5: case 6: case 7: d=0.08; break; case 8: case 9: case 10: case 11:d=0.1;break; default:d=0.15; }
#include <iostream.h> #include <iomanip.h> void main( ){ int c,s; float p,w,d,f; cout<<"输入运输单价p,重量w和里程s:"<<endl; cin>>p>>w>>s; c=s/250; switch(c){ case 0: d=0; break; case 1: d=0.02; break; case 2: case 3: d=0.05; break; case 4: case 5: case 6: case 7: d=0.08; break; case 8:case9:case10:case11:d=0.1;break; default:d=0.15;} f=p*w*s*(1-d); cout<<"运输单价为"<<p<<'\t'<<"重量为"<<w<<'\t‘ <<"里程为"<<s<<endl; cout<<"折扣为"<<d<<endl; cout<<"运费为"<<f<<endl;} 请在VC++平台上运行,输入不同的里程,使程序所有分支都可以被执行一次。 ok
【例3.7】设计一个计算器程序,实现加、减、乘、除运算。【例3.7】设计一个计算器程序,实现加、减、乘、除运算。 分析:读入两个操作数和运算符,根据运算符完成相应运算。 #include <iostream.h> void main( ){ float num1,num2; char op; cout<<"输入操作数1,运算符,操作数2:"<<endl; cin>>num1>>op>>num2; switch(op){ case '+': cout<<num1<<op<<num2<<"="<<num1+num2<<endl; break; case '-': cout<<num1<<op<<num2<<"="<<num1-num2<<endl; break; case '*': cout<<num1<<op<<num2<<"="<<num1*num2<<endl; break; case '/': cout<<num1<<op<<num2<<"="<<num1/num2<<endl; break; default : cout<<op<<"是无效运算符!"; } } 常量表达式采用字符型,上机运行一下。
3.2 循环结构程序设计 循环控制语句是三种基本流程控制语句之一。C++提供以下三种循环语句: • while语句 • do-while 语句 • for语句
循环结构程序设计 3.2.1 while语句 3.2.2 do-while 语句 3.2.3 for语句 3.2.4 循环的嵌套
3.2.1 while 语句 求表达式的值 while语句也称为当循环。 语句格式为: while (表达式) 循环体语句; 表达式值为真? 否 是 执行循环体语句 图3.1 while语句的执行流程图
while 语句 【例3.8】 求1+2+3+4的值。 N个连续整数相加算法 1、设置变量i用来放被加数,变量sum用来放和值,并初始化; 2、从第一个数开始,依次将被加数赋给i,并进行操作sumsum+i; 3、输出sum; 细化算法2: while(还有被加数) { i=当前被加数; sum+=i; i准备接受下一个被加数; } ok
源程序如下: #include <iostream.h> void main( ){ int i=1,sum=0;//循环初始条件 while(i<=4) { sum+=i; i++; //修改循环条件 } cout<<"sum="<<sum<<endl; } 在VC++平台上运行,试一试是否正确 ok
while 语句 注意: 在有循环语句的程序中,通常循环开始前对循环条件进行初始化;而在循环体语句中要包含修改循环条件的语句,否则循环将不能终止而陷入死循环。 C++表达方式灵活,上例中的循环语句还可以写成: while (i<=n) sum+=i++; 或者 while (sum+=i++, i<=n) ;//循环体为空语句 修改程序后在VC++平台上运行,看是否正确
3.2.2 do-while 语句 do-while语句称为直到循环, 格式为: do 循环体语句 while( 表达式 ) 执行循环体语句 求表达式的值 表达式的 值为真? 是 否 图3.2 do-while语句的执行流程图
do-while 语句 do/while语句和while语句的区别: 多数情况下可以互相替代。 区别是do/while语句至少执行一次循环体后再判断循环条件是否满足; while语句先判断条件是否满足,然后才执行循环体。
do-while 语句 【例3.9】用迭代法求a的平方根近似值。求平方根的迭代公式为: 要求前后两个迭代根之差小于10- 5。 迭代法求解:a是已知正数,x 0是迭代初值,给x 0一个值,假定 x 0 = a/2;则用迭代公式依次计算: x1=(x0+a/x0)/2;x2=(x1+a/x1)/2;…… xk+1=(xk+a/xk)/2; 当|xk+1–xk|<ε(ε是一个较小的正数)时,迭代终止,取xk+1的值为a的平方根近似值。 ok
和迭代法对应的程序算法是递推算法: 1、输入a(a>0)及较小正数delta(也可用常变量); 2、x 0 = a/2; 用迭代公式算x1=(x0+a/x0)/2; 3、while(|x1–x0|>=delta) { x 0 = x 1;//把最近的值给x 0; x1=(x0+a/x0)/2; } //求xk+1时只需要知道xk的值,所以只需2个变量; 4、取x1的值为a的平方根近似值,输出。 2、3步骤很适合用do/while语句实现: x 1 = a/2; do{ x0=x1; x1=(x0+a/x0)/2; } while(|x1–x0|>=delta); 回到题目
#include<iostream.h> #include<math.h> void main( ){ float x0,x1,a; cout<<"输入一个正数:"; cin>>a; if(a<0)cout<<a<<"不能开平方!"<<endl; else { //有实数解的情况 x1=a/2; //x1用于保存结果 do{ x0=x1; x1=(x0+a/x0)/2; } while (fabs(x1-x0)>=1e-5); cout<< a<<"的平方根为:"<<x1<<endl; } } 在VC++平台上运行,输入2,3,4,5试一试是否正确 回到题目
do-while 语句 【例3.10】输入一段文本,统计文本的行数、单词数及字符数。假定单词之间以空格或跳格或换行符间隔,且文本开始没有空行。 算法分析: 1、逐个读入文本中的字符,直到读到一个输入结束符EOF为止。 2、如何算行数?行结束标志为读到字符′\n′; 3、如何算单词数?设一个变量isword,读到字符时isword=1,读到间隔符时isword=0;如果读到一个间隔符而此时isword值为1,则说明刚读完一个单词;(如果读到一个字符而此时isword值为0,则说明刚开始读一个单词;) 4、如何算字符数? ok
算法 1、设置变量line、word、ch分别代表行数、单词数、非分隔字符数,并初始化;设置变量isword来辅助统计单词数; 2、do{ 从键盘读入一个字符c; if ( c==’\n’) line++; if (是单词开头) word++; if (c不是分隔符) ch++; } while (c!= EOF ); 3、输出统计结果。 将下面的程序在VC++平台上运行,试一试是否正确
#include<iostream.h> void main( ) { char c; int line=0, word=0, ch=0; int isword=0; do { c=cin.get(); if (ch==′ \n′) line++; //遇换行符行数+1 if (c!=′ ′&&c!=′ \t′&&c!=′\n′){ //读到非间隔符 if(isword==0) word++;//在单词的起始处给单词数+1 ch++; //字符数加+1 isword=1; } else isword=0; //读到间隔符 } while(c!=EOF); cout<<”行数:”<<line<<endl; cout<<”单词数:”<<word<<endl; cout<<”字符数:”<<char<<endl;}
表达式2值为真? 否 是 求表达式3的值 图3.3 for语句的执行流程图 求表达式1的值 求表达式2的值 执行循环体语句 3.2.3 for 语句 for循环语句的格式为: for ( <表达式1>; <表达式2>; <表达式3> ) <循环体语句> ok
for语句、while语句、do/while语句实现相同的功能:1+2+3+4for语句、while语句、do/while语句实现相同的功能:1+2+3+4 int i=1,sum=0; //循环初始条件 do { sum+=i; i++;//修改循环条件 } while(i<=4); int i=1,sum=0; //循环初始条件 while(i<=4) { sum+=i; i++;//修改循环条件 } for( int i=1,sum=0; i<=4; i++ ) { sum+=i; } /*习惯上:表达式1:循环初始条件;表达式2:循环终止条件;表达式3:修改循环条件*/ ok
for 语句的应用 • for语句的几点说明: 1、是先判断型的,同while语句; 2、使用更为灵活: 三个表达式可以是任意表达式,因此他们就可以实现循环初始化、计算、修改循环条件等任务,而不一定非在循环体中进行;
for 语句的应用 【例3.11】 设计程序输出Fibonacii数列的前20项,要求每行输出5个数据。 Fibonacii数列定义如下: 算法分析:除了第0项和第1项外,每一项都是由类似方法产生,即前两项之和;所以求当前项时,只需要记住前两项;程序不需要为每一项设置专用变量; 属递推算法。
算法: 1、设置变量n表示第几项,变量 f 1和 f 2用来记住当前项f 3之前的两项 ;变量初始化n=0; 2、while (当前项不到第20项) { if (当前项是第0项) f 1=0; if (当前项是第1项) f 2=1; if (当前项是第2项或更高项)f 3=f 1+f 2; 按要求输出 f 3 ; f 1=f 2; f 2=f 3; //记住最近两项 当前项后移一位; }
【例3.11】 设计程序输出Fibonacii数列的前20项,要求每行输出2个数据。Fibonacii数列定义如下: 程序如下: //文件名:Ex3_11.cpp #include<iostream.h> #include<iomanip.h> void main(){ int fib0=0,fib1=1,fib2; cout<<setw(5)<<fib0<<setw(5)<<fib1 <<endl; for(int n=3;n<=20;n++){ fib2=fib0+fib1; cout<<setw(5)<<fib2; if(n%5==0) cout<<endl; //控制每行2个数据 fib0=fib1; fib1=fib2; } }
for 语句的应用 在VC++平台上运行 运行结果: 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181
for 语句的应用 【例3.12】 输入一个不超过5位的整数,将其反向后输出。例如输入247,变成742输出。 算法分析: 1、将整数的各个数位逐个位分开,用一个数组保存各个位的值,然后反向组成新的整数。 2、将整数各位数字分开的方法是,通过求余得到个位数,然后将整数缩小十倍,再求余,并重复上述过程,分别得到十位、百位……,直到整数的值变成0为止。 ok