概述
5.1
【出题思路】
理解空语句的形式和用法。
【解答】
空语句是最简单的语句,空语句由一个单独的分号构成。如果在程序的某个地方,语法上需要一条语句但是逻辑上不需要,此时应该使用空语句,空语句什么也不做。
一种常见的情况是,当循环的全部工作在条件部分就可以完成时,我们通常会用到空语句。使用空语句时最好加上注释,从而令代码的阅读者知道这条语句是有意省略内容的。
5.2
【出题思路】
理解块的形式和用法。
【解答】
块是指用花括号括起来的语句和声明的序列,也称为复合语句。一个块就是一个作用域,在块中引入的名字只能在块内部以及嵌套在块中的子块里访问。如果在程序的某个地方,语法上需要一条语句,但是逻辑上需要多条语句,此时应该使用块。块不需要以分号结束。
例如,循环体必须是一条语句,但是我们通常需要在循环体内做很多事情,此时就应该把多条语句用花括号括起来,从而把语句序列转换成块。
5.3
【出题思路】
使用连续的逗号运算符可以把多条语句合并为一条,这一点与块的作用类似。但是一般来说,直接使用块在程序的可读性上更有优势。
【解答】
原文的 while 循环使用了块,其形式是:
while (val <= 10) {
sum += val;
++val;
}
利用逗号运算符改写之后的形式如下所示:
while (val <= 10)
sum += val, ++val;
很明显,改写之后的代码不够清晰,可读性降低了。
5.4
【出题思路】
我们可以在 if、switch、while 和 for 语句的控制结构内定义变量。定义在控制结构当中的变量只在相应语句的内部可见,一旦语句结束,变量也就超出其作用范围了。如果其他代码需要访问控制变量,则变量必须定义在语句的外部。
【解答】
(a)是非法的,它的原意是希望在 while 语句的控制结构当中定义一个 string::iterator 类型的变量 iter,然后判断 iter 是否到达了 s 的末尾,只要还没有到达末尾就执行循环体的内容。但是该式把变量的定义和关系判断混合在了一起,如果要使用 iter 与其他值比较,必须首先为 iter 赋初值。修改后的程序应该是:
string::iterator iter = s.begin();
while (iter != s.end()) {
++iter;
/* ... */
}
(b)是非法的,变量 status 定义在 while 循环控制结构的内部,其作用域仅限于 while 循环。if 语句已经位于 while 循环的作用域之外,status 在 if 语句内是一个未命名的无效变量。要想在 if 语句中继续使用 status,需要把它定义在 while 循环之前。修改后的程序应该是:
bool status;
while (status = find(word)) { /* ... */}
if (!status) { /* ... */ }
5.5
【出题思路】
练习 if-else 语句的基本语法结构。
【解答】
满足题意的程序如下所示:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
int grade;
cout << "请输入您的成绩:" << endl;
cin >> grade;
if (grade < 0 || grade > 100) {
cout << "该成绩不合法" << endl;
return -1;
}
if (grade == 100) { // 处理满分的情况
cout << "等级成绩是:" << "A++" << endl;
return 0;
}
const vector<string> scores = {"F", "D", "C", "B", "A"};
string lettergrade;
// 如果成绩不合格,不需要考虑添加加号减号的问题
if (grade < 60)
lettergrade = scores[0];
else {
lettergrade = scores[(grade - 50) / 10]; // 获得字母形式的成绩
if (grade != 100) // 只要不是 A++,就考虑添加加号减号
if (grade % 10 > 7)
lettergrade += '+'; // 末尾是 8 或者 9 的成绩添加一个加号
else if (grade % 10 < 3)
lettergrade += '-'; // 末尾是 0、1 或者 2 的成绩添加一个减号
}
cout << "等级成绩是:" << lettergrade << endl;
return 0;
}
// 测试样例一,运行结果
请输入您的成绩:
100
等级成绩是:A++
Process finished with exit code 0
// 测试样例二,运行结果
请输入您的成绩:
80
等级成绩是:B-
Process finished with exit code 0
// 测试样例三,运行结果
请输入您的成绩:
101
该成绩不合法
Process finished with exit code 255
// 测试样例四,运行结果
请输入您的成绩:
87
等级成绩是:B
Process finished with exit code 0
5.6
【出题思路】
条件运算符可以实现与 if-else 语句类似的功能,当有嵌套的条件表达式时,注意其满足右结合律。
C++ 运算符优先级
【解答】
改写后的程序如下所示:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
int grade;
cout << "请输入您的成绩:" << endl;
cin >> grade;
if (grade < 0 || grade > 100) {
cout << "该成绩不合法" << endl;
return -1;
}
if (grade == 100) { // 处理满分的情况
cout << "等级成绩是:" << "A++" << endl;
return 0;
}
const vector<string> scores = {"F", "D", "C", "B", "A"};
string lettergrade;
// 如果成绩不合格,不需要考虑添加加号减号的问题
if (grade < 60)
lettergrade = scores[0];
else {
lettergrade = scores[(grade - 50) / 10]; // 获得字母形式的成绩
if (grade != 100) // 只要不是 A++,就考虑添加加号减号
// 末尾是 8 或者 9 的成绩添加一个加号
// 末尾是 0、1 或者 2 的成绩添加一个减号
// 注意运算符的优先级和结合性,不确定的可以加括号
lettergrade += grade % 10 > 7 ? "+" : grade % 10 < 3 ? "-" : "";
}
cout << "等级成绩是:" << lettergrade << endl;
return 0;
}
// 测试样例一,运行结果
请输入您的成绩:
100
等级成绩是:A++
Process finished with exit code 0
// 测试样例二,运行结果
请输入您的成绩:
80
等级成绩是:B-
Process finished with exit code 0
// 测试样例三,运行结果
请输入您的成绩:
101
该成绩不合法
Process finished with exit code 255
// 测试样例四,运行结果
请输入您的成绩:
87
等级成绩是:B
Process finished with exit code 0
5.7
【出题思路】
理解 if 语句的语法规则。
【解答】
(a)if 语句的循环体应该是一条语句,需要以分号结束,程序修改为:
if (ival1 != ival2)
ival1 = ival2;
else ival1 = ival2 = 0;
(b)if 语句的循环体只能是一条语句,本题从代码的缩进格式上来说需要做两件事,一是修改 minval 的值,二是重置 occurs 的值,所以必须把这两条语句放在一个块里。
程序修改为:
if (ival < minval) {
minval = ival;
occurs = 1;
}
(c)ival 是定义在 if 语句中的变量,其作用域仅限于第一个 if 语句,要想在第二个 if 语句中也使用它,就必须把它定义在两个 if 语句的外部。程序修改为:
int val;
if (ival = get_value())
cout << "ival = " << ival << endl;
if (!val)
cout << "ival = 0n";
(d)程序的原意是判断 ival 的值是否是 0,原题使用赋值运算符的结果是把 0 赋给了 ival,然后检验 ival 的值,这样使得条件永远不会满足。程序修改为:
if (ival == 0)
ival = get_value();
5.8
【出题思路】
理解悬垂 else 的定义,以及 C++ 是如何处理悬垂 else 的。
【解答】
悬垂 else 是指程序中的 if 分支多于 else 分支时,如何为 else 寻找与之匹配的 if 分支的问题。
C++ 规定,else 与离它最近的尚未匹配的 if 匹配,从而消除了二义性。
5.9
【出题思路】
if 语句和 switch 语句是分支语句的两种形式,一般来说可以相互转化。
【解答】
满足题意的程序如下所示:
#include <iostream>
using namespace std;
int main() {
unsigned int vowelCnt = 0;
char ch;
cout << "请输入一段文本:" << endl;
while (cin >> ch && ch != 'Q') {
if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u')
++vowelCnt;
}
cout << "您输入的文本中共有 " << vowelCnt << " 个元音字母" << endl;
return 0;
}
// 运行结果
请输入一段文本:
AaOoEeIiUu Q
您输入的文本中共有 5 个元音字母
Process finished with exit code 0
5.10
【出题思路】
要实现本题的要求,只需更新 switch 语句的 case 分支即可。
【解答】
本题的关键是在适当位置添加 break;
语句。其中,表示同一字母大小写的 case 标签之间不写 break;
,因为它们要做的操作是一样的;而不同字母的 case 分支最后要写上 break;
。满足题意的程序如下所示:
#include <iostream>
using namespace std;
int main() {
unsigned int aCnt = 0, eCnt = 0, iCnt = 0, oCnt = 0, uCnt = 0;
char ch;
cout << "请输入一段文本:" << endl;
while (cin >> ch && ch != 'Q') {
switch (ch) {
case 'a':
case 'A':
++aCnt;
break;
case 'e':
case 'E':
++eCnt;
break;
case 'i':
case 'I':
++iCnt;
break;
case 'o':
case 'O':
++oCnt;
break;
case 'u':
case 'U':
++uCnt;
break;
}
}
cout << "元音字母 a 的数量是:" << aCnt << endl;
cout << "元音字母 e 的数量是:" << eCnt << endl;
cout << "元音字母 i 的数量是:" << iCnt << endl;
cout << "元音字母 o 的数量是:" << oCnt << endl;
cout << "元音字母 u 的数量是:" << uCnt << endl;
return 0;
}
// 运行结果
请输入一段文本:
AaOoEeIiUu Q
元音字母 a 的数量是:2
元音字母 e 的数量是:2
元音字母 i 的数量是:2
元音字母 o 的数量是:2
元音字母 u 的数量是:2
Process finished with exit code 0
5.11
【出题思路】
继续扩充 case 标签即可。其中,读入字符的语句应该使用 cin.get(ch)
,而不能使用 >>
,因为后者会忽略本题所要统计的特殊符号。
#include <iostream>
using namespace std;
int main() {
unsigned int aCnt = 0, eCnt = 0, iCnt = 0, oCnt = 0, uCnt = 0;
unsigned int spaceCnt = 0, tabCnt = 0, newlineCnt = 0;
char ch;
cout << "请输入一段文本:" << endl;
while (cin.get(ch) && ch != 'Q') {
switch (ch) {
case 'a':
case 'A':
++aCnt;
break;
case 'e':
case 'E':
++eCnt;
break;
case 'i':
case 'I':
++iCnt;
break;
case 'o':
case 'O':
++oCnt;
break;
case 'u':
case 'U':
++uCnt;
break;
case ' ':
++spaceCnt;
break;
case 't':
++tabCnt;
break;
case 'n':
++newlineCnt;
break;
}
}
cout << "元音字母 a 的数量是:" << aCnt << endl;
cout << "元音字母 e 的数量是:" << eCnt << endl;
cout << "元音字母 i 的数量是:" << iCnt << endl;
cout << "元音字母 o 的数量是:" << oCnt << endl;
cout << "元音字母 u 的数量是:" << uCnt << endl;
cout << "空格的数量是:" << spaceCnt << endl;
cout << "制表符的数量是:" << tabCnt << endl;
cout << "换行符的数量是:" << newlineCnt << endl;
return 0;
}
// 运行结果
请输入一段文本:
AaOoEeIiUu
fksjkfl
Q
元音字母 a 的数量是:2
元音字母 e 的数量是:2
元音字母 i 的数量是:2
元音字母 o 的数量是:2
元音字母 u 的数量是:2
空格的数量是:1
制表符的数量是:3
换行符的数量是:3
Process finished with exit code 0
5.12
【出题思路】
为了统计字符序列的情况,必须记录前一个字符的内容。
【解答】
我们的设定是一个字符只会被统计一次。如果用户输入的序列是 xxxxxfflxxx,则统计结果是 ff:1 次、fl:0 次、fi:0 次。如果用户输入的序列是 xxxxxfiffffflxxx,则统计结果是 ff:2 次、fl:1 次、fi:1 次。
cin.ignore():C++跳过(忽略)指定字符
满足题意的程序如下:
#include <iostream>
using namespace std;
int main() {
unsigned int ffCnt = 0, flCnt = 0, fiCnt = 0;
char ch, prech = '