本博客主要记录C++ Primer(第五版)中的练习题答案与解析。
参考:C++ Primer
C++ Primer
什么是空语句,什么时候会用到?
空语句只含有一个单独的分号。一种常见的情况是:当循环的全部工作在条件部分就可以完成时,通常就会用到空语句(P154)。
什么是块,什么时候会用到块?
用花括号括起来的语句和声明的序列成为块,一个块就是一个作用域。如循环体内有多条执行语句,就需要用到块,函数也需要用到块(P155)。
使用逗号运算符重写while循环,使其不需要块,观察改写之后代码可读性提高还是降低了。
重写后:while (val <= 10) sum += val, ++val;
可读性并没有提高,使用块更易读。
说明下列例子的含义,如果存在问题,试着修改。
(a) while (string::iterator iter != s.end()) { /* ... */ }
iter没有指向,直接判断其不等于s.end()是非法的。
(b)while ( bool status = find(word) ) {/* ... */ } if ( !status ) { /* ... */ }
while执行的条件就是status为真,status取反为假,因此if判断永远不成立。
写一段自己的程序,使用if else语句实现把数字成绩转化为字母成绩的要求。
代码:
#include
#include
#include
#include
using namespace std;
int main()
{
vector<string> scores = { "F", "D", "C", "B", "A", "A++" };
for (int g; cin >> g;)
{
string letter;
if (g < 60)
{
letter = scores[0];
}
else
{
letter = scores[(g - 50) / 10];
if (g != 100)
letter += g % 10 > 7 ? "+" : g % 10 < 3 ? "-" : "";
}
cout << letter << endl;
}
return 0;
}
测试:
60
D-
75
C
88
B+
改写上题程序,使用条件运算符代替if-else语句。
代码
#include
#include
#include
#include
using namespace std;
int main()
{
vector<string> scores = { "F", "D", "C", "B", "A", "A++" };
int grade = 0;
while (cin >> grade)
{
string lettergrade = grade < 60 ? scores[0] : scores[(grade - 50) / 10];
lettergrade += (grade == 100 || grade < 60) ? "" : (grade % 10 > 7) ? "+" : (grade % 10 < 3) ? "-" : "";
cout << lettergrade << endl;
}
return 0;
}
改正下面代码段中的错误。
(a)
if (ival1 != ival2)
ival1 = ival2//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";// 第二个if中的ival未定义,ival的作用域仅限于第一个if循环中
(d)
if (ival = 0)
ival = get_value(); // if中的判断应写为if (ival == 0)或 if (0 == ival)
什么是“悬垂else”?c++语言是如何处理else字句的?
当if语句嵌套时,可能会出现if语句的数量大于else语句的情况,这时,我们如何确定给定的else是和哪个if匹配的呢?这个问题就称作悬垂else。c++中规定,else与离它最近且尚未匹配的if语句匹配(P158)。
编写一段程序,使用if语句统计从cin读入的文本中有多少元音字母。
代码:
#include
#include
#include
#include
using namespace std;
int main()
{
unsigned aCnt = 0, eCnt = 0, iCnt = 0, oCnt = 0, uCnt = 0;
char ch;
while (cin >> ch)
{
if (ch == 'a') ++aCnt;
else if (ch == 'e') ++eCnt;
else if (ch == 'i') ++iCnt;
else if (ch == 'o') ++oCnt;
else if (ch == 'u') ++uCnt;
}
cout << "Number of vowel a: \t" << aCnt << '\n'
<< "Number of vowel e: \t" << eCnt << '\n'
<< "Number of vowel i: \t" << iCnt << '\n'
<< "Number of vowel o: \t" << oCnt << '\n'
<< "Number of vowel u: \t" << uCnt << endl;
return 0;
}
测试:
a
e
d
^Z
Number of vowel a: 1
Number of vowel e: 1
Number of vowel i: 0
Number of vowel o: 0
Number of vowel u: 0
上述代码有一个问题,如果是大写字母则不会被统计在内。编写程序,使大写字母和小写字母都能够统计在内。
代码:
#include
#include
#include
#include
using namespace std;
int main()
{
unsigned aCnt = 0, eCnt = 0, iCnt = 0, oCnt = 0, uCnt = 0;
char ch;
while (cin >> ch)
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 << "Number of vowel a(A): \t" << aCnt << '\n'
<< "Number of vowel e(E): \t" << eCnt << '\n'
<< "Number of vowel i(I): \t" << iCnt << '\n'
<< "Number of vowel o(O): \t" << oCnt << '\n'
<< "Number of vowel u(U): \t" << uCnt << endl;
return 0;
}
测试:
A
a
c
D
e
^Z
Number of vowel a(A): 2
Number of vowel e(E): 1
Number of vowel i(I): 0
Number of vowel o(O): 0
Number of vowel u(U): 0
修改统计元音字母的程序,使其也能统计空格、制表符和换行符的数量。
代码:
#include
#include
#include
#include
using namespace std;
int main()
{
unsigned aCnt = 0, eCnt = 0, iCnt = 0, oCnt = 0, uCnt = 0, spaceCnt = 0, tabCnt = 0, newLineCnt = 0;
char ch;
while (cin >> std::noskipws >> ch)
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 << "Number of vowel a(A): \t" << aCnt << '\n'
<< "Number of vowel e(E): \t" << eCnt << '\n'
<< "Number of vowel i(I): \t" << iCnt << '\n'
<< "Number of vowel o(O): \t" << oCnt << '\n'
<< "Number of vowel u(U): \t" << uCnt << '\n'
<< "Number of space: \t" << spaceCnt << '\n'
<< "Number of tab char: \t" << tabCnt << '\n'
<< "Number of new line: \t" << newLineCnt << endl;
return 0;
}
测试:
a
d
A
E
^Z
Number of vowel a(A): 2
Number of vowel e(E): 1
Number of vowel i(I): 0
Number of vowel o(O): 0
Number of vowel u(U): 0
Number of space: 0
Number of tab char: 1
Number of new line: 6
注意cin要使用noskipws,noskipws会告诉istream读取字符时不要跳过空白符。
修改统计元音字母的程序,使其能统计以下含有两个字符的字符序列的数量:ff,fl, fi
代码:
#include
#include
#include
#include
using namespace std;
int main()
{
unsigned aCnt = 0, eCnt = 0, iCnt = 0, oCnt = 0, uCnt = 0, spaceCnt = 0, tabCnt = 0, newLineCnt = 0, ffCnt = 0, flCnt = 0, fiCnt = 0;
char ch, prech = '\0';
while (cin >> std::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 ' ':
++spaceCnt;
break;
case '\t':
++tabCnt;
break;
case '\n':
++newLineCnt;
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 << '\n'
<< "Number of vowel e(E): \t" << eCnt << '\n'
<< "Number of vowel i(I): \t" << iCnt << '\n'
<< "Number of vowel o(O): \t" << oCnt << '\n'
<< "Number of vowel u(U): \t" << uCnt << '\n'
<< "Number of space: \t" << spaceCnt << '\n'
<< "Number of tab char: \t" << tabCnt << '\n'
<< "Number of new line: \t" << newLineCnt << '\n'
<< "Number of ff: \t" << ffCnt << '\n'
<< "Number of fl: \t" << flCnt << '\n'
<< "Number of fi: \t" << fiCnt << endl;
return 0;
}
下面显示的每个程序都有一个常见的编程错误,指出错误在哪里,然后修改它们。
(a)添加break;
(b)ix应在外部声明定义
(c)不能用逗号加以表示包括case 1 : case 2: case : 3
(d)case 后面需要加的是常量表达式,可以加const修饰符,将ival、jval、kval变成”常量“
从标准库中读取若干string对象并查询连续重复出现的单词。
代码:
#include
#include
#include
#include
using namespace std;
int main()
{
pair<string, int> max_duplicated;
int count = 0;
for (string str, prestr; cin >> str; prestr = str)
{
if (str == prestr) ++count;
else count = 0;
if (count > max_duplicated.second) max_duplicated = { prestr, count };
}
if (max_duplicated.first.empty()) cout << "There's no duplicated string." << endl;
else cout << "the word " << max_duplicated.first << " occurred " << max_duplicated.second + 1 << " times. " << endl;
return 0;
}
测试:
how now now now brown cow cow
^Z
the word now occurred 3 times.
说明下面循环的含义并改正其错误。
(a)
for(int ix = 0; ix != sz; ++ ix) {...}
if (ix != sz) // for循环结束的条件是ix == sz,因此if语句永远不成立。
// ...
(b)
int ix;
for (ix != sz; ++ix) {/* ... */} // 省略了初始化语句必须要有“;”,表示一个空语句。
(c)
for (int ix = 0; ix != sz; ++ix; ++ sz) {/* ... */} // ++ix和++sz同时执行,则for会一直循环下去。
假设有两个包含整数的vector对象,编写一段程序,检验其中一个vector的对象是否为另一个的前缀。为了实现这一目标,对于两个不等长的vector,只需挑出长度较短的那个,把它的所有元素和另一个vector对象比较即可。例如,两个vector的元素分别是0、1、1、2和0、1、1、2、3、5、8,则程序的返回结果应该为真。
代码:
#include
#include
#include
#include
using namespace std;
bool is_prefix(vector<int> const& lhs, vector<int> const& rhs)
{
if(lhs.size() > rhs.size())
return is_prefix(rhs, lhs);
for(unsigned i = 0; i != lhs.size(); ++i)
if(lhs[i] != rhs[i]) return false;
return true;
}
int main()
{
vector<int> l{ 0, 1, 1, 2 };
vector<int> r{ 0, 1, 1, 2, 3, 5, 8 };
cout << (is_prefix(r, l) ? "yes\n" : "no\n");
return 0;
}
说明循环含义并指出错误
(a)do需要使用花括号包含后面的语句,使其成为一个块。
(b)因为在do循环体中还需要使用到ival这个变量(作为判断条件),所以应该将其定义在循环体外部。
(c)同上
使用do while执行:提示用户输入两个string对象,然后跳出较短的那个并输出它。
代码:
#include
#include
#include
#include
using namespace std;
int main()
{
string rsp;
do {
cout << "Input two strings: ";
string str1, str2;
cin >> str1 >> str2;
cout << (str1 <= str2 ? str1 : str2)
<< " is less than the other. " << "\n\n"
<< "More? Enter yes or no: ";
cin >> rsp;
} while (!rsp.empty() && tolower(rsp[0]) == 'y');
return 0;
}
测试
Input two strings: asd asde
asd is less than the other.
More? Enter yes or no: n
从标准输入中读取string对象的序列直到连续出现两个相同的单词或者所有单词都读完为止。使用while循环一次读取一个单词,当一个单词连续出现两次时使用break语句终止循环。输出连续重复的单词,或者输出一个消息说明没有任何单词重复。
代码:
#include
#include
#include
#include
using namespace std;
int main()
{
string read, tmp;
while (cin >> read)
if (read == tmp) break; else tmp = read;
if (cin.eof()) cout << "no word was repeated." << endl;
else cout << read << " occurs twice in succession." << endl;
return 0;
}
测试
abc abc
abc occurs twice in succession.
修改P171练习题的程序,使其找到的重复单词必须以大写字母开头
代码:
#include
#include
#include
#include
using namespace std;
int main()
{
string curr, prev;
bool no_twice = true;
while (cin >> curr)
{
if (isupper(curr[0]) && prev == curr)
{
cout << curr << ": occurs twice in succession." << endl;
no_twice = false;
break;
}
prev = curr;
}
if (no_twice)
cout << "no word was repeated." << endl;
return 0;
}
测试:
Abc
Abc
Abc: occurs twice in succession.
从标准输入读入两个整数,输出第一个数除以第二个数的结果
代码:
#include
using std::cin;
using std::cout;
using std::endl;
int main()
{
int i, j;
cin >> i >> j;
cout << i / j << endl;
return 0;
}
修改程序,当第二个数是0时抛出异常。
代码:
#include
#include
int main(void)
{
int i, j;
std::cin >> i >> j;
if (j == 0)
throw std::runtime_error("divisor is 0");
std::cout << i / j << std::endl;
return 0;
}
测试
1
0
terminate called after throwing an instance of 'std::runtime_error'
what(): divisor is 0
修改程序,使用try语句块捕获异常。catch子句应该为用户输出一条提示信息,询问是否输入新数并重新执行try语句块的内容。
代码:
#include
#include
using std::cin; using std::cout; using std::endl; using std::runtime_error;
int main(void)
{
for (int i, j; cout << "Input two integers:\n", cin >> i >> j; )
{
try
{
if (j == 0)
throw runtime_error("divisor is 0");
cout << i / j << endl;
}
catch (runtime_error err)
{
cout << err.what() << "\nTry again? Enter y or n" << endl;
char c;
cin >> c;
if (!cin || c == 'n')
break;
}
}
return 0;
}
测试:
Input two integers:
1
0
divisor is 0
Try again? Enter y or n
n