在我自学C++过程中,我选择了C++Primer这本书,并对部分代码习题进行了求解以及运行结果。接下来几个月我将为大家定时按章节更新习题答案与运行结果,运行环境(Visual Studio Code,windows 11):
C++ Primer (第五版)习题答案总目录:
https://blog.csdn.net/weixin_48467622/article/details/136418131?spm=1001.2014.3001.5501
目录
5.3 使用逗号运算符重写1.4.1节的 while 循环,使它不再需要块,观察改写之后的代码可读性提高了还是降低了。
5.5 写一段自己的程序,使用if else 语句实现把数字转换为字母成绩的要求。
5.6 改写上一题的程序,使用条件运算符代替if else语句。
5.8 什么是“悬垂else”?C++语言是如何处理else子句的?
5.9 编写一段程序,使用一系列if语句统计从cin读入的文本中有多少元音字母。
5.11 修改统计元音字母的程序,使其也能统计空格、制表符、和换行符的数量。
5.12 修改统计元音字母的程序,使其能统计含以下两个字符的字符序列的数量: ff、fl和fi。
5.13 下面显示的每个程序都含有一个常见的编码错误,指出错误在哪里,然后修改它们。
5.19 编写一段程序,使用do while 循环重复地执行下述任务:首先提示用户输入两个string对象,然后挑出较短的那个并输出它。
5.21 修改5.5.1节练习题的程序,使其找到的重复单词必须以大写字母开头。
5.22 本节的最后一个例子跳回到 begin,其实使用循环能更好的完成该任务,重写这段代码,注意不再使用goto语句。
5.23 编写一段程序,从标准输入读取两个整数,输出第一个数除以第二个数的结果。
5.24 修改你的程序,使得当第二个数是0时抛出异常。先不要设定catch子句,运行程序并真的为除数输入0,看看会发生什么?
5.25 修改上一题的程序,使用try语句块去捕获异常。catch子句应该为用户输出一条提示信息,询问其是否输入新数并重新执行try语句块的内容。
5.1 什么是空语句?什么时候会用到空语句?
最简单的语句是空语句,空语句只有一个单独的分号:
;//null statement
如果在程序的某个地方,语法上需要一条语句但逻辑上不需要,此时应该使用空语句。
5.3 使用逗号运算符重写1.4.1节的 while 循环,使它不再需要块,观察改写之后的代码可读性提高了还是降低了。
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
int sum = 0, val = 1;
while (val < 11)
sum += val, val++;
cout << sum << endl;
return 0;
}
5.4 说明下列例子的含义,如果存在问题,试着修改它。
(a) while (string::iterator iter != s.end()) { /* . . . */ }
(b) while (bool status = find(word)) { /* . . . */ }
if (!status) { /* . . . */ }
a) 这个循环试图用迭代器遍历string,但是变量的定义应该放在循环的外面,目前每次循环都会重新定义一个变量,明显是错误的。
std::string::iterator iter = s.begin();
while (iter != s.end()) { /* . . . */ }
b) 这个循环的 while 和 if 是两个独立的语句,if 语句中无法访问 status 变量,正确的做法是应该将 if 语句包含在 while 里面。
bool status;
while (status = find(word)) {/* ... */}
if (!status) {/* ... */}
5.5 写一段自己的程序,使用if else 语句实现把数字转换为字母成绩的要求。
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
vector<string> scores = { "F","D","C","B","A" ,"A++" };
int grade = 0;
string lgrade;
while (cin >> grade)
{
if (grade < 60)
{
lgrade = scores[0];
}
else
{
lgrade = scores[(grade - 50) / 10];
if (grade != 100)
{
if (grade % 10 > 7)
{
lgrade += "+";
}
else if (grade % 10 < 3)
{
lgrade += "-";
}
}
}
cout << lgrade << endl;
}
return 0;
}
5.6 改写上一题的程序,使用条件运算符代替if else语句。
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
vector<string> scores = { "F","D","C","B","A" ,"A++" };
int grade = 0;
string lgrade;
while (cin >> grade)
{
lgrade = grade < 60 ? scores[0] : scores[(grade - 50) / 10];
lgrade +=
(grade < 60 || grade == 100) ? "" :
(grade % 10 > 7) ? "+" :
(grade % 10 < 3) ? "-" : "";
cout << lgrade << endl;
}
return 0;
}
5.7 改写下列代码段中的错误。
(a) if (ival1 != ival2)
ival1 = ival2
else
ival1 = ival2 = 0;
(b) if (ival < minval)
minval = ival;
occurs = 1;
(c) if (int ival = get_value())
cout << "ival = " << ival << endl;
if (!ival)
cout << "ival = 0\n";
(d) if (ival = 0)
ival = get_value();
(a) if (ival1 != ival2)
ival1 = ival2;
else
ival1 = ival2 = 0;
(b) if (ival < minval)
{
minval = ival;
occurs = 1;
}
(c) int val;
if (ival = get_value())
cout << "ival = " << ival << endl;
if (!ival)
cout << "ival = 0\n";
(d) if (ival == 0)
ival = get_value();
5.8 什么是“悬垂else”?C++语言是如何处理else子句的?
当一个if语句嵌套在另一个if语句内部时,很可能if分支会多于else分支。这时候我们怎么知道某个给定的else是和哪个if匹配呢。这个问题通常称作悬垂else。就C++而言,它规定else与离它最近的尚未匹配的if匹配的if匹配,从而消除了程序的二义性。
5.9 编写一段程序,使用一系列if语句统计从cin读入的文本中有多少元音字母。
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
char c;
int aCnt = 0, eCnt = 0, iCnt = 0, oCnt = 0, uCnt = 0;
while (cin >> c)
{
if (c == 'a')
{
aCnt++;
}
else if (c == 'e')
{
eCnt++;
}
else if (c == 'i')
{
iCnt++;
}
else if (c == 'o')
{
oCnt++;
}
else if (c == 'u')
{
uCnt++;
}
}
cout << "Number of vowel a: \t" << aCnt << '\n' << endl;
cout << "Number of vowel e: \t" << eCnt << '\n' << endl;
cout << "Number of vowel i: \t" << iCnt << '\n' << endl;
cout << "Number of vowel o: \t" << oCnt << '\n' << endl;
cout << "Number of vowel u: \t" << uCnt << endl;
return 0;
}
5.10 我们之前实现的统计元音字母的程序存在一个问题:如果元音字母以大写形式出现,不会被统计在内。编写一段程序,既统计元音字母的小写形式,也统计元音字母的大写形式,也就是说,新程序遇到’a’和’A’都应该递增 aCnt 的值,以此类推。
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
char c;
int aCnt = 0, eCnt = 0, iCnt = 0, oCnt = 0, uCnt = 0;
while (cin >> c)
{
if (c == 'a' || c == 'A')
{
aCnt++;
}
else if (c == 'e' || c == 'E')
{
eCnt++;
}
else if (c == 'i' || c == 'I')
{
iCnt++;
}
else if (c == 'o' || c == 'O')
{
oCnt++;
}
else if (c == 'u' || c == 'U')
{
uCnt++;
}
}
cout << "Number of vowel a: \t" << aCnt << '\n' << endl;
cout << "Number of vowel e: \t" << eCnt << '\n' << endl;
cout << "Number of vowel i: \t" << iCnt << '\n' << endl;
cout << "Number of vowel o: \t" << oCnt << '\n' << endl;
cout << "Number of vowel u: \t" << uCnt << endl;
return 0;
}
5.11 修改统计元音字母的程序,使其也能统计空格、制表符、和换行符的数量。
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
char c;
int aCnt = 0, eCnt = 0, iCnt = 0, oCnt = 0, uCnt = 0, newlineCnt = 0, tCnt = 0, vCnt = 0;
while (cin >> noskipws >> c)
{
if (c == 'a' || c == 'A')
{
aCnt++;
}
else if (c == 'e' || c == 'E')
{
eCnt++;
}
else if (c == 'i' || c == 'I')
{
iCnt++;
}
else if (c == 'o' || c == 'O')
{
oCnt++;
}
else if (c == 'u' || c == 'U')
{
uCnt++;
}
else if (c == '\n')
{
newlineCnt++;
}
else if (c == '\t')
{
tCnt++;
}
else if (c == '\v')
{
vCnt++;
}
}
cout << "Number of vowel a: \t" << aCnt << endl;
cout << "Number of vowel e: \t" << eCnt << endl;
cout << "Number of vowel i: \t" << iCnt << endl;
cout << "Number of vowel o: \t" << oCnt << endl;
cout << "Number of vowel u: \t" << uCnt << endl;
cout << "Number of vowel newline: \t" << newlineCnt << endl;
cout << "Number of vowel 空格: \t" << tCnt << endl;
cout << "Number of vowel 制表: \t" << vCnt << endl;
return 0;
}
5.12 修改统计元音字母的程序,使其能统计含以下两个字符的字符序列的数量: ff、fl和fi。
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
unsigned aCnt = 0, eCnt = 0, iCnt = 0, oCnt = 0, uCnt = 0, tabCnt = 0, newlineCnt = 0, ffCnt = 0, flCnt = 0, fiCnt = 0;
char ch;
char prech = '\0';
while (cin >> noskipws >> ch)
{
switch (ch) {
case 'a':
case 'A':
++aCnt;
break;
case 'e':
case 'E':
++eCnt;
break;
case 'i':
if (prech == 'f') ++fiCnt;
case 'I':
++iCnt;
break;
case 'o':
case 'O':
++oCnt;
break;
case 'u':
case 'U':
++uCnt;
break;
case '\n':
++newlineCnt;
break;
case '\t':
case '\v':
++tabCnt;
break;
case 'f':
if (prech == 'f') ++ffCnt;
break;
case 'l':
if (prech == 'f') ++flCnt;
break;
}
prech = ch;
}
cout << "Number of vowel a(A): \t" << aCnt << endl;
cout << "Number of vowel e(E): \t" << eCnt << endl;
cout << "Number of vowel i(I): \t" << iCnt << endl;
cout << "Number of vowel o(O): \t" << oCnt << endl;
cout << "Number of vowel u(U): \t" << uCnt << endl;
cout << "Number of newline: \t" << newlineCnt << endl;
cout << "Number of tab: \t" << tabCnt << endl;
cout << "Number of fi: \t" << fiCnt << endl;
cout << "Number of ff: \t" << ffCnt << endl;
cout << "Number of fl: \t" << flCnt << endl;
return 0;
}
5.13 下面显示的每个程序都含有一个常见的编码错误,指出错误在哪里,然后修改它们。
(a) unsigned aCnt = 0, eCnt = 0, iouCnt = 0;
char ch = next_text();
switch (ch) {
case 'a': aCnt++;
case 'e': eCnt++;
default: iouCnt++;
}
(b) unsigned index = some_value();
switch (index) {
case 1:
int ix = get_value();
ivec[ ix ] = index;
break;
default:
ix = ivec.size()-1;
ivec[ ix ] = index;
}
(c) unsigned evenCnt = 0, oddCnt = 0;
int digit = get_num() % 10;
switch (digit) {
case 1, 3, 5, 7, 9:
oddcnt++;
break;
case 2, 4, 6, 8, 10:
evencnt++;
break;
}
(d) unsigned ival=512, jval=1024, kval=4096;
unsigned bufsize;
unsigned swt = get_bufCnt();
switch(swt) {
case ival:
bufsize = ival * sizeof(int);
break;
case jval:
bufsize = jval * sizeof(int);
break;
case kval:
bufsize = kval * sizeof(int);
break;
}
a)加上break
unsigned aCnt = 0, eCnt = 0, iouCnt = 0;
char ch = next_text();
switch (ch) {
case 'a': aCnt++; break;
case 'e': eCnt++; break;
default: iouCnt++; break;
}
b)case 1处可能被略过,default处又使用到变量ix,所以需要将ix定义到switch case之外:
unsigned index = some_value();
int ix;
switch (index) {
case 1:
ix = get_value();
ivec[ ix ] = index;
break;
default:
ix = static_cast<int>(ivec.size())-1;
ivec[ ix ] = index;
}
c) case 后面应该用冒号而不是逗号。
unsigned evenCnt = 0, oddCnt = 0;
int digit = get_num() % 10;
switch (digit) {
case 1: case 3: case 5: case 7: case 9:
oddcnt++;
break;
case 2: case 4: case 6: case 8: case 0:
evencnt++;
break;
}
d)case 标签必须是整型常量表达式。
const unsigned ival=512, jval=1024, kval=4096;
unsigned bufsize;
unsigned swt = get_bufCnt();
switch(swt) {
case ival:
bufsize = ival * sizeof(int);
break;
case jval:
bufsize = jval * sizeof(int);
break;
case kval:
bufsize = kval * sizeof(int);
break;
}
5.14 编写一段程序,从标准输入中读取若干string对象并查找连续重复出现的单词,所谓连续重复出现的意思是:一个单词后面紧跟着这个单词本身。要求记录连续重复出现的最大次数以及对应的单词。如果这样的单词存在,输出重复出现的最大次数;如果不存在,输出一条信息说明任何单词都没有连续出现过。例如:如果输入是:
how now now now brown cow cow
那么输出应该表明单词now连续出现了3次。
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
string s, pres, maxs;
unsigned int Cnt = 1, mCnt = 1;
while (cin >> s)
{
if (s == pres)
{
Cnt++;
}
else
{
if (Cnt > mCnt)
{
mCnt = Cnt;
maxs = pres;
}
Cnt = 1;
}
pres = s;
}
if (Cnt > mCnt)
{
mCnt = Cnt;
maxs = pres;
}
if (mCnt > 1)
{
cout << maxs << ":" << mCnt << endl;
}
else
{
cout << "No repeat!" << endl;
}
return 0;
}
5.15 说明下列循环的含义并改正其中的错误。
(a) for (int ix = 0; ix != sz; ++ix) { /* ... */ }
if (ix != sz)
// . . .
(b) int ix;
for (ix != sz; ++ix) { /* ... */ }
(c) for (int ix = 0; ix != sz; ++ix, ++sz) { /*...*/ }
(a) ix定义for循环的内部,只能在for循环内部使用,如果需要外部使用,则需要定义在外部:
int ix;
for (ix = 0; ix != sz; ++ix) { /* ... */ }
if (ix != sz)
// . . .
(b)没有初始化语句,应该加以分号:
int ix;
for (; ix != sz; ++ix) { /* ... */ }
(c)sz初始化不明确,如果sz的初始值为0,则不进入循环;如果sz的初始值不为0,则需要循环体内需要有语句退出循环,否则会无休止地执行下去。
5.16 while 循环特别适用于那种条件不变、反复执行操作的情况,例如,当未达到文件末尾时不断读取下一个值。for 循环更像是在按步骤迭代,它的索引值在某个范围内一次变化。根据每种循环的习惯各自编写一段程序,然后分别用另一种循环改写。如果只能使用一种循环,你倾向于哪种?为什么?
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
int v[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
while (i < size(v))
{
cout << v[i] << " ";
i++;
}
cout << endl;
i = 0;
for (; i < 10; i++)
{
cout << v[i] << " ";
}
cout << endl;
return 0;
}
如果只能用一种循环,我会更倾向使用 while,因为while 显得简洁,代码可读性强。
5.17 假设有两个包含整数的vector对象,编写一段程序,检验其中一个vector对象是否是另一个的前缀。为了实现这一目标,对于两个不等长的vector对象,只需挑出长度较短的那个,把它的所有元素和另一个vector对象比较即可。例如,如果两个vector对象的元素分别是0、1、1、2 和 0、1、1、2、3、5、8,则程序的返回结果为真。
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
vector<int> v1 = { 0,1,2,3,4,5,6,7,8,9 };
vector<int> v2 = { 0,1,2,3,4 };
if (v1.size() > v2.size())
{
int i = 0;
for (; i < v2.size(); i++)
{
if (v1[i] != v2[i])
{
cout << false << endl;
break;
}
}
if (i == v2.size())
{
cout << true << endl;
}
}
else if (v1.size() < v2.size())
{
int i = 0;
for (; i < v1.size(); i++)
{
if (v1[i] != v2[i])
{
cout << false << endl;
break;
}
}
if (i == v1.size())
{
cout << true << endl;
}
}
return 0;
}
5.18 说明下列循环的含义并改正其中的错误。
(a) do
int v1, v2;
cout << "Please enter two numbers to sum:" ;
if (cin >> v1 >> v2)
cout << "Sum is: " << v1 + v2 << endl;
while (cin);
(b)
do {
// . . .
} while (int ival = get_response());
(c)
do {
int ival = get_response();
} while (ival);
(a)应该添加花括号:
do { // added bracket.
int v1, v2;
cout << "Please enter two numbers to sum:" ;
if (cin >> v1 >> v2)
cout << "Sum is: " << v1 + v2 << endl;
}while (cin);
(b)应该将ival 定义在循环外:
int ival;
do {
// . . .
} while (ival = get_response());
(c)使用的变量必须定义在循环体外:
int ival;
do {
ival = get_response();
} while (ival);
5.19 编写一段程序,使用do while 循环重复地执行下述任务:首先提示用户输入两个string对象,然后挑出较短的那个并输出它。
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
do
{
cout << "请输入两个string对象:" << endl;
string s1, s2;
cin >> s1 >> s2;
(s1.size() < s2.size()) ?
(cout << s1 << endl) :
(cout << s2 << endl);
}
while (cin);
return 0;
}
5.20 编写一段程序,从标准输入中读取string对象的序列直到连续出现两个相同的单词或者所有的单词都读完为止。使用while循环一次读取一个单词,当一个单词连续出现两次时使用break语句终止循环。输出连续重复出现的单词,或者输出一个消息说明没有任何单词是连续重复出现的。
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
string s, repeats, pres;
while (cin >> s)
{
if (s == pres)
{
repeats = pres;
break;
}
pres = s;
}
if (size(repeats) != 0)
{
cout << repeats << endl;
}
else
{
cout << "No repeat!" << endl;
}
return 0;
}
5.21 修改5.5.1节练习题的程序,使其找到的重复单词必须以大写字母开头。
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
string s, repeats, pres;
while (cin >> s)
{
if (!isupper(s[0]))
continue;
if (s == pres)
{
repeats = pres;
break;
}
pres = s;
}
if (size(repeats) != 0)
{
cout << repeats << endl;
}
else
{
cout << "No repeat!" << endl;
}
return 0;
}
5.22 本节的最后一个例子跳回到 begin,其实使用循环能更好的完成该任务,重写这段代码,注意不再使用goto语句。
// 向后跳过一个带初始化的变量定义是合法的
begin:
int sz = get_size();
if (sz <= 0) {
goto begin;
}
for (int sz = get_size(); sz <=0; sz = get_size())
;
5.23 编写一段程序,从标准输入读取两个整数,输出第一个数除以第二个数的结果。
#include <iostream>
#include <cstring>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
int v1, v2;
cin >> v1 >> v2;
cout << v1 / v2 << endl;
return 0;
}
5.24 修改你的程序,使得当第二个数是0时抛出异常。先不要设定catch子句,运行程序并真的为除数输入0,看看会发生什么?
#include <iostream>
#include <cstring>
#include <vector>
#include <stdexcept>
#include <iterator>
using namespace std;
int main()
{
int v1, v2;
cin >> v1 >> v2;
if (v2 == 0)
{
throw runtime_error("Divisor can't be 0!");
}
cout << v1 / v2 << endl;
return 0;
}
运行终止
5.25 修改上一题的程序,使用try语句块去捕获异常。catch子句应该为用户输出一条提示信息,询问其是否输入新数并重新执行try语句块的内容。
#include <iostream>
#include <cstring>
#include <vector>
#include <stdexcept>
#include <iterator>
using namespace std;
int main()
{
int v1, v2;
while (cin >> v1 >> v2)
{
try
{
if (v2 == 0)
{
throw runtime_error("Divisor can't be 0!");
}
cout << v1 / v2 << endl;
}
catch (runtime_error err)
{
cout << err.what()
<< "\nTry again? Enter y or n" << endl;
char c;
cin >> c;
if (c == 'n' || !cin)
{
break;
}
}
}
return 0;
}