8.01 編寫函數,接受一個istream &參數,返回值也是istream&。此函數必須從給定流中讀取數據,直至遇到文件結束標識符時停止。它將讀取的數據打印在標准輸出上。完成這些操作后,在返回流之前,對流進行復位,使其處於有效狀態。
8.02 測試函數,調用cin。
// 8.01和8.02題
istream& readByIs(istream& is)
{
string word;
while (is >> word) {
cout << word << " ";
}
cout << endl;
is.clear();
return is;
}
void test801()
{
readByIs(cin);
}
8.03 什么情況下,下面的while循環會終止。
while (cin >> i) /* ... */
- 遇到輸入結束符;
- 遇到輸入錯誤,比如i是int型,卻輸入了字符。
8.04 編寫函數,以讀模式打開一個文件,將其內容讀入到一個string的vector中,將每一行作為一個獨立的元素存於vector中。
void readFileToVec(const string& fileName, vector<string>& svec)
{
ifstream ifs(fileName);
if (ifs) {
string buf;
while (getline(ifs, buf)) {
svec.push_back(buf);
}
}
}
void test804()
{
string file_name = "C:/Users/tutu/Documents/code/cpp_primer/ch08/string.txt";
vector<string> svec;
readFileToVec(file_name, svec);
ofstream of;
for (auto i : svec) {
cout << i << endl;
}
}
8.05 重寫上面的程序,將每個單詞作為一個獨立的元素進行存儲。
while (ifs >> buf)
// 將上題中的while (getline(ifs, buf))改為上述語句。
8.06 重寫7.1.1節的書店程序,從一個文件中讀取交易記錄。將文件名作為參數傳遞給main。
#include "../ch07/Sales_data.h"
int main(int argc, char** argv)
{
ifstream ifs(argv[1]);
if (ifs) {
Sales_data total;
if (read(ifs, total)) { // ifstream繼承與istream,因此這里可以直接使用文件流。
Sales_data trans;
while (read(ifs, trans)) {
if (total.isbn() == trans.isbn()) {
total.combine(trans);
}
else {
print(cout, total) << endl;
total = trans;
}
}
print(cout, total) << endl;
}
else {
cout << "No data?" << endl;
}
}
else {
cout << "file name error?" << endl;
}
return 0;
}
// windows下運行方式:ch08.exe C:\Users\tutu\Documents\code\cpp_primer\ch08\sales.txt
8.07 修改上一個程序,將結果保存在一個文件中。將輸出文件名作為第二個參數傳給main。
#include "../ch07/Sales_data.h"
int main(int argc, char** argv)
{
ifstream ifs(argv[1]);
ofstream ofs(argv[2]);
if (ifs) {
Sales_data total;
if (read(ifs, total)) {
Sales_data trans;
while (read(ifs, trans)) {
if (total.isbn() == trans.isbn()) {
total.combine(trans);
}
else {
print(ofs, total) << endl;
total = trans;
}
}
print(ofs, total) << endl;
}
else {
cout << "No data?" << endl;
}
}
else {
cout << "file name error?" << endl;
}
return 0;
}
8.08 修改上一題的程序,將結果追加到給定的文件末尾。對同一個輸出文件,運行程序至少兩次,檢驗數據是否得以保留。
把ofstream ofs(argv[2]);改為ofstream ofs(argv[2], ofstream::app);
8.09 使用8.1.2節第一個練習所編寫的函數打印一個istringstream對象的內容。
void test809()
{
string str = "hello world";
istringstream iss(str);
readByIs(iss);
}
8.10 編寫程序,將來自一個文件中的行保存在一個vector
void test810()
{
string line, word;
vector<string> str_line;
string fileName = "C:/Users/tutu/Documents/code/cpp_primer/ch08/string.txt";
ifstream ifs(fileName);
if (ifs) {
while (getline(ifs, line)) {
str_line.push_back(line);
}
for (auto i : str_line) {
istringstream record(i);
while (record >> word) {
cout << word << " ";
}
cout << endl;
}
}
}
8.11 本節的程序在外層while循環中定義了istringstream對象。如果record對象定義在循環之外,你需要對程序做怎樣的修改?重寫程序,將record的定義移到while循環之外,驗證你設想的修改方法是否正確。
void test811()
{
string line, word;
vector<PersonInfo> people;
string fileName = "C:/Users/tutu/Documents/code/cpp_primer/ch08/personInfo.txt";
ifstream ifs(fileName);
if (ifs) {
istringstream record;
while (getline(ifs, line)) {
PersonInfo info;
record.clear(); // 記得clear,否則只會打印一行
record.str(line);
record >> info.name;
while (record >> word) {
info.number.push_back(word);
}
people.push_back(info);
}
}
else {
cout << "No data?" << endl;
}
for (auto i : people) {
i.print(cout);
}
}
8.12 我們為什么沒有在PersonInfo中使用類內初始化?
因為這里我們使用了聚合類,不需要類內初始化。
8.13 重寫本節的電腦號碼程序,從一個命名文件而非cin讀取數據。
#include <sstream>
struct PersonInfo
{
string name;
vector<string> number;
std::ostream& print (std::ostream& os);
};
std::ostream& PersonInfo::print (std::ostream& os)
{
os << name << "\t";
for (auto i : number) {
os << i << " ";
}
cout << endl;
return os;
}
void test813()
{
string line, word;
vector<PersonInfo> people;
string fileName = "C:/Users/tutu/Documents/code/cpp_primer/ch08/personInfo.txt";
ifstream ifs(fileName);
if (ifs) {
while (getline(ifs, line)) {
PersonInfo info;
istringstream record(line);
record >> info.name;
while (record >> word) {
info.number.push_back(word);
}
people.push_back(info);
}
}
else {
cout << "No data?" << endl;
}
for (auto i : people) {
i.print(cout);
}
}
8.14 我們為什么要將entry和nums定義為const auto&。
使用引用是因為,都是類內string類型,引用可以避免拷貝,提高效率。
const是因為函數內不改變對象的值。