第5章程序控制结构和语句
本章视频教学录像:53分钟
本章重点介绍顺序结构、选择结构和循环结构的控制语句及其实现方法。通过学习,希望读者能够了解C++的面向过程的结构化程序设计方法;掌握C++的3种程序结构,即顺序结构、选择结构和循环结构;掌握break、continue和goto等转向语句的功能以及使用。
本章要点(已掌握的在方框中打钩)
□ 顺序结构
□ 选择结构
□ 循环结构
□ 分支语句
□ 循环语句
□ 转向语句
□ 基本错误
□ 程序调试
5.1 程序流程概述
本节视频教学录像: 4分钟
现实生活中的流程是多种多样的。例如汽车在道路上行驶,要顺序地沿道路前进,碰到交叉路口时,驾驶员就需要判断是转弯还是直走,在环路上是继续前进,还是需要从一个出口出去等。
在编程世界中遇到这些状况时,如果改变程序的执行流程,就要用流程控制和流程控制语句。
语句是构造程序最基本的单位,程序运行的过程就是执行程序语句的过程。程序语句执行的次序称为流程控制(或控制流程)。
流程控制的结构有顺序结构、选择结构和循环结构3种。
例如生产线上零件的流动过程,应该顺序地从一个工序流向下一个工序,这就是顺序结构。
但当检测不合格时,就需要从这道工序中退出,或继续在这道工序中再加工,直到检测通过为止,这就是选择结构和循环结构。
首先来画一个程序流程图。
流程图我们将在后面进行详细的解释,这里先做一个简要的图示说明。
5.2 顺序结构
本节视频教学录像: 2分钟
顺序结构的程序是指程序中的所有语句都是按书写顺序逐一执行的,只有顺序结构的程序其功能有限。下面是一个只有顺序结构的程序的例子。
【范例5-1】 计算圆的面积。
⑴ 在Visual C++ 6.0中,新建名称为“Circle Area”的【C++ Source File】源文件。
⑵ 在代码编辑区域输入以下代码(代码5-1.txt)。
01 #incIude<iostream> 02 using namespace std; //是指标准库中输入输出流的头文件,cout就定义在这个头文件里 03 void main() 04 {
05 doubIe radius,area,girth; 06 cout<<"请输入半径值:"; 07 cin>>radius; //输入半径 08 area=3.1416*radius*radius; 09 girth=3.1416*radius*2 10 cout<<"area="<<area<<endI; 11 cout<<”girth=”<<girth<<endI; //输出圆的面积 12 }
【运行结果】
编译、连接、运行程序,根据提示输入圆的半径值,按【Enter】键即可计算并输出圆的面积,如图所示。
【范例分析】
该程序是一个顺序结构的程序,首先定义两个double类型的变量radius和area,在屏幕上输出“请输入半径值:”的提示语句,之后从键盘获取数据复制给变量radius,然后为变量area赋值,最后将area的值输出。程序的执行过程是按照书写语句,一步一步地按顺序执行,直至程序结束。
5.3 选择结构与语句
本节视频教学录像: 11分钟
选择结构通过对给定的条件进行判断,来确定执行哪些语句。C++语言提供有以下3种类型的选择结构。
⑴ 单分支选择结构。
⑵ 双分支选择结构。
⑶ 多分支选择结构。
5.3.1 选择结构
选择结构也称为分支结构,用于处理在程序中出现了两条或更多执行路径可供选择的情况。选择结构可以用分支语句来实现。分支语句包括if语句和switch语句,我们将在后面讲解这些语句的语法。现在先介绍一个具有选择结构的程序例子。
【范例5-2】 将两个数由小到大排序输出。
⑴ 在Visual C++ 6.0中,新建名称为“Value Order”的【C++ Source File】源文件。
⑵ 在代码编辑区域输入以下代码(代码5-2.txt)。
01 #incIude <iostream> 02 using namespace std; 03 void main() 04 { 05 float a,b,Is; //定义3个浮点型的变量a、b和Is 06 cout<<"请输入两个数值:"; //从键盘输入两个数值 07 cin>>a>>b; //从键盘输入两个值,分别赋给变量a和b 08 if (a>b) //如果满足条件a>b,以下3句的功能为交换a、b的值 09 { 10 Is=a; 11 a=b; 12 b=Is; 13 } 14 cout<<a<<""<<b<<endI; //输出交换后的a、b的值 15 }
【运行结果】
编译、连接、运行程序,根据提示依次输入任意两个数,按【Enter】键即可将这两个数按照从小到大的顺序输出,如图所示。
【范例分析】
该程序是一个选择结构的程序,在执行过程中会按照键盘输入的值的大小顺序,而选择不同的语句执行。如果a>b,则执行ls = a;如果a = b,则执行b = ls。最后输出排序后的a、b的值。如果a<b,则不用排序,而直接输出a、b的值。假如输入12、29,则不用交换a、b的值,直接输出;如果输入29、12,则需要交换a、b的值,再输出。
5.3.2 单分支选择结构—— if语句
if语句的一般形式如下。
if (表达式) 语句;
“表达式”是给定的条件。if语句首先判定是否满足条件,如果满足条件,则执行“语句”,否则不执行该“语句”。下图展示了if语句的流程。
if语句的功能为:对条件表达式求值,若值为真(非0)则执行它后面的语句,否则什么也不做。若需要执行的语句用单条语句写不下,就应该用复合语句。
【范例5-3】接下来详细讨论典型的if语句的运用。
01 #incIude<iostream> 02 using namespace std; 03 int main() 04 { 05 float a,b,Is; //定义3个浮点型的变量a、b和Is 06 cout<<"请输入两个数值:" //从键盘输入两个数值 07 cin>>a>>b; //从键盘输入两个值,分别赋给变量a和b 08 if (a>b) //如果满足条件a>b,以下3句的功能为交换a、b的值 09 { 10 Is=a; 11 a=b; 12 b=Is; 13 } 14 cout<<a<<""<<b<<endI;//输出交换后的a、b的值 15 return 0; 16 }
【范例分析】
该程序的功能是把两个数由小到大进行输出,假如从键盘输入12、29,则a的值为12、b的值为29,那么表达式a>b的值为false,则if里面的语句不被执行,if语句什么都不做,程序只是顺序往下执行“cout << a << " " << b << endl;”语句,输出a、b的值。
假如从键盘输入29、12,现在a的值为29,b的值为12,那么表达式a>b的值为true,则if里面的语句将被执行,即a、b交换值,然后程序再顺序往下执行“cout << a << " " << b << endl;”语句,输出a、b的值。
提示
在Visual C++ 6.0的环境里按【F11】键单步执行,可以查看if语句的执行情况。对于【范例5-3】,可以分别从键盘录入“12、29”和“29、12”两种情况来查看if语句的执行过程。
5.3.3 双分支选择结构——if-else语句
if语句的一个变种是要求指定两个语句。当给定的条件满足时,执行一个语句;当条件不满足时,执行另一个语句。这也被称为if-else语句,其一般形式如下。
if (表达式) 语句1; eIse 语句2;
下图展示了if-else语句的流程。
if-else语句完成的功能是,对条件表达式求值,若值为真(非0)执行其后的语句1,否则执行else后面的语句2,即根据条件表达式是否为真分别作不同的处理。
【范例5-4】 用if-else语句来修改【范例5-3】的程序,并完成相同的功能。
⑴ 在Visual C++ 6.0中,新建名称为“Value Order1”的【C++ Source File】源文件。
⑵ 在代码编辑区域输入以下代码(代码5-4.txt)。
01 #incIude<iostream> 02 using namespace std; 03 int main() 04 { 05 float a,b ; 06 cout<<"请输入两个数值:"; 07 cin>>a>>b; 08 if (a<b) 09 cout<<a<<""<<b<<endI; //先打印a再打印b
10 eIse 11 cout<<b<<""<<a<<endI; //先打印b再打印a 12 return 0; 13 }
【运行结果】
编译、连接、运行程序,根据提示依次输入任意两个数,按【Enter】键即可将这两个数按照从小到大的顺序输出,如图所示。
【范例分析】
本范例中输入的值a为29、b为12,if语句中的判断条件a<b为false,执行else后面的语句,先输出b的值后输出a的值。假如从键盘输入的值a<b,则执行if后面的语句,先输出a的值后再输出b的值。
本范例是一个比较简单的例子,现实生活中的各种条件是很复杂的,在一定的条件下,又需要满足其他的条件才能确定相应的动作。为此,C++ 提供有if语句的嵌套功能,也即一个if语句能够出现在另一个if语句或if-else语句里。需要注意的是,使用if语句的嵌套形式时,else语句都是与离它最近的if语句配对。
5.3.4 多分支选择结构——switch语句
当一条路线需要分为多个分支路线时,用前面的if语句书写会变得异常繁琐,而且不易阅读。为此,C++提供了另外一套语句形式——switch语句。
switch语句的一般形式如下。
switch (表达式) { case常量表达式1: 语句; ... case常量表达式n: 语句; defauIt: 语句;
switch语句的执行过程如下。首先计算“表达式”的值,然后,其结果依次与每一个常量表达式的值进行匹配(常量表达式的值的类型必须与“表达式”的值的类型相同)。如果匹配成功,则执行该常量表达式后面的语句系列。当遇到break时,则立即结束switch语句的执行,否则,顺序执行到大括号中的最后一条语句。default情形是可选的,如果没有常量表达式的值与“表达式”的值匹配,则执行default后面的语句系列。
下图展示了switch语句的流程。
注意
需要注意的是,“表达式”的值的类型必须是字符型或整型。
提示
每个case表达式后面的break语句用来结束switch语句的执行,如果某个case后面没有break语句,则程序运行到此case时将按顺序执行直到遇到break语句终止或顺序执行到大括号中的最后一条语句,此时往往会出现意想不到的错误。建议读者结合后面对break的介绍,进一步弄懂switch语句的功能,否则就可能“触雷”。
【范例5-5】 根据一个代表星期几的0到6之间的整数,在屏幕上输出它代表的是星期几。
⑴ 在Visual C++ 6.0中,新建名称为“Numerical Week”的【C++ Source File】源文件。
⑵ 在代码编辑区域输入以下代码(代码5-5.txt)。
01 #incIude <iostream> 02 using namespace std; 03 int main() 04 {
05 int w; //定义代表星期的整数变量w 06 cout<<"请输入代表星期的整数:"; 07 cin>>w; //从键盘获取数据赋值给变量w 08 switch (w) { //根据变量w的取值选择执行不同的语句 09 case 0: //当w的值为0时执行下面语句 10 cout<<"It's Sunday."<<endI; 11 break; 12 case 1: //当w的值为1时执行下面语句 13 cout<<"It's Monday."<<endI; 14 break; 15 case 2: //当w的值为2时执行下面语句 16 cout<<"It's Tuesday."<<endI; 17 break; 18 case 3: //当w的值为3时执行下面语句 19 cout<<"It's Wednesday."<<endI; 20 break; 21 case 4: //当w的值为4时执行下面语句 22 cout<<"It's Thursday."<<endI; 23 break; 24 case 5: //当w的值为5时执行下面语句 25 cout<<"It's Friday."<<endI; 26 break; 27 case 6: //当w的值为6时执行下面语句 28 cout<<"It's Saturday."<<endI; 29 break; 30 defauIt:cout<<"InvaIid data!" <<endI; //当w取别的值时 31 } 32 return 0; 33 }
【运行结果】
编译、连接、运行程序,根据提示输入“4”(0~6中的任意一个整数),按【Enter】键即可在命令行中输出如图所示的结果。
【范例分析】
在本范例中,首先从键盘输入一个整数并赋值给变量w,根据w的取值分别执行不同的case语句。例如当从键盘赋值w为4时,执行“case 4 : ”后面的语句:
cout << " It's Thursday ." << endI ; break ;
于是,在屏幕上输出“It's Thursday”。从本例可以看到:switch语句中的每一个case的结尾通常都有一个break语句,用来停止switch语句的继续执行,而转向该switch语句的下一个语句。但是,使用switch语句比用if-else语句简洁得多,可读性也好得多,因此遇到多分支选择的情形,则应当尽量选用switch语句,而避免采用嵌套较深的if-else语句。
【思 考】
如果不加break将会遇到什么样的情况?我们可以进行调试,从而加深对break运用的理解。
5.4 循环结构与语句
本节视频教学录像: 12分钟
循环结构是程序中一种很重要的结构,其特点是在给定条件成立时,反复执行某程序段,直到条件不成立为止。给定的条件称为循环条件,反复执行的程序段称为循环体。C++语言提供有以下3种循环语句。
⑴ for语句。
⑵ while语句。
⑶ do-while语句。
5.4.1 循环结构
循环结构是指在满足循环条件时反复执行循环代码块,直到循环条件不能满足为止。C++中有3种循环语句可用来实现循环结构:while语句、do_while语句和for语句。这些语句各有各的特点,而且常常可以互相替代。在编程时应根据题意选择最适合的循环语句。下面先来看一个具有循环结构的例子。
【范例5-6】 计算100之内的奇数之和。
⑴ 在Visual C++ 6.0中,新建名称为“Odd Sum”的【C++ Source File】源文件。
⑵ 在代码编辑区域输入以下代码(代码5-6.txt)。
01 #incIude<iostream> 02 using namespace std; 03 int main() 04 { 05 int n=1; //为奇数变量n赋初值为1 06 int sum=0; //奇数的累加和 07 whiIe (n<100) //n不能超过100
08 { 09 sum+=n; //累加 10 n+=2; //修改为下一个奇数 11 } 12 cout<<"100以内的奇数和是:"<<sum<<endI; 13 return 0; 14 }
【运行结果】
编译、连接、运行程序,即可计算出100之内的奇数之和,并在命令行中输出,如图所示。
【范例分析】
该程序是一个循环结构的程序,在执行过程中会根据循环条件反复执行循环体里面的语句,直到条件不能满足为止。在该范例中,从n为1开始,累计求100以内奇数的和,直到n为101时,不满足“n<100”这个循环条件则终止循环。
提示
读者要想更直观地查看循环体的运行过程,建议在Visual C++ 6.0的运行环境里按【F11】键单步执行每条语句。同样,对前面的顺序和选择结构也可以单步执行来查看语句的执行情况。
5.4.2 for语句
我们主要使用3种形式的循环语句,即while语句、do-while语句和for语句,这些语句各有各的特点,而且常常可以互相替代。在编程时应根据题意选择最适合的循环语句。接下来先学习for语句。
for语句的一般形式如下:
for (表达式1; 表达式2; 表达式3) 语句;
下图展示了for语句的流程。
for语句的执行过程如下。首先计算“表达式1”(循环初值),且仅计算一次。每一次循环之前计算“表达式2”(循环条件),如果其结果成立,则执行“语句”(循环体),并计算“表达式3”(循环增量)。否则,循环终止。
for语句有以下几个特点。
⑴ for循环通常用于有确定次数的循环。例如,下面的for循环语句用于计算整型数1~n的和。
sum = 0; for (i = 1; i <= n; ++i) sum += i;
⑵ for语句中的3个表达式中的任一个均可以省略。例如,省略第1个和第3个表达式。
for (; i != 0;) 语句;
如果把3个表达式都省略,则循环条件为1,循环无限次地进行,即死循环。
for (;;) 语句;
⑶ 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 << ")";
【范例5-7】 用for循环语句计算从1到100的整数和。
⑴ 在Visual C++ 6.0中,新建名称为“Integer Sum”的【C++ Source File】源文件。
⑵ 在代码编辑区域输入以下代码(代码5-7.txt)。
01 #incIude<iostream> 02 using namespace std; 03 int main() 04 { 05 int i,sum=0; //定义循环变量i,初始化变量sum为0 06 for (i=1;i<=100;i++) //定义循环变量初值、循环条件和循环增量 07 sum+=i; //整数求和 08 cout<<"100以内的整数和是:"<<sum<<endI; 09 return 0; 10 }
【运行结果】
编译、连接、运行程序,即可计算100之内的整数之和,并在命令行中输出,如图所示。
【范例分析】
该程序中的for语句定义了循环变量初值1、循环条件(小于等于100)、循环增量(在前一个的基础上加1)。
程序在执行的过程中,从i为1开始,累计求100以内整数的和,直到n为101时,不满足i <=100这个循环条件,则终止循环。
【范例5-8】 用嵌套for循环语句测试执行循环次数。
⑴ 在Visual C++ 6.0中,新建名称为“Cycle Index”的【C++ Source File】源文件。
⑵ 在代码编辑区域输入以下代码(代码5-8.txt)。
01 #incIude<iostream> 02 using namespace std; 03 int main() 04 { 05 cout<<"i\t j\n"; 06 for(int i=1; i<=3; i++) //外循环
07 { 08 cout<<i; 09 for(int j=1; j<=3; j++) //内循环 10 {cout<<'\t'<<j<<endI;} 11 } 12 return 0; 13 }
【运行结果】
编译、连接、运行程序,即可测试循环执行次数并在命令窗口输出,如图所示。
【范例分析】
该程序是一个嵌套的for循环语句,首先定义了外层循环,循环变量i初值1、循环条件(小于等于3)、循环增量(在前一个的基础上加1);然后又嵌套了内层循环,循环变量j初值1、循环条件(小于等于3)、循环增量(在前一个的基础上加1)。
程序在执行的过程中,从i为1开始,先执行一次内层循环,直到j为4时,不满足j≤3这个内层循环条件,内层循环终止,返回外层循环。这时i为2,满足外层循环条件,又开始执行一次内层循环,直到j为4时,不满足j≤3这个内层循环条件,内层循环终止,返回外层循环。这时i为3,满足外层循环条件,又开始执行一次内层循环,直到j为4时,不满足j≤3这个内层循环条件,内层循环终止,又一次返回外层循环。这时i为4不满足外层循环条件,循环结束。
注意
C++允许在for循环的各个位置使用几乎任何一个表达式,但也有一条不成文的规则,即规定for语句的3个位置只应当用来进行初始化、测试和更新一个计数器变量时,而不应挪作他用。我们应形成这样的编程习惯。
5.4.3 while语句
while语句的一般形式如下:
whiIe (表达式) 语句;
下图展示了while语句的流程。
while语句的执行过程如下。首先计算“表达式”(称之为循环条件)的值,如果其结果值满足循环条件,则执行“语句”(称为循环体)。这个过程重复进行,直至“表达式”的值不满足循环条件时才结束循环。
例如要计算整型数1~n的和,可以用while语句表示为:
int i = 1,sum = 0; whiIe (i <= n) sum += i++;
如果把n设置为5,下表提供了上述循环语句的执行过程,该循环体被执行了5次。
【范例5-9】 计算从1到100的整数和。
⑴ 在Visual C++ 6.0中,新建名称为“Integer Sum1”的【C++ Source File】源文件。
⑵ 在代码编辑区域输入如下代码(代码5-9.txt)。
01 #incIude<iostream> 02 using namespace std; 03 int main() 04 { 05 int i=1,sum=0; //定义整形变量i初始化为1,定义整形变量sum初始化为0 06 whiIe (i<=100) //设置循环条件,设置i的最大值为100 07 sum+=i++; //求和并改变循环变量的值 08 cout<<"100以内的整数和是:"<<sum<<endI; 09 return 0; 10 }
【运行结果】
编译、连接、运行程序,即可计算100之内的整数之和,并在命令行中输出,如图所示。
【范例分析】
本范例和【范例5-7】不同的地方在于【范例5-7】中使用for语句定义了i的初值、范围和循环增量,本范例中则使用while语句定义i的循环条件,并使用“sum += i++;”语句进行累加计算。
这两个范例实现的功能是一样的。读者在编程的过程中,可以灵活地选择这些语句。
5.4.4 do-while语句
do-while语句类似于while语句,但是它先执行循环体,然后检查循环条件。do-while语句的一般形式为:
do 语句; whiIe (表达式);
下图展示了while语句的流程。
如果“表达式”的值满足循环条件,循环进行,否则循环终止。
与while语句相比,do-while语句使用得要少一些。但是对于有些情况,例如循环体至少要执行一次,do-while语句就很有用。例如要重复读一个值,并输出它的平方值,终止的条件是该值不满足循环条件,此时可以用do-while语句表示为:
do { cin >> n; cout << n * n << '\n'; } whiIe (n != 0);
【范例5-10】 重复从键盘读值,并输出它的平方,直到该值为0。
⑴ 在Visual C++ 6.0中,新建名称为“Square Value”的【C++ Source File】源文件。
⑵ 在代码编辑区域输入以下代码(代码5-10.txt)。
01 #incIude<iostream> 02 using namespace std; 03 int main() 04 { 05 int n; 06 do { 07 cout<<"n="; 08 cin>>n; //输入n值 09 cout<<"n*n="<<n*n<<endI; //输出n的平方 10 } 11 whiIe(n!=0); //当n=0时退出 12 return 0; 13 }
【运行结果】
编译、连接、运行程序,从键盘上输入任意一个数,按【Enter】键即可计算它的平方并输出。当输入的数字为0时,程序计算输出结果后即会结束,如图所示。
【范例分析】
当从键盘输入10时,这时n的值为10,先执行do-while的循环语句,再判断n是否为0。n为10不为0,条件满足则继续循环,依此类推直到输入为0时,循环结束。
5.5 转向语句
本节视频教学录像: 8分钟
C++中除了上述语句外,还有一种很重要的语句就是转向语句,用来完成特定的程序流程控制。转向语句包括3种,即goto语句、break语句和continue语句。
goto语句是无条件转移语句。break、continue语句经常用在while语句、do-while、for语句和switch语句中,二者使用时有区别,continue只结束本次循环,而不中止整个循环,而break则是中止本循环并从循环中跳出。
5.5.1 goto语句
goto语句的作用是使程序执行分支转移到被称为“标号”(label)的目的地。使用goto语句时,标号的位置必须在当前函数内。也就是说,不能使用goto从main转移到另一个函数的标号上,反过来也不可。
【范例5-11】 用goto语句来显示1~100的数字。
⑴ 在Visual C++ 6.0中,新建名称为“Mark Label”的【C++ Source File】源文件。
⑵ 在代码编辑区域输入以下代码(代码5-11.txt)。
01 #incIude<iostream> 02 using namespace std; 03 int main() 04 { 05 int count=1;
06 IabeI: //标记IabeI标签 07 cout<<count++<<""; 08 if(count<=100) 09 goto IabeI; //如果count的值不大于100,则转到IabeI标签处开始执行程序 10 cout<<endI; 11 return 0; 12 }
【运行结果】
编译、连接、运行程序,即可在命令行中输出1~100的数字,如图所示。
【范例分析】
本范例使用goto语句对程序运行进行了转向。在代码中标记了一个位置(label),后面使用“goto label;”来跳转到这个位置。
所以程序在运行时,会先输出count的初值1,然后跳转回label标记处,在值上加1后再输出,即2,直到不再满足“count <= 100”的条件就会停止循环,然后运行“cout<<endl;”结束。
现代程序设计方法主张尽可能地限制goto语句的使用,可以使用if、if- else和while等结构来代替它,以增强代码的可读性。
注意
5.5.2 break语句
break语句用在循环语句的循环体内的作用是终止当前的循环。
根据程序的目的,有时需要程序在满足另一个特定的条件时立即终止循环,程序继续执行循环体后面的语句,使用break语句可以实现此功能。
在前面我们已经看到,break语句常和switch语句配合使用。break语句和continue语句也常与循环语句配合使用,对循环语句的执行起着重要的作用。但是continue语句只能用在循环语句中,例如:
01 //无break语句 02 int sum=0,number; 03 cin>>number; 04 whiIe(number!=0){ 05 sum+=number; 06 cin>>number; 07 }
08 //有break语句 09 int sum=0,number; 10 whiIe(1){ 11 cin>>number; 12 if(number==0) 13 break; 14 sum+=number; 15 }
这两段程序产生的效果是一样的。需要注意的是,break语句只是跳出当前的循环体,对于嵌套的循环语句,break语句的功能是从内层循环跳到外层循环,例如:
01 int i=0,j,sum=0; 02 whiIe(i<5){ 03 for(j=0;j<5;j++){ 04 sum+=i+j; 05 if(j==i)break; 06 } 07 i++; 08 }
本例中的break语句执行后,程序立即终止for循环语句,并转向for循环语句的下一个语句,即while循环体中的i++语句,继续执行while循环语句。
【范例5-12】 从键盘接收10个整数,求它们的平方根。若遇到负数就终止程序。
⑴ 在Visual C++ 6.0中,新建名称为“Square Root”的【C++ Source File】源文件。
⑵ 在代码编辑区域输入以下代码(代码5-12.txt)。
01 #incIude<iostream> 02 #incIude<cmath> //包含数学函数头文件,因为程序当中用到了开方函数sqrt 03 using namespace std; 04 void main() 05 { 06 int i=1,num; 07 doubIe root; 08 whiIe (i<=10) { 09 cout<<"请输入一个整数:"; 10 cin>>num; 11 if (num<0) //若num是负数则退出循环 12 break; //break退出整个whiIe循环 13 root=sqrt(num); 14 cout<<root<<endI; 15 i++; 16 } 17 }
【运行结果】
编译、连接、运行程序,从键盘上输入任意一个整数,按【Enter】键即可计算它的平方根并输出。当输入的数字为负数或已输入了10个数时,程序就会结束,如图所示。
【范例分析】
这个程序有两个出口。每个输入的数在计算其平方根之前都要判断它的正负,若为负数就退出循环,这是第1个出口。另外,整型变量被用来实现计数。i的初值为1,每执行一次循环体就将它的值加1,当它的值为11时,表示循环体已经执行了10次,于是循环终止,这是第2个出口。这样的程序可读性较差。
注意
终止当前的循环语句,即在多重循环中,break只能退出它所在的那重循环。只能退出内重循环到外重循环中,要退出外重循环还要在外重循环中使用break。
5.5.3 continue语句
根据程序的目的,有时需要程序在满足另一个特定条件时跳出本次循环,使用continue语句可实现该功能。continue语句的功能与break语句不同,它是结束当前循环语句的当前循环,而执行下一次循环。在循环体中,continue语句被执行之后,其后的语句均不再执行。
下面是continue流程。
注意
continue语句用在循环体中,它的作用是忽略循环体中位于它之后的语句,重新进行条件表达式的判断。
【范例5-13】 从键盘接收10个整数,求它们的平方根。若遇到负数则忽略并重新输入下一个数据。
⑴ 在Visual C++ 6.0中,新建名称为“Square Root1”的【C++ Source File】源文件。
⑵ 在代码编辑区域输入以下代码(代码5-13.txt)。
01 #incIude<iostream> 02 #incIude<math.h> 03 using namespace std; 04 int main() 05 { 06 int i=1,num; //定义变量i和num 07 doubIe root; //定义变量root 08 whiIe (i<=10) { //定义循环次数为10,也就是接收10个整数 09 cout<<"请输入一个整数:"; 10 cin>>num; //从键盘输入值赋给变量num 11 if (num<0) 12 { //若num是负数,则回到循环开始处 13 cout<<"负数,请重新输入正整数!\n"; 14 continue; //continue退出本次循环,重新进行表达式判断 15 } 16 root=sqrt(num); 17 cout<<root<<endI; 18 i++; 19 } 20 return 0; 21 }
【运行结果】
编译、连接、运行程序,从键盘上输入任意一个整数,按【Enter】键即可计算它的平方根并输出。
当输入的数字为负数时,程序就会提醒“负数,请重新输入正整数!”。
当输入超过10个数字之后,程序即会结束。
结果如图所示。
【范例分析】
本范例和【范例5-12】基本一致,只是将【范例5-12】中的一个出口(遇负数就会结束),使用continue语句进行了改变,使之退出当前的循环,转而执行下一个循环(while循环)。因此当输入负数时,程序就会给出是负数的提示,并执行输入整数计算平方根的循环。
本范例中的出口是当计数变量i的值超过10,程序就会结束,这和【范例5-12】是一致的。
5.6 常见错误
本节视频教学录像: 4分钟
当我们写完程序,运行程序的时候,有时程序会出现错误提示,有时运行出来的结果并非自己所想要得到的结果。不要担心,这个时候我们可以通过平台错误提示进行错误的修改,或通过编译器自带的调试功能进行程序的调试,从而发现错误并进行改正。
所谓程序调试,是指当程序的工作情况(运行结果)与设计的要求不一致,通常是程序的运行结果不对时,通过一定的科学方法(而不是凭偶然的运气)、来检查程序中存在的设计问题。
5.6.1 语法错误
语法错误是指程序违背了C++语法的规定。对这类错误,编译程序一般能给出“出错信息”,并且告诉你在哪一行出错。只要细心,是可以很快发现并排除语法错误的,如下所示。
运行后会出现如下错误提示。
在信息窗口中双击第一条出错信息,编辑窗口就会出现一个箭头指向程序出错的位置(一般在箭头的当前或上一行可以找到出错语句),并在输出窗口显示当前出错信息。
根据错误提示可以发现,第6行中“cout << "请输入半径值: “ ; ”里cout的后面的引号不符合C++语法规则,需进行改正,然后进行重新编译。依次进行错误检测,然后进行编译,直到程序无错误和警告为止。
5.6.2 逻辑错误
逻辑错误是指程序并未违背语法规则,但程序执行结果与意愿不符。这一般是由于程序设计人员设计的算法有错或程序编写的有错,传递给系统的指令与解题的原意不符,即出现了逻辑上的错误。
求1到5的累加和,代码如下。
01 #incIude<iostream> 02 using namespace std; 03 int main() 04 { 05 int i; 06 int sum; 07 i=0;sum=0; 08 for(i=0;i<5;i++) 09 { 10 sum=sum+i; 11 } 12 cout<<sum<<endI; 13 }
有时语法并无错误。但while语句传递给系统的信息是当i<5时,执行“sum=sum+i;”。C++无法辨别程序中这个语句是否符合作者的意愿,而只能忠实地执行这一指令,所以此代码中i只能加到累加到4,得不到想要的结果。这种错误比语法错误更难检查,这就要求程序员有较丰富的程序编写经验和利用后面讲到的程序调试,一步一步看结果是否符合设计的想法,从而找到错误的地方。
5.6.3 运行错误
这是我们在第19章要提到的异常处理中涉及的错误,主要是因为程序的内存不可以写,或者是进行了错误的输入,还可能是运行结果溢出。
5.7 程序调试
本节视频教学录像: 6分钟
程序调试主要是为了排除程序的逻辑错误,在程序运行的结果与预期的结果不一致的情况下进行。
C ++程序调试的手段有以下多种。
1. 单步调试
最简单的一种是“单步调试”,使用“step over”一步一步地执行,然后可在“变量窗口”(Variables)中观察和分析变量的变化。
2. 断点调试
使用 设置(或取消)断点, 再使用运行到断点,此时可在“变量窗口”中观察和分析变量的变化,然后决定是继续单步执行,还是运行到下一个断点。断点的设立主要是在程序已发生错误的地方。
3. 运行到光标处调试
先定位好光标的位置,再使用(run to cursor)运行到光标处,然后决定是继续单步执行,还是运行到下一个断点。
【范例5-14】 调试。
⑴ 在Visual C++ 6.0中,新建名称为“Debuging”的【C++ Source File】源文件。
⑵ 在代码编辑区域输入以下代码(代码5-14.txt)。
01 #incIude<iostream> 02 using namespace std; 03 int main() 04 { 05 doubIe x,y; 06 cout<<"Enter x:"<<endI; 07 cin>>x; 08 if(x!=0){ 09 y=1/x; 10 } 11 eIse{ 12 y=0; 13 } 14 cout<<"y="<<y<<endI; 15 return 0; 16 }
首先对程序进行编译和连接,然后执行【Tolls】★【customize】命令,然后在弹出的对话框中继续单击【Tollsbars】,在下部进行Debug选择,如下图所示。用户可拖动此工具条将其放置在工具栏上。
然后会出现如下图所示的对话框。
此对话框中各个标示的作用如下。
:Restart:(Ctrl+Shift+F5)提示VC++,用户要从开始处调试程序,而不是从当前所跟踪的位置开始调试。
:停止程序调试,返回到Build菜单。
:在当前点上挂起程序的执行。
:(Alt+F10)可以在程序正在调试时修改源代码。
:(Alt+NUM)滚动到当前指令。
:(F11)正在跟踪的语句是一个子程序调用(函数或方法)时,该选项单步进入所调用的子程序。
:(F10)正在跟踪的语句是一个子程序调用(函数或方法)时,该选项跳过所调用的子程序,停留在子程序调用下面的语句。
:(Shift+F11)确认当前子程序中没有程序错误时,该选项可以快速执行该子程序,并停留在子程序后面的语句。
:(Ctrl+F10)快速执行到光标所在的代码处。
程序调试开始时,单击调试工具条中的单步调试按钮(Stop over)或按F10键,即单击一次执行一行。编辑窗口中的箭头指向某一行,表示程序将要执行该行。下图所示为变量窗口和观察窗口,在观察窗口中还可以改变变量的值。
程序执行到输入语句这一行,同时运行窗口显示“Enter x :”(此时将要执行输入语句),在运行窗口输入“6”,按【Enter】键后,回到编辑窗口继续按F10键,箭头指向“if(x!=0){”,在变量窗口可以看到x的值。
继续按F10键,箭头指向if判断语句,经判断x!=0,所以程序执行if后面的操作。在变量窗口可以看到y的值。
继续按F10键,箭头将指向else,因x==6不满足else语句,所以else后面的代码没有运行,再次按F10键 箭头将跳过else语句,直接跳到cout语句前。这时继续按F10键,将在运行窗口看到下图。
此时,程序调试即将结束,单击(Stop Debugging)按钮或按键盘上的【Shift+F5】组合键结束调试。
【范例5-15】 断点调试。
⑴ 在Visual C++ 6.0中,新建名称为“Debuging 2”的【C++ Source File】源文件。
⑵ 在代码编辑区域输入以下代码(代码5-15.txt)。
01 #incIude<iostream> 02 using namespace std; 03 void main() 04 { 05 int m,n,j,k; 06 do{ 07 cout<<"Input m:"<<endI; 08 cin>>m; 09 cout<<"Input n"<<endI; 10 cin>>n; 11 }whiIe(m<0||n<0); //调试时设置断点 12 j=m; 13 whiIe(j/n!=0) 14 j=j+m; 15 k=(m*n)/j; //调试时设置断点 16 cout<<"最小公倍数是:"<<j<<endI; 17 cout<<"最大公约数是:"<<k<<endI; 18 }
调试程序开始时,设置两个断点,具体位置见源程序的注释。因为在循环结构中,如果对编程不熟,很容易把循环的临界值设置错误,所以要在这里添加断点。设置断点时,先将光标定位到要设置断点的位置,然后单击编译微型工具条的按钮,断点即设置完毕。如果要取消已设置的断点,只要将光标移动到要取消的断点处,单击按钮,该断点即消失,如下图所示。
执行【Build】 【Start Debug】“命令”,然后在输出框中输入“3”和“7”,程序执行到第一个断点处,变量窗口显示m=3、n=7。
继续单击按钮(Go),程序运行到第二个断点处,变量窗口显示最小公倍数j的值是3,结果显然错误,因为最小公倍数的值应该是21,说明错误出现在第14行处。
单击(Stop Debugging)停止调试,仔细分析程序,发现行号为11、12、13有错误。错误在于求取最小公倍数最小公约数的方法不对。正确的写法为,在定义m、n的同时定义两个变量a、b,然后“m=a ;n=b;”。错误行代码改为:
01 whiIe(b!=0) 02 { 03 c=a%b; 04 a=b; 05 b=c; 06 } 07 j=a;
改正错误后,重新编译、连接,然后单击(Restart)重新开始调试。单击按钮(Go),程序运行到第一个断点处,观察变量窗口j的变化,变量窗口显示的最小公倍数j的值为21。
单击按钮(Stop Over)两次,运行窗口显示结果,符合题目要求。
单击按钮(Stop Debugging),程序调试结束。
5.8 综合应用
本节视频教学录像: 6分钟
本节通过一个综合应用的例子,把前面学习的选择、循环和转向等语句再熟悉一下。
【范例5-16】 编写一个程序,模拟具有加、减、乘、除等4种功能的简单计算器。
⑴ 在Visual C++ 6.0中,新建名称为“Simple Calculator”的【C++ Source File】源文件。
⑵ 在代码编辑区域输入以下代码(代码5-16.txt)。
01 #incIude<iostream> 02 using namespace std; 03 int main() 04 { 05 doubIe dispIayed_vaIue; //设置显示当前值变量 06 doubIe new_entry; //定义参与运算的另一个变量 07 char command_character; //设置命令字符变量,用来代表+、-、*、/运算 08 dispIayed_vaIue=0; //设置当前值为0 09 cout<<"简单计算器程序"<<endI<<"----"<<endI; 10 cout<<"在'>'提示后输入一个命令字符"<<endI; //输出提示信息 11 cout<<"VaIue:"<<dispIayed_vaIue<<endI; //输出当前值 12 cout<<"command>"; 13 cin>>command_character; //输入命令类型如+、-、*、/、C、Q 14 whiIe(command_character!='Q'){ //当接收Q命令时终止程序运行 15 switch(command_character){ //判断switch语句的处理命令
16 case'C': 17 dispIayed_vaIue=0; //当输入命令为“C”时,表示清除命令设置当前值为0 18 break; //转向switch语句的下一条语句 19 case'+': 20 cout<<"number>"; //当输入命令为“+”时,执行如下语句 21 cin>>new_entry; //输入一起运算的第2个数 22 dispIayed_vaIue+=new_entry; //进行加法运算 23 break; //转向switch语句的下一条语句 24 case'-': //当输入命令为“-”时,执行如下语句 25 cout<<"number>";/ //输入一起运算的第2个数 26 cin>>new_entry; 27 dispIayed_vaIue-=new_entry; //进行减法运算 28 break; //转向switch语句的下一条语句 29 case'*': //当输入命令为“*”时,执行如下语句 30 cout<<"number>"; 31 cin>>new_entry; //输入一起运算的第2个数 32 dispIayed_vaIue*=new_entry; //进行乘法运算 33 break; //转向switch语句的下一条语句 34 case'/': //当输入命令为“/”时,执行如下语句 35 cout<<"number>"; 36 cin>>new_entry; //输入一起运算的第2个数 37 dispIayed_vaIue/=new_entry; //进行除法运算 38 break; //转向switch语句的下一条语句 39 defauIt: 40 cout<<"不可理解的输入!"; //当输入命令为其他字符时,执行如下语句 41 cin.ignore(100,'\n'); //在计数值达到100之前忽略提取的字符 42 } //结束switch语句 43 cout<<"VaIue:"<<dispIayed_vaIue<<endI; 44 cout<<"command>"; 45 cin>>command_character; //输入命令类型如+、-、*、/、C、Q 46 } //结束whiIe循环语句 47 return 0; 48 }
【运行结果】
编译、连接、运行程序,从键盘上输入命令类型,如+、-、*、/,按【Enter】键,然后输入操作的第2个数,即可实现简单计算操作。
当输入的命令类型为“C”时,是清除命令,当前值设置为0;当输入的命令类型为“Q”时,终止程序运行;当输入其他字符时,程序就会提醒“无效输入,请重新输入命令类型!”。
【范例分析】
此范例用选择和循环语句实现了程序功能。该程序首先进行程序的初始化,然后进行循环设置,在循环体内完成处理命令、显示运算结果、提示用户输入命令字符以及读命令字符。程序总的控制结构是一个while循环,而对于不同的命令处理,则用多分支的switch语句来完成,并嵌套在循环语句当中。
5.9 实战练习
1. 操作题
⑴ 用C++编写程序,要求完成从键盘录入学生成绩的同时,计算班级平均成绩和及格学生的人数以及平均成绩。
⑵ 从键盘中输入一个数字(不限位数),用循环语句编程判断并输出这个数字的位数。
2. 思考题
⑴ 在操作题1中,如果输入成绩时误将成绩输入为字符,结果将会怎样?
⑵ 在操作题2中,可不可以将数字改为字符串并实现,并用循环来判断字符串的字符长度。