C++Primer第五版 第五章习题答案

练习5.1

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

      空语句:最简单的语句,空语句只有一个单独的分号。当程序中在语法上需要一条语句但是逻辑上却不需要时,此时应该使用空语句。

//不断的读取输入流的内容,直到输入中遇到s。
while (cin >> a && a != s)
    ; //使用空语句时,应该加上注释,使得代码阅读者知道语句是有意义的。

练习5.2

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

      块(也称复合语句)是指用花括号括起来的(可能为空的)语句和声明序列。

      当语言需要一个语句而程序逻辑需要多个语句时,可能会使用一个块。例如:

while (val <= 10)
{
    sum += val;
    ++val;
}

练习5.3

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

#include <iostream>
int main()
{
    int sum = 0, val = 1;
    while (val <= 10)
        sum += val, ++val;
    std::cout << "Sum of 1 to 10 inclusive is " << sum << std::endl;
    // 改写之后的代码可读性降低了

    return 0;
}

练习5.4

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

(a) while (string::iterator iter != s.end()) { /* . . . */ }
// iter变量未初始化,且初始化应该在while外部,修改:
    std::string::iterator iter = s.begin();
    while (string::iterator iter != s.end()) { /* . . . */ }

(b) while (bool status = find(word)) { /* . . . */ }
        if (!status) { /* . . . */ }
// status声明在while的控制结构里,只能在while循环内部使用,if语句不在while块中,所以status应该在外部声明
// 赋值运算作为条件,通常应该加上括号。如果像这题这样没加,当find(word)返回false赋值给status时,循环将一直持续下去,修改:
    bool status;
    while ((status = find(word))) {/* ... */}
    if (!status) {/* ... */}

练习5.5

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

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

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

int main()
{
    vector<string> scores = {"F", "D", "C", "B", "A", "A++"};

    int grade{0};
    while (cin >> grade) {
        string lettergrade;
        if (grade < 60)
            lettergrade = scores[0];
        else {
            lettergrade = scores[(grade - 50) / 10];
            if (grade != 100) {
                if (grade % 10 > 7)
                    lettergrade += "+";
                else if (grade % 10 < 3)
                    lettergrade += "-";
            }
        }

        cout << lettergrade << endl;
    }

    return 0;
}

练习5.6

改写上一题的程序,使用条件运算符代替if else语句。

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

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

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;
}

练习5.7

改写下列代码段中的错误。

(a) if (ival1 != ival2) 
        ival1 = ival2;                 // 少了分号
    else ival1 = ival2 = 0;
(b) if (ival < minval)
    {
        minval = ival;                 // 少了花括号
        occurs = 1;
    }
(c) int val;                           // val定义要在外部,才能在两个if语句中都使用它
    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语句,在c++中,else总是与其最近的尚未匹配的if相匹配。

练习5.9

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

#include <iostream>

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

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;
}

练习5.10

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

#include <iostream>
using std::cin;
using std::cout;
using std::endl;

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;
}

练习5.11

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

#include <iostream>

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

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;
}

练习5.12

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

#include <iostream>

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

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;
}

练习5.13

下面显示的每个程序都含有一个常见的编码错误,指出错误在哪里,然后修改它们。

      case关键字和它对应的值一起被称为case标签,case标签必须是整型常量表达式。

(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) // 如果在某处一个带有初值的变量位于作用域之外,在另一处该变量位于作用域之内,则从前一处跳到后一处是非法行为
    // 这里ix定义不可以放在switch作用域内
    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 <string>

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

int main()
{
    string pre_word, word, max_repeat_word;
    int repeat_times = 0, max_repeat_times = 0;
    
    while (cin >> word) {
        if (word == pre_word) {
            ++repeat_times;
        } else {
            repeat_times = 1;
            pre_word = word;
        }
        
        if (max_repeat_times < repeat_times) {
            max_repeat_times = repeat_times;
            max_repeat_word = pre_word;
        }
    }
    
    if (max_repeat_times <= 1){
        cout << "no word was repeated" << endl;
    } else {
        cout << "the word '" << max_repeat_word << "' occurred " << max_repeat_times << " times" << endl;
    }
}

练习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循环的语句头中定义,if语句在for循环的语句块外,所以ix时未定义的
    int ix;
    for (ix = 0; ix != sz; ++ix)  { /* ... */ }
    if (ix != sz)

(b) // for循环语句头中某些部分可以省略,但是分号不能省略
    int ix;
    for (; ix != sz; ++ix) { /* ... */ }

(c) // ix和sz同时加1,循环永远也结束不了
    for (int ix = 0; ix != sz; ++ix) { /*...*/ }

练习5.16

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

// while循环
int i;
while ( cin >> i )
    // ...

// 等同的for循环
for (int i = 0; cin >> i;)
    // ...

// for循环
for (int i = 0; i != size; ++i)
    // ...

// 等同的while循环
int i = 0;
while (i != size)
{
    // ...
    ++i;
}

练习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, 1, 2};
    vector<int> vec2{0, 1, 1, 2, 3, 5, 8};

    auto size = vec1.size() < vec2.size() ? vec1.size() : vec2.size();
    for (decltype(vec1.size()) i = 0; i != size; ++i) {
        if (vec1[i] != vec2[i]) {
            cout << "false" << endl;
            return 0;
        }
    }
    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) int ival;
    do {
        // . . .
    } while (ival = get_response());      // 不应在此范围内声明
(c) int ival = get_response();
    do {
        ival = get_response();            // ival不应在此范围内声明
    } while (ival);

练习5.19

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

#include <iostream>
#include <string>

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

int main()
{
    string rsp;
    do {
        cout << " 输入两个字符串: ";
        string str1, str2;
        cin >> str1 >> str2;
        cout << (str1 <= str2 ? str1 : str2) << " 比另一个小。 "
             << "\n\n"
             << " 再一次? 输入yes或者no: ";
        cin >> rsp;
    } while (!rsp.empty() && rsp[0] == 'y');
    return 0;
}

练习5.20

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

#include <iostream>
#include <string>

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

int main()
{
    string read, tmp;
    while (cin >> read)
        if (read == tmp)
            break;
        else
            tmp = read;

    if (cin.eof())
        cout << "一个单词也没有重复." << endl;
    else
        cout << read << "连续出现两次." << endl;
    return 0;
}

练习5.21

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

#include <iostream>
using std::cin;
using std::cout;
using std::endl;

#include <string>
using std::string;

int main() {
  string curr, prev;
  bool no_twice = false;

  while (cin >> curr) {
    if (!isupper(curr[0])) {
      prev = "";
      continue;
    }
    if (prev == curr) {
      cout << curr << " 连续出现两次。" << endl;
      no_twice = true;
      break;
    }
    prev = curr;
  }

  if (!no_twice) cout << " 没有单词重复 " << endl;
}

练习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>

int main(void)
{
    int a, b;
    std::cin >> a >> b;
    std::cout << static_cast<double>(a) / b << std::endl;

    return 0;
}

练习5.24

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

#include <iostream>
#include <stdexcept>

int main(void)
{
    int a, b;
    std::cin >> a >> b;

    if (b == 0) throw std::runtime_error("divisor is 0");

    std::cout << static_cast<double>(a) / b << std::endl;

    return 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(void)
{
    int a, b;
    cout << "Input two integers: ";
    while (cin >> a >> b) {
        try {
            if (b == 0) throw runtime_error("divisor is 0");
            cout << static_cast<double>(a) / b << endl;
            cout << " 输入两个整数: ";
        }
        catch (runtime_error err) {
            cout << err.what() ;
            cout << "\n再试一次? 输入 y 或 n:" << endl;
            char c;
            cin >> c;
            if (!cin || c == 'n')
                break;
            else
                cout << " 输入两个整数: ";
        }
    }

    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值