《C++ Primer》第8章 8.3节习题答案

《C++ Primer》第8章 IO库

8.3 string流 习题答案

练习8.9:使用你为8.1.2节(第281页)第一个练习编写的函数打印一个sitringstream对象的内存。

【出题思路】

本题练习字符串流的输入。

【解答】

#include 
#include 
#include 
#include 
#include 

using namespace std;

istream& f(istream &in)
{
    string v;
    while(in >> v, !in.eof())       //直到遇到文件结束符才停止读取
    {
        if(in.bad())
        {
            throw runtime_error("IO流错误");
        }

        if(in.fail())
        {
            cerr << "数据错误,请重试:" << endl;
            in.clear();
            in.ignore(100, '\n');
            continue;
        }
        cout << v << endl;
    }

    in.clear();
    return in;
}

int main(int argc, char *argv[])
{
    ostringstream msg;          //字符串输出流
    msg << "C++ Primer 第五版" << endl;
    istringstream in(msg.str());
    f(in);

    return 0;
}

运行结果:

练习8.10:编写程序,将来自一个文件中的行保存在一个vector中。然后使用一个sitringstream从vector读取数据元素,每次读取一个单词。

【出题思路】

本题继续练习字符串流的输入。

【解答】

#include 
#include 
#include 
#include 
#include 

using namespace std;

int main()
{
    //打开文件
    ifstream in("../chapter08/data08_10.txt");
    if(!in)
    {
        cerr << "无法打开输入文件" << endl;
        return -1;
    }

    string line;
    vector words;

    while(getline(in, line))                            //从文件中读取一行
    {
        words.push_back(line);                          //添加到vector中
    }

    in.close();                                         //输入完毕,关闭文件

    vector::const_iterator it = words.begin();  //迭代器
    while(it != words.end())                            //遍历vector
    {
        istringstream line_str(*it);
        string word;
        while(line_str >> word)                         //通过istringstream从vector中读取数据
        {
            cout << word << "  ";
        }
        cout << endl;
        ++it;
    }
    cout << "run sucess============" << endl;
    return 0;
}

运行结果:

练习8.11:本节的程序在外层while循环中定义了sitringstream对象。如果record对象定义在循环之外,你需要对程序进行怎样的修改?重写程序,将record的定义移到while循环之外,验证你设想的修改方法是否正确。

【出题思路】

本题练习字符串流的重复使用,每次通过str成员将流绑定到不同的字符串,同时还要调用clear来重置流的状态。

【解答】

#include 
#include 
#include 
#include 

using namespace std;

struct PersonInfo
{
    string name;
    vector phones;
};

int main(int argc, char *argv[])
{
    string line, word;                          //分别保存来自输入的一行和单词
    vector people;                  //保存来自输入的所有记录
    istringstream record;
    cout << "please input data" << endl;
    while(getline(cin, line))
    {
        PersonInfo info;                        //创建一个保存此记录数据的对象
        record.clear();                         //重复使用字符串流时,每次都要调用clear
        record.str(line);                       //将记录绑定到则读入的行
        record >> info.name;                    //读取名字
        while(record >> word)                   //读取电话号码
        {
            info.phones.push_back(word);        //保持它们
        }

        people.push_back(info);                 //将此记录追加到people末尾
    }

    cout << "people.size=============" << people.size() << endl;
    return 0;
}

运行结果:

《C++ Primer》第8章 8.3节习题答案_第1张图片

 练习8.12:我们为什么没有在PersonInfo中使用类内初始化?

【出题思路】

体会根据应用特点决定程序设计策略。

【解答】

由于每个人的电话号码数量不固定,因此更好的方式不是通过类内初始化指定人名和所有电话号码,而是在缺省初始化之后,在程序中设置人名并逐个添加电话号码。

练习8.13:重写本节的电话号码程序,从一个命名文件而非cin读取数据。

【出题思路】

本题练习文件流和字符串流输入输出的综合应用。

【解答】

#include 
#include 
#include 
#include 
#include 

using namespace std;

struct PersonInfo
{
    string name;
    vector phones;
};

string format(const string &s) { return s; }

bool valid(const string &s)
{
    //如何验证电话号码将在第17章介绍
    //现在简单返回true
    return true;
}

int main(int argc, char *argv[])
{
    string line, word;//分别保存来自输入的一行和单词
    vector people;//保存来自输入的所有记录
    istringstream record;

    if(argc != 2)
    {
        cerr << "请给出文件名" << endl;
        return -1;
    }

    ifstream in(argv[1]);
    if(!in)
    {
        cerr << "请给打开输入文件" << endl;
        return -1;
    }

    while(getline(in, line))
    {
        PersonInfo info;                    //创建一个保存此记录数据的对象
        record.clear();                     //重复使用字符串流时,每次都要调用clear
        record.str(line);                   //将记录绑定到刚读入的行
        record >> info.name;                //读取名字
        while(record >> word)               //读取电话号码
        {
            info.phones.push_back(word);    //保持它们
        }
        people.push_back(info);             //将此记录追加到people末尾
    }
    ostringstream os;
    for(const auto &entry: people)          //对people中每一项
    {
        ostringstream formatted, badNums;   //每个循环步创建的对象
        for(const auto &nums: entry.phones) //对每个数
        {
            if(!valid(nums))
            {
                badNums << "  " << nums;    //将数的字符串形式存入badNums
            }
            else
            {
                //将格式化的字符串“写入”formatted
                formatted << "  " << format(nums);
            }

            if(badNums.str().empty())       //没有错误的数,打印名字和格式化的数
            {
                os << entry.name << "  " << formatted.str() << endl;
            }
            else                            //否则,打印名字和错误的数据
            {
                cerr << "input error:" << entry.name << " invalid number(s) " << badNums.str() << endl;
            }
        }
    }
    cout << "os.str()=============\n" << os.str() << endl;
    return 0;
}

运行结果:

 练习8.14:我们为什么将entry和nums定义为const auto&?

【出题思路】

回顾范围for语句的相关内容。

【解答】

这两条语句分别使用范围for语句枚举people中所有项(人)和每项的phones中的所有项(电话号码)。使用const表明在循环中不会改变这些项的值;auto是请求编译器依据vector元素类型来推断出entry和nums的类型,既简化代码又避免出错;使用引用的原因是,people和phones的元素分别是结构对象和字符串对象,使用引用即可避免对象拷贝。

 

你可能感兴趣的:(#,C++,Primer(第5版)学习笔记,C++,Primer习题答案)