C++Primer:cin的用前检查(练习8.11解答)


1. 背景

本节程序:

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
struct PersonInfo
{
    string name;
    vector<string> phones;
};

int main()
{
    string line, word;
    vector<PersonInfo> people;
    while (getline(cin, line)) //读取个人信息:名字、电话
    {
        PersonInfo info;
        istringstream record(line);
        record >> info.name; //保存名字
        while (record >> word)
        {
            info.phones.push_back(word); //保存多个电话
        }
        people.push_back(info);
    }

    for (auto &a1 : people) //打印保存的数据
    {
        cout << a1.name << " ";
        for (auto &a2 : a1.phones)
        {
            cout << a2 << " ";
        }
        cout << endl;
    }

    return 0;
}

输入数据:

morgan 2015552368 8625550123
drew 9735550130
lee 6095550132 2015550175 8005550000

输出结果:
运行结果

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

2. 解答

错误修改:

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
struct PersonInfo
{
    string name;
    vector<string> phones;
};

int main()
{
    string line, word;
    vector<PersonInfo> people;
    istringstream record;      //修改
    while (getline(cin, line)) 
    {
        PersonInfo info;
        // istringstream record(line);
        record.str(line);    //修改
        record >> info.name; 
        while (record >> word)
        {
            info.phones.push_back(word); 
        }
        people.push_back(info);
    }

    for (auto &a1 : people) 
    {
        cout << a1.name << " ";
        for (auto &a2 : a1.phones)
        {
            cout << a2 << " ";
        }
        cout << endl;
    }

    return 0;
}

输出结果:
运行结果

分析:

  1. 如上程序确实将record放置到while外定义,但修改后程序的结果只输出第一个人的信息,与原结果不同。修改程序错误。
istringstream record(line);//while内定义
//改为
istringstream record;      //while外定义
record.str(line);    //while内赋值
  1. 经调试发现,程序初次经过如下内层while时可以正确保存,但下次再经过这内层while时程序直接退出,即record >> word的返回值是false。
while (record >> word)
{
    info.phones.push_back(word); //保存多个电话
}
  1. 初次运行内层while时,只有当record读到文件结束位置,eofbit和failbit被置位,返回流的状态出错才能退出循环。故下次再进入内层while时,record已出错,不能再保存数据。

C++Primer中文版(第5版)第280页:
  一个流一旦发生错误。其上后续的IO操作都会失败。只有当一个流处于无错状态时,我们才可以从它读取数据,向它写入数据。
  while 循环检查>>表达式返回流的状态。如果输入操作成功,流保持有效状态。
  如果到达文件结束位置,eofbit和failbit都会被置位。
  如果badbit、eofbit、failbit任一个被置位,则检测流状态的条件会失败。

  1. 若record在外层while内定义,每次循环时record被重新定义,其初始状态无错,故每次经过内层while都能保存数据,读完数据后record出错退出内层while。
    while (getline(cin, line)) //外层while
    {
        PersonInfo info;
        istringstream record(line);//外层while内定义
        record >> info.name; 
        while (record >> word)//内层while
        {
            info.phones.push_back(word);
        }
        people.push_back(info);
    }
  1. 若record在外层while外定义,初次运行内层while后record失效,故需要通过将其全部复位后才能保存数据。
    istringstream record; //修改,外层while定义
    while (getline(cin, line))
    {
        PersonInfo info;
        record.clear();   //修改,将record的状态复位
        record.str(line); //修改,保存数据
        record >> info.name;
        while (record >> word)//内层while
        {
            info.phones.push_back(word);
        }
        people.push_back(info);
    }

正确修改:

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
struct PersonInfo
{
    string name;
    vector<string> phones;
};

int main()
{
    string line, word;
    vector<PersonInfo> people;
    istringstream record; //修改,外层while定义
    while (getline(cin, line))
    {
        PersonInfo info;
        record.clear();   //修改,将record的状态复位
        record.str(line); //修改,保存数据
        record >> info.name;
        while (record >> word) //内层while
        {
            info.phones.push_back(word);
        }
        people.push_back(info);
    }

    for (auto &a1 : people)
    {
        cout << a1.name << " ";
        for (auto &a2 : a1.phones)
        {
            cout << a2 << " ";
        }
        cout << endl;
    }

    return 0;
}

输出结果:
运行结果

3. 总结

  1. 使用一个流之前需先检查其状态。
  2. 一个流一旦发生错误,就无法读取或写入数据。
发布了77 篇原创文章 · 获赞 25 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_34801642/article/details/104971575