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;
}
输出结果:
分析:
- 如上程序确实将record放置到while外定义,但修改后程序的结果只输出第一个人的信息,与原结果不同。修改程序错误。
istringstream record(line);//while内定义
//改为
istringstream record; //while外定义
record.str(line); //while内赋值
- 经调试发现,程序初次经过如下内层while时可以正确保存,但下次再经过这内层while时程序直接退出,即record >> word的返回值是false。
while (record >> word)
{
info.phones.push_back(word); //保存多个电话
}
- 初次运行内层while时,只有当record读到文件结束位置,eofbit和failbit被置位,返回流的状态出错才能退出循环。故下次再进入内层while时,record已出错,不能再保存数据。
C++Primer中文版(第5版)第280页:
一个流一旦发生错误。其上后续的IO操作都会失败。只有当一个流处于无错状态时,我们才可以从它读取数据,向它写入数据。
while 循环检查>>表达式返回流的状态。如果输入操作成功,流保持有效状态。
如果到达文件结束位置,eofbit和failbit都会被置位。
如果badbit、eofbit、failbit任一个被置位,则检测流状态的条件会失败。
- 若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);
}
- 若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. 总结
- 使用一个流之前需先检查其状态。
- 一个流一旦发生错误,就无法读取或写入数据。