C ++ Primer(第五版)第五章练习答案

5.1 节练习

练习 5.1

什么是空语句?什么时候会用到空语句?

空语句中只含有一个单独的分号;
如果在程序的某个地方,语法上需要一条语句但是逻辑上不需要,此时应该使用空语句。

练习 5.2

什么是块?什么时候会用到块?

块就是复合语句,是指用花括号括起来的语句和声明序列;
如果在程序的某个地方,语法上需要一条语句,但是逻辑上需要多条语句,则应该使用复合语句。

练习5.3

使用逗号运算符(参见 4.10节,第 104 页)重写 1.4.1 节(第 10 页)的 while 循环,使它不再需要块,观察改写之后的代码的可读性提高了还是降低了。

while(val <= 10)
    sum += val, ++val;

可读性降低。

5.2 节练习

练习 5.4

说明下列例子的含义,如果存在问题,试着修改它。

(a) while (string::iterator iter != s.end()) {/*...*/}
(b) while (bool status = find(word)) {/*...*/}
    if (!status) {/*...*/}

(a) 遍历字符串 s;在 while 控制结构内定义的变量 iter 必须初始化,可以在内部初始化。
(b) 查找 word;status 是在 while 控制结构内部定义的,不能在 while 循环以外使用,函数死循环。可以将 if 语句块放到 while 循环内。

5.3.1 节练习

练习 5.5

写一段自己的程序,使用 if else 语句实现把数字成绩转换为字母成绩的要求。

#include<iostream>
#include<vector>
#include<string>

using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;

int main()
{
    const vector<string> scores = {"F", "E", "D", "C", "B", "A", "A++"};
    string lettergrade;
    int grade;
    while (cin >> grade)
    {
        if (grade < 60)
        {
            lettergrade = scores[0];
        }
        else
        {
            lettergrade = scores[(grade - 50) / 10];
        }
        cout << lettergrade << endl;
    }
    return 0;
}

练习 5.6

改写上一题的程序,使用条件运算符(参见 4.7 节,第 134 页)代替 if else 语句。

#include<iostream>
#include<vector>
#include<string>

using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;

int main()
{
    const vector<string> scores = {"F", "E", "D", "C", "B", "A", "A++"};
    string lettergrade;
    int grade;
    while (cin >> grade)
    {
        grade < 60 ? lettergrade = scores[0] : lettergrade = scores[(grade - 50) / 10];
        cout << lettergrade << 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 ival = get_value();
	if (ival)// if内的条件应该为bool类型
        cout << "ival = " << ival << endl;
    if (!ival)
        cout << "ival = 0\n";
(d) if (ival == 0)// if内的条件应该为bool类型
        ival = get_value();

练习 5.8

什么是“悬垂 else”?C++语言是如何处理 else 子句的?

悬垂 else 是指在嵌套if语句中,if 分支多于 else 分支的情况。
C++的解决方法是规定 else 与离它最近的未匹配的 if 语句匹配。

5.3.2 节练习

练习 5.9

编写一段程序,使用一系列 if 语句统计从 cin 读入的文本中有多少元音字母。

#include<iostream>

using std::cin;
using std::cout;
using std::endl;

int main()
{
    char c;
    int vowelCnt = 0;
    while (cin >> c)
    {
        if (c == 'a')
        {
            ++vowelCnt;
        }
        if (c == 'e')
        {
            ++vowelCnt;
        }
        if (c == 'i')
        {
            ++vowelCnt;
        }
        if (c == 'o')
        {
            ++vowelCnt;
        }
        if (c == 'u')
        {
            ++vowelCnt;
        }
    }
    cout << vowelCnt << endl;
    return 0;
}

练习 5.10

我们之前实现的统计元音字母的程序存在一个问题:如果元音字母以大写形式出现,不会被统计在内。编写一段程序,既统计元音字母的小写形式,也统计元音字母的大写形式,也就是说,新程序遇到’a’和’A’都应该递增 aCnt 的值,以此类推。

#include<iostream>

using std::cin;
using std::cout;
using std::endl;

int main()
{
    char c;
    unsigned aCnt = 0, eCnt = 0, iCnt = 0, oCnt = 0, uCnt = 0;
    while (cin >> c)
    {
        switch (c)
        {
        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;
        default:
            break;
        }
    }
    cout << aCnt << endl;
    cout << eCnt << endl;
    cout << iCnt << endl;
    cout << oCnt << endl;
    cout << uCnt << endl;
    return 0;
}

练习 5.11

修改统计元音字母的程序,使其也能统计空格、制表符、和换行符的数量。

#include<iostream>

using std::cin;
using std::cout;
using std::endl;

int main()
{
    char c;
    unsigned aCnt = 0, eCnt = 0, iCnt = 0, oCnt = 0, uCnt = 0, sCnt = 0, tCnt = 0, nCnt = 0;
    while (cin.get(c))
    {//cin的>>输入操作符将空字符(空格、tab和回车)当作输入的结束,故使用cin.get(ch)方法,可获得空格、回车和tab等特殊字符。
        switch (c)
        {
        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 ' ':
            ++sCnt;
            break;

        case '\t':
            ++tCnt;
            break;

        case '\n':
            ++nCnt;
            break;

        default:
            break;
        }
    }
    cout << aCnt << endl;
    cout << eCnt << endl;
    cout << iCnt << endl;
    cout << oCnt << endl;
    cout << uCnt << endl;
    cout << sCnt << endl;
    cout << tCnt << endl;
    cout << nCnt << endl;
    return 0;
}

练习 5.12

修改统计元音字母的程序,使其能统计含以下两个字符的字符序列的数量: ff、fl和fi。

#include<iostream>

using std::cin;
using std::cout;
using std::endl;

int main()
{
    char c, prec='1';//c 的上一个字符,定义一个非目标字符
    unsigned aCnt = 0, eCnt = 0, iCnt = 0, oCnt = 0, uCnt = 0, sCnt = 0, tCnt = 0, nCnt = 0;
    unsigned ffCnt = 0, flCnt = 0, fiCnt = 0;
    while (cin.get(c))
    {//每次循环后,保存字符,到下次循环是,如果是 f、l、i 时,判断前一个字符是否是f
        switch (c)
        {
        case 'a':
        case 'A':
            ++aCnt;
            break;

        case 'e':
        case 'E':
            ++eCnt;
            break;

        case 'i':
            if (prec=='f')
            {
                ++fiCnt;
            }
        case 'I':
            ++iCnt;
            break;

        case 'o':
        case 'O':
            ++oCnt;
            break;

        case 'u':
        case 'U':
            ++uCnt;
            break;

        case ' ':
            ++sCnt;
            break;

        case '\t':
            ++tCnt;
            break;

        case '\n':
            ++nCnt;
            break;

        case 'f':
        if (prec=='f')
        {
            ++ffCnt;
        }
        break;

        case 'l':
        if (prec=='f')
        {
            ++flCnt;
        }
        break;

        default:
            break;
        }
        prec = c;
    }
    cout << aCnt << endl;
    cout << eCnt << endl;
    cout << iCnt << endl;
    cout << oCnt << endl;
    cout << uCnt << endl;
    cout << sCnt << endl;
    cout << tCnt << endl;
    cout << nCnt << endl;
    cout << ffCnt << endl;
    cout << flCnt << endl;
    cout << fiCnt << 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 ) case 和 break 后没有写 break,其次 default 情况下,任意字符均会使 iouCnt++,逻辑错误。改为:

unsigned aCnt = 0, eCnt = 0, iouCnt = 0;
    char ch = next_text();
    switch (ch) {
        case 'a': aCnt++;break;
        case 'e': eCnt++;break;
        case 'i': case 'o': case 'u': iouCnt++;break;
        default: break;
    }

( b ) 执行 switch 语句时,如果是 case 2 就会跳过 ix 的定义。改为:

(b) unsigned index = some_value();
	int ix = get_value();
    switch (index) {
        case 1:
            ivec[ ix ] = index;
            break;
        default:
            ix = ivec.size()-1;
            ivec[ ix ] = index;
    }

( c ) case 语法错误。改为:

(c) 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;
    }

case 标签必须是整型常量表达式。改为:

(d) 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.4.1 节练习

练习 5.14

编写一段程序,从标准输入中读取若干 string 对象并查找连续重复出现的单词。所谓连续重复出现的意思是:一个单词后面紧跟着这个单词本身。要求记录连续重复出现的最大次数以及对应的单词。如果这样的单词存在,输出重复出现的最大次数;如果不存在,输出一条信息说明任何单词都没有连续出现过。例如:如果输入是

how now now now brown cow cow

那么输出应该表明单词 now 连续出现了 3 次。

#include<iostream>
#include<vector>
#include<string>

using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;

int main()
{
    vector<string> words;
    string cinWord;
    int count = 1, temp = 1;
    string word=" ", teWord=" ";
    while (cin >> cinWord)
    {
        words.push_back(cinWord);
    }
    auto beg = words.begin();
    while (beg + 1 != words.end())
    {
        teWord = *beg;
        if (*beg == *(beg + 1))
        {
            ++temp;
        }
        else
        {
            temp = 1;
        }
        if (temp > count)
        {
            count = temp;
            word = teWord;
        }
        ++beg;
    }
    if (count != 1)
    {
        cout << "单词 " << word << " 连续出现了 " << count << " 次。" << endl;
    }
    else
    {
        cout << "没有任何单词连续出现过!" << endl;
    }
    return 0;
}

5.4.2 节练习

练习 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) { /*...*/ }

ix 只能在 for 循环内部使用,如果要在外部使用,需要定义在 for 循环外:

(a) int ix;
	for (ix = 0; ix != sz; ++ix) { /* ... */ }
    if (ix != sz)

缺少 init-statement。改为:

(b) int ix;
    for (/*空语句*/;ix != sz; ++ix) { /* ... */ }

如果 sz 初始值为 0 的话,会进入死循环,删除 sz 自增:

(c) for (int ix = 0; ix != sz; ++ix) { /*...*/ }

练习 5.16

while 循环特别适用于那种条件不变、反复执行操作的情况,例如,当未达到文件末尾时不断读取下一个值。for 循环更像是在按步骤迭代,它的索引值在某个范围内依次变化。根据每种循环的习惯用法各自编写一段程序,然后分别用另一种循环改写。如果只能使用一种循环,你倾向于哪种?为什么?

#include<iostream>

using std::cin;

int main()
{
    int a = 0;
    while (cin>>a)
    {
        /* code */
    }
    for (size_t i = 0; cin >> i; /*空语句*/)
    {
        /* code */
    }

    int i = 0;
    for (i = 0; i < 10; i++)
    {
        /* code */
    }
    while (i < 10)
    {
        ++i;
    }
    return 0;
}

while 循环,更加简洁。

练习 5.17

假设有两个包含整数的 vector 对象,编写一段程序,检验其中一个 vector 对象是否是另一个的前缀。为了实现这一目标,对于两个不等长的 vector 对象,只需挑出长度较短的那个,把它的所有元素和另一个 vector 对象比较即可。例如,如果两个 vector 对象的元素分别是 0、1、1、2 和 0、1、1、2、3、5、8,则程序的返回结果为真。

#include<iostream>
#include<vector>

using std::cout;
using std::endl;
using std::vector;

int main()
{
    vector<int> vec1 = {0, 1, 2, 3}, vec2 = {0, 1, 2, 3, 4, 5};
    auto beg1 = vec1.begin(), beg2 = vec2.begin();
    while (*beg1 == *beg2)
    {
        ++beg1;
        ++beg2;
    }
    if (beg1==vec1.end())
    {
        cout << "前缀" << endl;
    }
    else
    {
        cout << "不是前缀" << endl;
    }
    return 0;
}

5.4.4 节练习

练习 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 {
        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 )ival 应该定义在循环之外:

int ival;
    do {
        ival = get_response();
    } while (ival); 

练习 5.19

编写一段程序,使用 do while 循环重复地执行下述任务:首先提示用户输入两个 string 对象,然后挑出较短的那个并输出它。

#include<iostream>
#include<string>

using std::cin;
using std::cout;
using std::endl;
using std::string;

int main()
{
    string rsp;
    do
    {
        cout << "please enter two string: ";
        string str1="", str2="";
        cin >> str1 >> str2;
        cout << "The longer string is: " << ((str1.size() > str2.size()) ? str1 : str2) << "\n\n"
             << "More? Enter yes or no: ";
        cin >> rsp;
    } while (!rsp.empty()&&rsp[0]!='n');

    return 0;
}

5.5.1 节练习

练习 5.20

编写一段程序,从标准输入中读取 string 对象的序列直到连续出现两个相同的单词或者所有单词都读完为止。使用 while 循环一次读取一个单词,当一个单词连续出现两次时使用 break 语句终止循环。输出连续重复出现的单词,或者输出一个消息说明没有任何单词是连续重复出现的。

#include<iostream>
#include<string>
#include<vector>

using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;

int main()
{
    string word = " ", preWord = " ";
    vector<string> words;
    while (cin >> word)
    {
        words.push_back(word);
        if (preWord == word)
        {
            break;
        }
        preWord = word;
    }
    if (*(words.end() - 1) == *(words.end() - 2))
    {
        cout << preWord << " 重复出现" << endl;
    }
    else
    {
        cout << "没有任何单词重复出现" << endl;
    }
    
    return 0;
}

5.5.2 节练习

练习 5.21

修改 5.5.1 节练习题的程序,使其找到的重复单词必须以大写字母开头。

#include<iostream>
#include<string>
#include<vector>

using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;

int main()
{
    string word = " ", preWord = " ";
    vector<string> words;
    while (cin >> word)
    {
        words.push_back(word);
        if (preWord == word && isupper(word[0]))
        {
            break;
        }
        preWord = word;
    }

    if (*(words.end() - 1) == *(words.end() - 2) && isupper(word[0]))
    {
        cout << preWord << " 重复出现" << endl;
    }
    else
    {
        cout << "没有任何单词重复出现" << endl;
    }
    
    return 0;
}

5.5.3 练习

练习 5.22

本节的最后一个例子跳回到 begin,其实使用循环能更好的完成该任务,重写这段代码,注意不再使用 goto 语句。

begin:
    int sz = get_size();
    if (sz <= 0) {
        goto begin;
    }

循环

    int sz = 0;
    do
    {
        sz = get_size();
    } while (sz <= 0);

5.6.3 节练习

练习 5.23

编写一段程序,从标准输入读取两个整数,输出第一个数除以第二个数的结果。

#include<iostream>

using std::cin;
using std::cout;
using std::endl;
int main()
{
    int a, b;
    cin >> a >> b;
    cout << a / b << endl;
    return 0;
}

练习 5.24

修改你的程序,使得当第二个数是 0 时抛出异常。先不要设定 catch 子句,运行程序并真的为除数输入 0 ,看看会发生什么?

#include<iostream>
#include<stdexcept>

using std::cin;
using std::cout;
using std::endl;
using std::runtime_error;

int main()
{
    int a, b;
    cin >> a >> b;
    if (b == 0)
    {
        throw runtime_error("除数不能为 0");
    }
    cout << a / b << endl;
    
    return 0;
}

结果

2
0
terminate called after throwing an instance of 'std::runtime_error'
  what():  除数不能为 0

练习 5.25

修改上一题的程序,使用 try 语句块去捕获异常。catch 子句应该为用户输出一条提示信息,询问其是否输入新数并重新执行 try 语句块的内容。

#include<iostream>
#include<stdexcept>

using std::cin;
using std::cout;
using std::endl;
using std::runtime_error;

int main()
{
    int a, b;
    while (cin >> a >> b)
    {
        try
        {
            if (b == 0)
            {
                throw runtime_error("除数不能为 0");
            }
            cout << a / b << endl;
        }
        catch(runtime_error err)
        {
            cout << err.what() << "\n是否再次输入?Enter y or n" << endl;
            char c;
            cin >> c;
            if (!cin || c == 'n')
            {
                break;
            }
        }   
    }

    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值