C++程序设计第四章 基本语句.docx
《C++程序设计第四章 基本语句.docx》由会员分享,可在线阅读,更多相关《C++程序设计第四章 基本语句.docx(43页珍藏版)》请在冰豆网上搜索。
C++程序设计第四章基本语句
C++程序设计
第4章基本语句
一个C++程序可以由若干个源程序文件组成,一个源程序文件由编译预处理指令、自定义类型说明和函数组成,一个函数由若干条语句组成。
语句是组成程序的基本单位。
本章介绍C++基本语句的分类、程序结构,详细介绍其中的流程控制语句,包括选择语句、循环语句和跳转语句等。
4.1语句分类
程序是由语句构成的。
每一条语句都用一个分号结尾。
根据MSDNC++规范,C++语句可分为以下9大类。
4.1.1说明语句
程序中往往要引入新的名称,来表示某个类型的变量或命名常量,也可能表示用户自定义的某种类型,如结构类型、枚举类型、类等。
所有这些引入新名字的语句统称为说明语句(也称为声明语句)。
也可以将说明语句再详细划分为类型说明语句、变量或对象说明语句。
说明语句在程序执行过程中并没有对数据进行任何操作,仅是向编译器提供一些说明性信息。
说明语句可出现在函数中,也可以出现在函数之外。
变量说明语句就是最常见的说明语句。
例如:
inti=3;
这是一条说明语句。
变量i是前面不曾出现的变量。
该语句说明了一个新变量i,后面的代码就能对这个变量i进行操作。
在后面章节还将看到,说明语句可用于说明函数原型、结构、类等。
注意编程中的说明与定义的区别。
说明可以是笼统的,比如说明一个函数原型、一个类原型,说明可以不包含具体内容,比如不包含函数体,不包含类中的成员。
说明也可以是具体的,而定义必须是具体的,当我们说定义一个函数时,不仅要确定函数原型,也要确定函数体。
4.1.2表达式语句
在任一表达式后面加上一个分号就构成一条表达式语句。
表达式语句的作用是执行计算。
变量说明语句和表达式语句相结合,完成计算过程。
例如:
inti=3;//这是说明语句,而不是赋值语句
i=4;//这是赋值语句,是一种表达式语句
赋值语句、逗号语句、自增自减语句都是常见的表达式语句。
一个函数调用可作为一个操作数,是表达式的一部分,所以函数调用语句也是一种表达式语句。
后面章节将详细介绍。
4.1.3选择语句
程序中往往要根据某个条件来执行不同的代码。
选择语句就是先计算一个条件,如果为真就执行特定的一段代码,如果条件为假,还可以执行另一段代码。
有两种选择语句:
if-else和switch语句。
4.1.4循环语句
编程中还经常要重复执行一段代码,直到满足特定的停止条件为止。
有三种循环语句:
while、do-while和for语句。
4.1.5跳转语句
一般情况下,程序自上向下逐条语句执行,形成一条控制流。
但有时需要在一个函数中将控制流跳转到另一个地方开始执行,或者从一个函数中将控制流返回到调用方。
跳转语句有break、continue、return、goto语句。
C++扩充的throw语句用来引发异常,导致控制流跳转到异常处理语句,也属于一种跳转语句,将在后面章节详细介绍。
选择语句、循环语句和跳转语句也被统称为流程控制语句。
本章后面将详细介绍这三类语句。
4.1.6空语句
只由一个分号“;”构成的语句称为空语句,它不执行任何动作,主要用于满足特殊语法要求。
例如,循环语句中需要一条语句作为循环体,但你又不想做任何事情,就可用一个空语句。
本章后面将会用到空语句。
4.1.7复合语句
复合语句(也称块语句block或者分程序),是用一对花括号{}把一条或多条语句括起来构成的一条语句。
一条复合语句可包含多条语句,但在逻辑上被看作一条语句,可以出现在任何需要一条语句的地方。
花括号是一种标点符号,左花括号表示复合语句的开始,右花括号表示复合语句的结束。
复合语句不需要分号来结束。
复合语句主要用在流程控制语句中。
一个函数体的开始和结束也需要一对花括号{},但一般不能把一个函数体作为一条复合语句。
复合语句的花括号{}区间构成一个作用域,其中可以定义变量,将在下一章介绍。
显然,一条复合语句内部可嵌套多条复合语句,嵌套层次的数目没有明确限制。
4.1.8异常处理语句
在执行代码过程中,可能会引发某些类型的异常(用throw语句引发异常,或者因某种错误引发异常),就需要捕获这些异常类型并加以适当处理,这样的语句就是异常处理语句。
这是C++扩充的一种新语句,主要是try-catch语句,将在第15章详细介绍。
4.1.9标号语句
前面介绍的goto跳转语句需要对函数中的某一条语句添加标号,这样使goto语句能根据标号的名称跳转到该语句开始执行。
4.2程序的基本结构
结构化编程有3种基本结构:
顺序结构、选择结构和循环结构。
每一种基本结构都由若干模块组成,一个模块是一条复合语句的抽象。
一个函数就是一个模块,下一章介绍函数。
每一种结构都是一个模块,而且每个模块都能在内部嵌套更小的多个模块。
每个模块的设计应遵循以下原则:
●每个模块都应该是单入口、单出口。
●每个模块都有机会执行,即不能让一些模块永远都不能执行。
●模块中不能有死循环,即不能只进不出。
4.2.1顺序结构
图4.1顺序结构
顺序结构的程序是按从上到下的顺序依次执行各个模块。
如图4.1所示,一个模块中嵌套了两个模块,先执行A模块,再执行B模块。
单入口要求,若A模块执行,B模块就一定执行。
即不允许在两个模块之间插入另一个入口,只执行B模块而不执行A模块。
这样保证B模块执行之前,A模块一定执行完毕。
单出口要求,当退出顺序结构时,A模块和B模块都执行完毕。
如果在A模块中有一条goto语句,就可能导致B模块不能执行。
如果在B模块中有标号语句,就可能使外部goto语句能跳转进入B模块执行,而A模块不能执行。
这样就违背了单入口、单出口的原则。
在A模块和B模块中,并非禁止所有的跳转。
在任何模块中都允许执行以下两种跳转语句:
●return语句:
将当前函数的执行返回到调用方。
●throw语句:
引发异常到外层的异常捕获处理语句。
以上两种跳转语句都有确定的目标,而且一般情况下只有在满足特定条件时,才使用这两种跳转语句,而不是无条件跳转,所以经常会用到这两种跳转语句。
顺序结构在逻辑上比较简单,容易理解,往往用来描述高层的执行顺序。
例如,输入数据、计算结果、输出结果,三个模块按次序执行。
每个模块都可以递归地嵌套内部子模块,而每个模块都应该是三种基本结构之一。
4.2.2选择结构
选择结构是根据条件的不同结果做出不同的选择,从而执行不同的语句。
如图4.2所示。
先计算一个条件,如果为真就执行A模块,否则就执行B模块(或者什么都不执行,图右面一种情形)。
图4.2选择结构
单入口要求,如果A模块能执行,条件就一定为真。
不允许出现这样的情形,执行了A模块,而没有执行条件判断,或者条件判断不为真。
单出口要求,在退出选择结构时,要么A模块执行,要么B模块执行。
如果A模块中有一条goto语句跳转到B模块中,或者跳转到其它地方,就会破坏单入口单出口的原则。
两个模块都应有机会执行,即该条件不应恒为真或恒为假。
实现选择结构的语句有if-else语句和switch语句。
4.2.3循环结构
图4.3循环结构
循环结构就是按照一个条件对某些语句重复执行多次。
一个循环结构由一个条件和一个循环体(表示为模块A)构成。
如图4.3所示。
有左右两种情形:
情形1。
先判断条件,若为真就执行模块A,然后再转去判断条件,直到条件为假,退出循环结构。
这种情形对应while语句和for语句。
单入口要求,模块A执行,条件必须满足。
即不允许外部直接跳转到模块A开始执行。
单出口要求,当退出循环结构时,条件一定为假。
即不允许在退出循环结构时,条件没有判断或者条件为真的情形。
条件如果恒为真,而且模块A中没有跳转语句,就形成了死循环,不能退出循环结构。
反之,条件如果恒为假,模块A将没有机会执行。
这样都将违背模块设计的原则。
情形2。
先执行模块A,然后再判断条件,如果为真,就再执行模块A,直到条件为假,退出循环结构。
这种情形对应do-while语句。
模块A至少执行一次。
单入口要求,模块A再次执行,条件必须满足。
单出口要求,当退出循环结构时,条件一定为假。
条件如果恒为真,而且模块A中没有跳转语句,此时形成死循环,不能退出循环结构。
反之,条件如果恒为假,模块A将执行一次。
对于以上两种情形,如果在模块A中有goto语句跳转到结构之外,或者模块A中有标号语句使外部goto语句能跳转到模块A中执行,都会破坏单入口单出口原则。
循环结构是最强有力的结构。
可以让程序按条件自动执行,以得到预期结果。
同时循环结构也是最复杂的结构,它可能导致死循环、甚至系统崩溃。
循环结构可以嵌套,即A模块中可包含更小的循环结构或者其它结构。
循环结构中,模块A中允许执行除goto之外的其它跳转语句。
例如:
●break语句:
结束循环,退出当前循环结构。
●continue语句:
结束本轮循环,跳转到当前循环结构的条件判断,尝试下一轮循环。
●return语句:
当前函数的执行返回到调用方。
●throw语句:
引发异常到外层的异常处理语句。
顺序结构、选择结构和循环结构都是基本结构。
一个程序应该仅由这三种基本结构嵌套形成,不允许出现goto语句。
这是结构化编程的最基本要求。
结构化方法还强调“自顶向下,逐步求精”的设计过程。
就是先从大处着眼,根据需求先描述一个抽象的过程框架,然后再对其中每一步进行分解、细化,逐步得到编码。
另外,结构化设计还有“高内聚、低耦合”的设计原则,在后面介绍。
4.3选择语句
选择语句又称为分支语句,如果在程序中需要根据不同的条件来决定执行何种操作,就要使用选择结构。
C++语言提供了两种选择结构语句:
条件语句(if语句)和开关语句(switch语句)。
4.2.1条件语句
条件语句又称为if语句,根据一个条件来决定是否执行某条语句,或者从两条语句中选择一个执行。
1.if语句
if语句的语法格式为:
if(<表达式>)
<语句>
图4.4if语句的执行过程
其中,<表达式>的值作为条件,如果计算值为非0,即为逻辑真,就执行<语句>,否则就执行下一条语句。
执行过程如图4.4所示。
条件表达式可以是任何表达式,但常用的是关系表达式或逻辑表达式;作为循环体的语句可以是单条语句,也可以是一条复合语句,即用花括号括起来的多条语句。
例如:
inta=1,b=2,c=0;
if(a>b)
c=a-b;
cout<在该程序中,if语句会判断a>b这个表达式的运算结果是否为逻辑真,若是,则执行c=a-b语句。
如果结果为逻辑假,则会跳过语句c=a-b,转而执行下面的cout<所以输出的c值是1,而不是0。
当条件满足时所执行的一条语句可以是复合语句。
例如:
floatscore=0;
cout<<"PleaseEnterScore:
";
cin>>score;
if(score>100||score<0){
cout<"<return;
}
上面代码检查输入的分数,合理的分数假设为0到100之间。
如果输入的分数score不在合理范围之内,就要执行下面的复合语句中的2条语句。
为了使程序方便阅读,在书写条件语句时,满足条件所执行的语句都缩进一个tab位置,只有在语句很短时才与if条件写在同一行上。
2.if-else语句
if-else语句的语法格式为:
if(<表达式>)
<语句1>
else
<语句2>
图4.5if-else语句的执行过程
其中,<表达式>的值作为条件,如果计算为非0,即为逻辑真,就执行<语句1>,否则就执行<语句2>。
它们可以是一条语句,也可以是一条复合语句。
执行过程如图4.5所示。
例如:
intx;
cout<<"inputx=";
cin>>x;
if(x%2==0)
cout<"<else
cout<"<}
程序中条件语句判断x的值是奇数还是偶数。
若x的值能被2整除,输出x是偶数(even);否则输出x是奇数(odd)。
在进行条件判断时,往往使用C语句的一个潜规则:
“非0为真”。
例如上面if语句等价于下面写法:
if(x%2)//等价于x%2!
=0
cout<"<else
cout<"<上面直接把算术表达式作为条件,就是将所有非0值都看作逻辑真。
我们建议还是用关系表达式或逻辑表达式作为条件比较直接、清晰可读。
if-else是最常用的条件语句,用一个条件形成了两个分支。
为了使程序方便阅读,一般将“else”与“if”书写在同一列上,在垂直方向对齐,而且将语句1和语句2缩进一个tab位置。
3.if语句的嵌套
对于if-else语句,语句1或语句2又可以是一条if-else语句,这就形成嵌套的if语句。
例如:
if(表达式1)
<语句1>
else
if(表达式2)
<语句2>
else
<语句3>
图4.6一种嵌套的if-else语句形式
上面是一条if-else语句的结构,只是其中else部分嵌套了一条if-else语句。
这种结构的执行过程如图4.6所示。
这种结构用两个条件形成了三个分支。
多次使用这样的嵌套方式可用n个条件形成n+1个分支。
例4-1实现一个函数
,任意给定自变量x的值,求函数y的值。
#include
voidmain(void){
floatx,y;
cout<<"inputx=";
cin>>x;
if(x>0)//条件1
y=1;//语句1
else
if(x==0)//条件2
y=0;//语句2
else
y=-1;//语句3,此时,x<0
cout<<"x="<}
上面嵌套的if-else语句能实现函数y的功能。
下面语句也能实现相同的函数y功能:
y=1;//先假设x>0的情形
if(x<=0)
if(x==0)
y=0;//x==0的情形
else
y=-1;//此时,x<0
在书写if语句嵌套形式时要特别注意else与if的配对问题。
一定要确保else与if的对应关系不存在歧义性。
对于上面代码,可能将“else”与第一个if垂直对齐,但仍然没有改变程序的功能,如下所示:
if(x<=0)
if(x==0)
y=0;//x==0的情形
else
y=-1;//此时,x<0
C++中规定else与其前边最近的未配对的if相配。
因此上面代码仍然完成原先功能。
如果真的要使else与第一个if配对,就要用复合语句花括号{}来改变配对关系,如下所示:
y=1;//
if(x<=0){
if(x==0)
y=0;//x==0的情形
}else//else与第一个if配对
y=-1;//此时,x>0
这样仅添加了一对花括号就改变所实现的函数。
当x>0时,y=-1;当x<0时,y=1。
例4-2输入一个分数,输出相应的五分制成绩。
设90分以上为“A”,80~89分为“B”,70~79分为“C”,60~69分为“D”,60分以下为“E”。
#include
voidmain(void){
intiScore=0;
cout<<"PleaseEnterScore:
";
cin>>iScore;
if(iScore>=90)
cout<<"A";//>=90
elseif(iScore>=80)
cout<<"B";//80-89
elseif(iScore>=70)
cout<<"C";//70-79
elseif(iScore>=60)
cout<<"D";//60-69
else
cout<<"E";//<60
}
上面程序用4个条件划分了5个分支。
注意,在嵌套的if语句中,后一个if条件判断以前一个if条件不满足为前提,因此if条件的次序很重要。
4.2.2开关语句
开关语句也称为switch语句,或者多选择语句、或者多分支语句。
它可以根据给定的表达式,从多个分支语句序列中选择执行一个分支。
该语句的一般格式为:
switch(<表达式>){
case<常量表达式1>:
<语句序列1>
[break;]
case<常量表达式2>:
<语句序列2>
[break;]
...
case<常量表达式n〉:
<语句序列n>
[break;]
[default:
<语句序列n+1>]
}
其中,<表达式>的类型只能是整型,即char、short或int型。
<常量表达式>的类型也只能char、short或int型,通常是字面常量。
每个<语句序列>可由一条或多条语句组成,也可以是空。
每个case常量及其后的语句序列构成一个case子句。
一条switch语句可包含一个以上的case子句。
多个case子句的常量之间不应重复。
如果有break语句的话,它应该是语句序列中的最后一条语句。
其中break语句和最后的default子句都是任选的。
一条完整的switch语句涉及到4个关键字:
switch、case、break、default。
图4.7switch语句的执行过程
假设一条switch语句包含default子句,它的执行过程如图4.7所示。
先计算表达式的值,设为x,再依次与下面case常量进行比较。
若x与某个case常量相等,则以此为入口,转去执行该case子句的语句序列,一直执行下去,直到遇到break语句或switch语句结束的右花括号为止。
如果x与所有的case常量都不相等,而且有default子句,就执行default子句,然后结束switch语句的执行。
应该注意的是,每个case常量只是一个入口标号,而不能确定前一个case子句的终点。
所以如果要使每个case子句作为一个条件分支,就应将break语句作为每个case子句的最后一条语句,这样每次执行只能执行其中一个分支。
这是switch语句的习惯用法。
default子句可以放在switch语句中的任何位置,但习惯上作为最后一个子句,此时不需要再将break作为它的最后一条语句。
例4-3输入一个分数,输出相应的五分制成绩。
设90分以上为“A”,80~89分为“B”,70~79分为“C”,60~69分为“D”,60分以下为“E”。
#include
voidmain(){
floatscore=0;
cout<<"PleaseEnterScore:
";
cin>>score;
if(score>100||score<0){
cout<"<return;
}
switch(int(score/10)){
case10:
case9:
cout<<'A';
break;
case8:
cout<<'B';
break;
case7:
cout<<'C';
break;
case6:
cout<<'D';
break;
default:
cout<<'E';
}
}
上面程序允许输入浮点数成绩,而且假定合理的分数范围应该在0到100之间,并用if语句检查。
对表达式score/10进行强制类型转换为int,这是必要的。
第一个case子句的语句序列为空,这样就与第二个case子句公用一个入口。
当省略case后面的语句序列时,则可实现多个入口,执行同一个语句序列。
例4-4任意给定一个月份数,输出它属于哪个季节(12月、1月、2月是冬季;3月、4月、5月是春季;6月、7月、8月是夏季;9月、10月、11月是秋季)。
#include
voidmain(void){
intmonth;
cout<<"inputmonth=";
cin>>month;
switch(month){
case12:
case1:
case2:
cout<<"winter"<break;
case3:
case4:
case5:
cout<<"spring"<break;
case6:
case7:
case8:
cout<<"summer"<break;
case9:
case10:
case11:
cout<<"autumn"<break;
default:
cout<<"inputmontherror!
"<}
}
switch语句能实现的功能,用嵌套的if语句同样能实现。
在一些情况下用switch语句可能具有较好的可读性。
但switch语句在使用中有许多限制和注意点。
例如,条件表达式不能是浮点数,而且只能判断是否相等来确定入口,break容易忘记等。
4.3循环语句
编程中经常要反复执行同一语句序列,直至满足某个停止条件为止,这种重复执行过程称为循环。
C++提供了3种循环语句:
while、do-while()和for语句。
每一种循环都具有三要素:
1、初始条件,主要用于设置启动循环的一些变量;
2、终止条件,用于设置循环的出口点;
3、循环变量的修改,在循环过程中修改循环变量以达到终止条件,避免死循环。
4.3.1while语句
while语句的语法格式为:
while(<表达式>)
<循环体语句>
图4.8while语句的执行过程
其中,<表达式>确定了执行循环的条件,可以是任意合法表达式,但通常是一个关系表达式或逻辑表达式。
如果表达式的值为非0(即逻辑真),就执行<循环体语句>,然后再计算<表达式>再判断,直到<表达式>的值为0(即逻辑假)。
<循环体语句>是一条语句,也可以是一条复合语句。
图4.8描述了while语句的执行过程。
如果在一开始表达式的值为0,即为逻辑假,则直接退出循环,而不执行循环体语句。
下面代码计算sum=1+2+3+…+100。
当然你可以不用循环,只