📄 02章 控制结构.txt
字号:
常见编程错误2.2
忽略复合语句中的一个或两个花括号可能在程序中生成语法错误或逻辑错误。
编程技巧2.5
总是在if/else结构(和任何控制结构)中放上花括号,可以避免不慎疏忽,特别是后面要在if或else语句中增加语句时。错误(fatal logic error)使程序失败和提前终止,而非致命逻辑错误(nonfatal logic error)则让程序继续执行,只是产生错误结果。
软件工程视点2.3
复合语句可以放在程序中出现单句语句的任何地方,也可以根本不放语句,即放上空语句。空语句就是在正常语句出现的地方放一个分号(;)。
常见编程错误2.3
在if结构条件后面放上分号会造成单项选择if结构的逻辑错误和双项选择if结构的语法错误 (如果if部分包含实际语句体)。
编程技巧2.6
有些程序员喜欢在花括号中输入各个语句之前输入复合语句的开始花括号和结束花括号。这样可以避免丢失一个或两个花括号。
本节介绍了复合语句的符号。复合语句可以包含声明(例如,和main程序体中一样),如果这 ,则这个复合语句称为块(block)。块中的声明通常放在块中任何操作语句之前,但也可以和操作语句相混和。第3章将介绍块的用法,在此之前,读者应避免使用块(除了作为main程序体)。
2.7 while重复结构
重复结构(repetition strucure)使程序 员可以指定一定条件下可以重复的操作。下列伪代码语句:
While there are more items on my shopping list
Purchase next item and cross it off my list
描述购物过程中发生的重复。条件"there are more ltems on my shopping list"(购物清单中还有更多
项目)可真可假。如果条件为true.则执行操作"Purchase next item and cross it off my list"(购买下
一个项目并将其从清单中划去)。如果条件仍然为true,则这个操作重复执行。while重复结构中的
语句构成while的结构体,该结构体可以是单句或复合句。最终,条件会变为false(购买清单中最
后一个项目并将其从清单中划去时),这时重复终止,执行重复结构之后的第一条伪代码语句。
常见编程错误2.4
如果不在while结构中提供最终导致while条件变为false的操作,则合造成无限循环(infinite loop)错误,重复结构永不终止。
常见编程错误2.5
将关键字while的拼写变为“While”是个语法错误,因为C++是区分大小写的语言。while、if和else等所有C++保留关键字只能包含小写字母。
作为实际while的例子,假设程序要寻找2的第一个大于1000的指数值。假设整数变量prod-
uct初始化为2,执行下列while重复结构之后,product即会包含所要值:
int product = 2;
while ( product <= 1000 )
product = 2 * product;
图2.5的流程图演示了对应于上述while重复结构的while结构控制流程。注意,流程图(除了
小圆框和流程之外)也只能包含表示所需操作的矩形框和表示所需判断的菱形框。这是我们强调的
操作/判断编程模型。程序员的任务就是根据算法需要用堆栈和嵌套两种方法组合其他几种控制结
构,然后在这些框中填入算法所要的操作和判断,从而生成程序。流程图中清楚地显示了重复。流
程从矩形出发,回到判断框中测试,直到判断为false。然后退出while结构,控制转入程序中下一
条语句。
进入while结构时,product的值为2。变量product重复乘以2,连续取值4、8、16、32、64、
128、256、512和1024。当product变为1024时,while结构条件product<=1000变为false,因此终
止重复,product的最后值为1024。程序继续执行while后面的下一条语句。
2.8 构造算法:实例研究1(计数器控制重复)
要演示如何开发算法,我们要解决几个全班平均成绩的问题。考虑下列问题:
班里有10个学生参加测验,可以提供考试成绩(0到100的整数值),以确定全班平均成绩。
全班平均成绩等于全班成绩总和除以班里人数。计算机上解决这个问题的算法是辅人每人的成绩,进行平均计算,然后打印结果。
下面用伪代码列出要执行的操作,指定这些操作执行的顺序。我们用计数器控制重复(counter-conttrolled repetition)一次一个地输人每人的成绩。这种方法用计数器(counter)变量控制一组语句执行的次数。本例中,计数器超过10时,停止重复。本节介绍伪代码算法(如图2.6)和对应程序(如图2.7)。下节介绍如何开发这个伪代码算法。计数器控制重复通常称为确定重复(definiterepetition),因为循环执行之前,已知重复次数。
注意算法中引用了总数(total)和计数器。总数变量用于累计一系列数值的和。计数器变量用于计数,这里计算输人的成绩数。存放总数的变量通常应先初始化为0之后再在程序中使用,否则总和会包括总数的内存地址中存放的原有数值。
Set total to zero
Set grade counter to one
While grade counter is less than or equal to ten
Input the next grade
Add the grade i.to the total
Add one to the grade counter
Set the class average to the total divided by ten
Print the class average
图2.6 用计数器控制重复解决全班平均成绩问题的伪代码算法
1 // Fig. 2.7: fig0207.cpp
2 // Class average program with counter-controlled repetition
3 #include <iostream.h>
4
5 int main()
6{
7 int total, // sum of grades
8 gradeCounter, // number of grades entered
9 grade, // one grade
10 average; // average of grades
11
12 // initialization phase
13 total = 0; // clear total
14 gradeCounter = 1; // prepare to loop
15
16 // processing phase
17 while ( gradeCounter <= 10 ) { // loop 10 times
18 cout << "Enter grade: "; // prompt for input
19 cin >> grade; // input grade
20 total = total + grade; // add grade to total
21 gradeCounter = gradeCounter + 1; // increment counter
22 }
23
24 // termination phase
25 average - total / 10; // integer division
26 cout << "Class average is "<< average << endl;
27
28 return 0; // indicate program ended successfully
29 }
输出结果:
Enter grade: 98
Enter grade: 76
Enter grade: 71
Enter grade: 87
Enter grade: 83
Enter grade: 90
Enter grade: 57
Enter grade: 79
Enter grade: 82
Enter grade: 94
Class average is 81
图2.7 用计数器控制重复解决全班平均成绩问题的C++程序和示例输出
根据使用情况,计数器变量通常应先初始化为0或1(下面会分别举例说明)。未初始化变量会包含垃圾值“garbage”value),也称为未定义值(undefined value),为该变量保存内存地址中最后存放的值。
常见编程错误2.6
如果不初始化计数器和总和变量,则程序的结果可能不正确.这是一种逻辑错误。
编程技巧2.7
一定要初始化计数器和总和变量。
编程技巧2.8
每个变量在单独一行中声明。
注意程序中的平均计算产生一个整数结果。实际上,本例中的成绩总和是817,除以10时应得到81.7,是个带小数点的数,下节将介绍如何处理这种值(称为浮点数)。
常见编程错误2.7
在计数器控制循环中,由于循环计数器(每人循环加1时)比最大合法值多1(例如,从1算到10时为11).因此在循环之后用计数器值进行计算通常会出现差1的错误。
图2.7中,如果第21行用gradeCounter而不是10进行计算,则这个程序的输出显示数值74。
2.9 构造算法与自上而下逐步完善:实例研究2(标记控制重复)
下面将全班平均成绩问题一般化,考虑如下问题:
开发一个计算全班平均成绩的程序,在每次程序运行时处理任意个成绩数。
在第一个全班平均成绩例子中,成绩个数(10)是事先预置的。而本例中,则不知道要输入多少个成绩,程序要处理任意个成绩数。程序怎么确定何时停止输入成绩呢?何时计算和打印全班平均成绩呢?
一种办法是用一个特殊值作为标记值(sentinelvalue),也称信号值(signalvalue)、哑值(dummy value)或标志值(flag value),表示数据输入结束(“end of data entry”)用户输入成绩,直到输入所有合法成绩。然后用户输入一个标记值,表示最后一个成绩已经输入。标记控制重复(sentinel-controlled repetition)也称为不确定重复(indefinite repetition),因为执行循环之前无法事先知道重复次数。
显然,标记值不能与可接受的输入值混淆起来。由于考试成绩通常是非负整数,因此可以用-1作标记值。这样,全班平均成绩程序可以处理95、96、75、74、89和-l之类的输人流。程序计算并打印成绩95、96、75、74和89的全班平均成绩(不计入-1,因为它是标记值)。
常见编程错误2.8
将选择的标记值与可接受的输入值混淆时会造成逻辑错误。
我们用自上而下逐步完善(top-down,stepwise refinement)的方法开发计算全班平均成绩的程序,这是开发结构化程序的重要方法。我们首先生成上层伪代码表示:
Determine the class avcraqe for the quiz
上层伪代码只是一个语句,表示程序的总体功能。这样.上层等于是程序的完整表达式。但上层通常无法提供编写C++程序所需的足够细节。因此要开始完善过程。我们将上层伪代码分解为一系列的小任务,按其需要完成的顺序列出。这个结果就是下列第一步完善(first,refinement):
Initialize variables
Input,sum,and count the quiz grades
Calculate and print the class average
这里只用了顺序结构,所有步骤按顺序逐步执行。
软件工程视点2.4
上层伪代码及每一步完善都是算法的完整定义,只是详细程度不同而已。
软件工程视点2.5
许多程序可以在逻辑上分为三个阶段:初初化阶段将程序变量初始化,处理阶段输入数据值和相应调整程序变量,结束阶段计算和打印最后结果。
上述“软件工程视点”通常是自上而下过程第一步完善的全部工作。要进行下一步完善(即第二步完善,second refinement),我们要指定特定变量,要取得数字的动态和以及计算机处理的数值个数,用一个变量接收每个输入的成绩值,一个变量保存计算平均值。下列伪代码语句:
Initialize variables
可以细化成:
Initialize total to zero
Initialize counter to zero
注意,只有total和counter变量要先初始化再使用,average和grade变量(分别计算平均值和用户输入)不需要初始化.因为它们的值会在计算或输入时重定义。
下列伪代码语句:
Input, sum, and count the quiz grades
需要用重复结构(即循环)连续输入每个成绩。由于我们事先不知道要处理多少个成绩,因此使用标记控制重复。用户一次一项地输入合法成绩。输入最后一个合法成绩后,用户输人标记值。程序在每个成绩输入之后测试其是否为标记值.如果用户输入标记值,则顺序循环终止。上述伪代码语句的第二步完善如下:
Input the first grade (possibly the sentinel)
While the user has not as yet entered the sentinel
Add this grade into the running total
Add one to the grade counter
Input the next grade (possibly the sentinel)
注意,在这个伪代码中,我们没有在while结构体中使用花括号,只是在while下面将这些语句缩排表示它们属于while。伪代码只是非正式的程序开发辅助工具。
下列伪代码语句可以完善如下:
If the counter is not equal to zero
Set the average to the total divided by the counter
Print the average
else
Print "No grades were entered"
注意我们这里要测试除数为0的可能性,这是个致命逻辑错误,如果没有发现,则会使程序失败(通常称为爆炸或崩溃)。图2.8显示了全班平均成绩问题第二步完善的完整伪代码语句。
常见编程错误2.9
除数为0是个致命逻辑错误。
编程技巧2.9
进行除法时,要测试除数为0的可能性,并在程序中进行相应处理(如打印一个错误消息).而不是让致
命逻辑错误发生。
图2.6和图2.8的伪代码中增加了一些空行,使伪代码更易读。空行将程序分成不同阶段。
图2.8所示的伪代码算法解决更一般的全班平均成绩问题,这个算法只进行了第二步完善,还
需要进一步完善。
Initialize total to zero
Initialize counter to zero
Input the first grade (possibly the sentinel)
While the user has not as yet entered the sentinel
Add this grade into the running total
Add one to the grade counter
Input the next grade (possibly the sentinel)
if the counter is not rqual to zero
Set the average to the total divided by the counter
Print the average
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -