编译软件为 vs2015。
第八章
练习8.1:
编写函数,接受一个 istream& 参数,返回值类型也是 istream&。此函数必须从给定流中读取数据,直至遇到文件结束标识时停止。它读取的数据打印在标准输出上。完成这些操作后,在返回流之前,对流进行复位,使其处于有效状态。
解答:
(注要求此函数从给定流中读取数据)
#include <iostream>
#include <string>
using namespace std;
istream &func(istream &input)
{
string str;
while (input >> str)
{
cout << str << endl;
}
input.clear();
return input;
}
练习8.2:
测试函数,调用参数为 cin。
解答:
#include <iostream>
#include <string>
using namespace std;
istream &func(istream &input)
{
string str;
while (input >> str)
{
cout << str << endl;
}
input.clear();
return input;
}
int main()
{
istream &in = func(cin);
cout << in.rdstate() << endl;
system("pause");
return 0;
}
练习8.3:
什么情况下,下面的 while 循环会终止?
while(cin>>i){ /*......*/ }
解答:
循环结束的条件:遇到 这三种情况 badbit(流已崩溃,系统级错误),failbit(IO 操作失败,可恢复错误),eofbit(到达文件结束符)。
练习8.4:
编写函数,以读模式打开一个文件,将其内容读入到一个 string 的 vector 中,将每一行作为一个独立的元素存在一个 vector 中。
解答:
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
using namespace std;
void ReadFile(const string &filename, vector<string> &vec)
{
ifstream input(filename);
if (input) // 如果读取成功
{
string str;
while (getline(input, str))
{
vec.push_back(str);
}
}
}
int main()
{
vector<string> vec;
ReadFile("D:\\string.txt", vec);
cout << "file content: " << endl;
for (auto &c : vec)
{
cout << c << endl;
}
system("pause");
return 0;
}
练习8.5:
重写上面的程序,将每个单词作为一个独立的元素存储。
解答:
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
using namespace std;
void ReadFile(const string &filename, vector<string> &vec)
{
ifstream input(filename);
if (input) // 如果读取成功
{
string str;
while (input >> str)
{
vec.push_back(str);
}
}
}
int main()
{
vector<string> vec;
ReadFile("D:\\string.txt", vec);
cout << "file content: " << endl;
for (auto &c : vec)
{
cout << c << endl;
}
system("pause");
return 0;
}
练习8.6:
重写 7.1.1 节的书店(第229页),从一个文件中读取交易记录。将文件名作为一个参数传递给 main (参见 6.2.5节,第 196 页)。
解答:
Sales_Data.h 文件如下:
#ifndef SALES_DATA_H
#define SALES_DATA_H
#include <iostream>
#include <string>
using namespace std;
class Sales_data
{
public:
string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
double aver_price = 0.0;
string isbn() const { return bookNo; };
Sales_data &combine(const Sales_data &item);
};
istream &read(istream &is, Sales_data &item)
{
double price = 0.0;
is >> item.bookNo >> item.units_sold >> price;
item.revenue = price*item.units_sold;
return is;
}
ostream &print(ostream &os, const Sales_data &item)
{
os << item.bookNo << " " << item.units_sold << " " << item.revenue
<< " " << item.revenue / item.units_sold;
return os;
}
Sales_data add(const Sales_data &lhs, const Sales_data &rhs)
{
Sales_data sum = lhs;
sum.combine(rhs);
return sum;
}
Sales_data &Sales_data::combine(const Sales_data &item)
{
units_sold += item.units_sold;
revenue += item.revenue;
aver_price = revenue / units_sold;
return *this;
}
#endif //Sales_Data_H
main.cpp 文件如下:
#include "Sales_Data.h"
#include <fstream>
using namespace std;
int main(int argc, char *argv[]) //argv[0]一般为一个空字符
{
argv[1] = "D:\\Sales_Record.txt";
ifstream input(argv[1]);
Sales_data total;
if (read(input, total))
{
Sales_data trans;
while (read(input, trans))
{
if (total.isbn() == trans.isbn())
//total.combine(trans);
total = add(total, trans);
else
{
print(cout, total);
cout << endl;
total = trans;
}
}
print(cout, total);
cout << endl;
}
else
{
cerr << "No data?!" << endl;
}
system("pause");
return 0;
}
Sales_Record.txt 文件如下:
运行结果:
练习8.7:
修改上一节的书店程序,将结果保存到一个文件中。将输出文件名作为第二个参数传递给 main 函数。
解答:
Sales_Data.h 文件同上,main.cpp 文件如下:
#include "Sales_Data.h"
#include <fstream>
using namespace std;
int main(int argc, char *argv[])
{
argv[1] = "D:\\Sales_Record.txt";
argv[2] = "D:\\Sales_Result.txt";
ifstream input(argv[1]);
ofstream output(argv[2]);
Sales_data total;
if (read(input, total))
{
Sales_data trans;
while (read(input, trans))
{
if (total.isbn() == trans.isbn())
//total.combine(trans);
total = add(total, trans);
else
{
print(output, total);
cout << endl;
total = trans;
}
}
print(output, total);
cout << endl;
}
else
{
cerr << "No data?!" << endl;
}
system("pause");
return 0;
}
保存文件的内容如下:
练习8.8:
修改上一题的程序,将结果追加到给定的文件末尾。对同一输出文件,运行程序至少两次,检验数据是否得以保留。
解答:
#include "Sales_Data.h"
#include <fstream>
using namespace std;
int main(int argc, char *argv[])
{
argv[1] = "D:\\Sales_Record.txt";
argv[2] = "D:\\Sales_Result.txt";
ifstream input(argv[1]);
ofstream output(argv[2], ofstream::app);
Sales_data total;
if (read(input, total))
{
Sales_data trans;
while (read(input, trans))
{
if (total.isbn() == trans.isbn())
//total.combine(trans);
total = add(total, trans);
else
{
print(output, total);
cout << endl;
total = trans;
}
}
print(output, total);
cout << endl;
}
else
{
cerr << "No data?!" << endl;
}
system("pause");
return 0;
}
可以看到,每运行一次程序,文件结果都会重新保存一次,且之前的结果也不会被丢弃。
练习8.9:
使用你为 8.1.2 节(第 281 页)第一个练习所编写的函数打印一个 istringstream 对象的内容。
解答:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
istream &func(istream &input)
{
string str;
while (input >> str)
{
cout << str << endl;
}
input.clear();
return input;
}
int main()
{
istringstream istr("Hello world");
func(istr);
system("pause");
return 0;
}
练习8.10:
编写程序,将来自一个文件中的行保存在一个 vector<string> 中。然后使用一个 istringstream 从 vector 中读取数据元素,每次读取一个单词。
解答:
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main(int argc, char *argv[])
{
argv[1] = "D:\\string.txt";
ifstream input(argv[1]);
vector<string> vec;
string str;
while (getline(input, str))
{
vec.push_back(str);
}
for (auto &c : vec)
{
istringstream output(c);
string word;
while (output >> word)
cout << word << endl;
}
system("pause");
return 0;
}
练习8.11:
本节的程序在外层 while 循环中定义了 istringstream 对象。如果 record 对象定义在循环之外,你需要对程序进行怎样的修改?重写程序,将 record 定义移到 while 之外,验证你设想的修改方法是否正确。
解答:
#include <string>
#include <sstream>
#include <iostream>
#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;
record.clear();
record.str(line);
record >> info.name;
while (record >> word)
{
info.phones.push_back(word);
people.push_back(info);
}
}
for (auto &c : people)
{
cout << c.name << endl;
for (auto & p : c.phones)
{
cout << p << " " << endl;
}
}
system("pause");
return 0;
}
练习8.12:
我们为什么没有在 PersonInfo 中使用类初始化?
解答:
PersonInfo 在这里是一个聚合类,因此没有类内初始化和构造函数。
练习8.13:
重写本节的电话号码程序,从一个命名文件而非 cin 读取数据。
解答:
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>
using namespace std;
struct PersonInfo
{
string name;
vector<string> phones;
};
int main()
{
ifstream input("D:\\school use\\Vspractice\\pra8_13\\Phones.txt");
string line, word;
vector<PersonInfo> people;
istringstream record;
while (getline(input, line))
{
PersonInfo info;
record.clear();
record.str(line);
record >> info.name;
while (record >> word)
{
info.phones.push_back(word);
people.push_back(info);
}
}
for (auto &c : people)
{
cout << c.name << endl;
for (auto & p : c.phones)
{
cout << p << " " << endl;
}
}
system("pause");
return 0;
}
练习8.14:
我们为什么将 entry 和 nums 定义为 const auto& ?
解答:
首先因为他们都是类类型,不是内置类型,所以用引用的方式;其次程序中这两个参数只用于访问对象而不修改对象,所以定义为常量类型。