📄 02章 控制结构.txt
字号:
Print "No grades were entered"
图2.8 用标记符控制重复解决全班平均成绩问题的伪代码算法
软件工程视点2.6
伪代码算法的细节足以将伪代码变为C++代码时,程序员即可停止自上而下逐步完善的过程,然后就可
方便地实现C++程序。
图2.9显示了C++程序和示例执行结果。尽管只输入整数成绩,但结果仍然可能产生带小数点
的平均成绩,即实数。int类型无法表示实数,程序中引入float数据类型处理带小数点的数(也称
为浮点数,floatingpoint number),并引入特殊的强制类型转换运算符(cast operator)处理平均值计
算。这些特性将在程序之后详细介绍。
1 // Fig. 2.9: fig02_09.cpp
2 // Class average program with sentinel-controlled repetition.
3 #include <iostream.h>
4 #include <iomanip.h>
5
6 int main()
7 {
8 int total, // sum of grades
9 gradeCounter, // number of grades entered
10 grade; // one grade
11 float average; // number with decimal point for average
12
13 // initialization phase
14 total = 0;
15 gradeCounter = 0;
16
17 // processing phase
18 cout << "Enter grade, -1 to end: ";
19 cin >> grade;
2O
21 while ( grade !=-1 ) {
22 total = total + grade;
23 gradeCounter = gradeCounter + 1;
24 cout << "Enter grade, -1 to end: ";
25 cin >> grade;
26 }
27
28 // termination phase
29 if ( gradeCounter != 0 } {
30 average - static_cast< float >( total ) / gradeCounter;
31 cout << "Class average is "<< setprecision{ 2 )
32 << setiosflags( ios::fixed | ios::showpoint )
33 << average << endl;
34 }
35 else
36 cout << "NO grades were entered" << endl;
37
38 return 0; // indicate program ended successfully
39 }
输出结果:
Enter grade, -1 to end: 75
Enter grade, -1 to end: 94
Enter grade, -1 to end: 97
Enter grade,-1 to end: 88
Enter grade, -1 to end: 70
Enter grade, -1 to end: 64
Enter grade, -1 to end: 83
Enter grade, -1 to end: 89
Enter grade, -1 to end: -1
Class average is 82.50
图2.9 用标记符控制重复解决全班平均成绩问题的C++程序和示例执行结果
注意图2.9中while循环中的复合语句。如果没有花括号,则循环体中的最后三条语句会放到循环以外,使计算机错误地理解如下代码:
while { grade ! = -1 )
total - total + grade;
gradeCounter = gradeCounter + 1;
cout << "Enter grade, -1 to end:";
cin >> grade;
如果用户输入的第一个成绩不是-l,则会造成无限循环。
注意下列语句:
cin >> grade;
前面用一个输出语句提示用户输入。
编程技巧2.10
提示用户进行每个键盘输入。提示应表示输入形式和任何特殊输入值(如用户终止循环时输入的标记值)。
编程技巧2.11
在标记控制循环中,提示请求输入数据项目时应显式指定标记值是什么值。
平均值并不一定总是整数值,而常常是包含小数的值,如7.2或-93.5。这些值称为浮点数,用数据类型float表示。变量average声明为数据类型float,以获得计算机结果中的小数。但total/gradeCounter的计算结果是整数,因为total和gradeCounter都是整数变量。两个整数相除是整除(integer division),小数部分丢失(即截尾,truncated)。由于先要进行计算,因此小数部分在将结果赋给average之前已经丢失。要用整数值进行浮点数计算,就要先生成用于计算的临时浮点数值。
C++提供了一元强制类型转换运算符(unary cast operator)。下列语句:
average = static cast< float >(total) / gradeCounter;
包括一元强制类型转换运算符static_cast<float>(),生成用于计算的临时浮点数值(total)。这样使用强制类型转换运算符称为显式类型转换(explicit conversion)。total中存放的值还是整数,而计算时则用浮点数值(total的临时float版本)除以整数gradcCounter。
c++编译器只能对操作数的数据类型一致的表达式求值。要保证操作数的数据类型一致,编译器对所选择的操作数进行提升(promotion)操作(也称为隐式类型转换,implicit conversion)。例如,在包含数据类型float和int的表达式中,int操作数提升为float。本例中,gradeCounter提升为float之后进行计算,将浮点数除法得到的结果赋给average。本章稍后将介绍所有标准数据类型及其提升顺序。任何数据类型都可用强制类型转换运算符,static_cast运算符由关键字statlc cast加尖括号(<>)中的数据类型名组成。强制类型转换运算符是个一元运算符(unary perator),即只有一个操作数的运算符。第1章曾介绍过二元算术运算符。C++也支持一元正(+)、负(-)运算符,程序员可以编写-7、+5之类的表达式。强制类型转换运算符从右向左结合,其优先级高于正(+)、负(-)运算符等其他一元运算符,该优先级高于运算符*、/和%,但低于括号的优先级。优先级表中用static_cast<type>()表示强制类型转换运算符。
图2.9中格式化功能将在第11章详细介绍,这里先做一简要介绍。下列输出语句中调用
setpreclslon(2):
cout<<"Class average is" << setprecision(2)
<< Setiosflaqs(iOS::fixed |iOS::showpoint)
<<averaqe<<endl;
表示float变量average打印小数点右边的位数为两位精度(precision),例如92.37,这称为参数化流操纵算子(parameterized stream manipulator)。使用这些调用的程序要包含下列预处理指令:
#include<iomanip.h>
注意endl是非参数化流操纵算子(nonparameterized stream manipulator),不需要iomanip.h头文件。如果不指定精度,则浮点数值通常输出六位精度(即默认精度,default precision),但稍后也会介绍一个例外。
上述语句中的流操纵算子setiosflags(ios::fixed | ios::showpoInt)设置两个输出格式选项ios::fixed和ios::showpoint。垂直条(1)分隔setiosflags调用中的多个选项(垂直条将在第16章详细介绍)。选项ios::fixed使浮点数值以浮点格式(而不是科学计数法,见第ll章)输出。即使数值为整数,ios::showpoInt选项也会强制打印小数点和尾部O,如88.OO。如果不用ios::showpoint选项,则C++将该整数显示为88,不打印小数点和尾部o。程序中使用上述格式时,将打印的值取整,表示小数点位数,但内存中的值保持不变。例如,数值87.945和67.543分别输出为87.95和67.54。
常见编程错误2.10
如莱在使用浮点敷时认为其精确地表示了敷值.则全得到不正确的蛄柬。浮点敷雇大多数计算机上都采用近似表示。
编程技巧2.12
不要比较浮点数值的相等和不等性,而要测试差值绝对值是否小于指定的值。
尽管浮点数算不总是100%精确,但其用途很广。例如,我们说正常体温98.6(华氏温度)时,并不需要精确地表示,如果温度计上显示98.6度.实际上可能是98.5999473210643度。这里显示98.6对大多数应用已经足够了。
另一种得到浮点数的方法是通过除法。10除以3得到3.333333……,是无限循环小敷。计算机只分配固定空间保存这种值,因此只能保存浮点值的近似值。
2.10 构造算法与自上而下逐步完善:实例研究3(嵌套控制结构)
下面介绍另一个问题。这里还是用伪代码和自上而下逐步完善的方法构造算法,然后编写相应的C++程序。我们介绍过按顺序堆叠的控制结构,就像小孩堆积木一样。这里显示C++中控制结构的另一种方法,称为嵌套控制结构。
考虑下列问题:
学校开了一门课,让学生参加房地产经纪人证书考试。去年,几个学生读完这门课并参加了证 书考试。学校想知道学生考试情况,请编写一个程序来总结这个结果。已经得到了10个学生 的名单,每个姓名后面写1时表示考试通过,写2时表示没有通过。
程序应分析考试结果,如下所示:
1.输入每个考试成绩(即l或2),每次程序请求另一个考试成绩时,在屏幕上显示消息“Enter result"。
2.计算每种类型的考试成绩数。
3.显示总成绩,表示及格人数和不及格人数。
4.如果超过8个学生及格,则打印消息“Raise tuition”。
认真分析上述问题后,我们做出下列结论:
1.程序要处理10个考试成绩,用计数器控制循环。
2.每个考试成绩为数字l或2,每次程序读取考试成绩时,程序要确定成绩是否为数字1或2。
我们的算法中测试1,如果不是l,则我们假设其为2(本章末尾的练习会考虑这个假设的结果)。
3,使用两个计数器,分别计算及格人数和不及格人数。
4.程序处理所有结果之后,要确定是否有超过8个学生及格。
下面进行自上而下逐步完善的过程。首先是上层的伪代码表示:
Analyze exam results and decide if tuition should be raised
我们再次强调,顶层是程序的完整表达,但通常要先进行几次完善之后才能将伪代码自然演变成C++程序。我们的第一步完善为:
Initialize variables
lnput the ten quiz qrades and COU~t passes and failures
Print a sugary Of the cxam results and decide if tuition should be raised
这里虽然有整个程序的完整表达式,但还需要进一步完善。我们要提供特定变量。要用两个计数器分别计算,用一个计数器控制循环过程,用一个变量保存用户输入。伪代码语句:
Initialize variables
可以细分如下:
Initialize passes to zero
lnitialize failules to zero
Inltiallze student counter to One
注意.这里只初始化计数器和总和。伪代码语句:
Input the ten quiz grades and count Passes and faiLures
要求循环输入每个考试成绩。我们事先知道共有10个成绩,因此可以用计数器控制循环。在循环中(即嵌套在循环中),用一个双项选择结构确定考试成绩为数字1或2,并递增相应的计数器。上述伪代码语句细化如下:
while student counter is less than or equal to ten
Input the next exam result
if the student passed
Add one to Passes
else
Add One to failures
Add one to student counter
注意这里用空行分开if/else控制结构,以提高程序可读性。伪代码语句:
Print a sugary Of the exam results and declde if tuition should be raised
可以细化如下:
Print the number of passes
Print the number of filuies
if more than eight students Passed
Priht "Raise tuition"
图2.10显示了完整的第2步完善结果。注意这里用空行分开while结构,以提高程序可读性。
Initlalize passes to zero
Init±a1ize failures to zero
lnitlallze student counter to one
while student counter is less than or equal to ten
Input the next exam result
if the student Passed
Add one to passes
else
Add one to failures
Add one to student counter
Priht the number of passes
Prirt the number of filures
if more than eight students passed
Print”Raise tuition'’
图2.10检查考试成绩的伪代码
这个伪代码语句已经足以转换为C++程序。图2.11显示了C++程序及示例的执行结果。注意,
我们利用C++的一个特性,可以在声明中进行变量初始化。循环程序可能在每次循环开头要求初始
化,这种初始化通常在赋值语句中进行。
1 // Fig. 2.11: fig02_ll.cpp
3 #include <iostream.h>
4
5 int main()
6 {
// initialize variables in declarations
int passes = 0, // number of passes
Passes = v; // number or passes
failures = 0, // number of failures
studentCounter = 1, // student counter
result; // oue exam result
// process 10 students; counter-controlled loop
while ( studentCounter <= 10 ) {
cout << "Enter result (1=pass,2=fail): ";
cin >> result;
if { result == 1 } // if/else nested in while
passes = passes + 1;
else
failures = failures + 1;
studentcounter = studentCounter + 1;
)
// termination phase
cout << "Failed" << failures << endl;
if ( passes > 8 )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -