C++ primer 第八章習題

chapter8 IO庫

練習

8.1.2 節練習

練習8.1

  • 編寫函數,接受一個istream&參數,返回值類型也是istream&。此函數須從給定流中讀取數據,直至遇到文件結束標識時停止。它將讀取的數據打印在標準輸出上。完成這些操作後,在返回流之前,對流進行復位,使其處於有效狀態。
#include <iostream>
#include <string>
using namespace std;
istream& func(istream &is) {
	string str;
	while (!is.eof() && is >> str ) {    //優先判斷是否輸入結束標識符
		cout << str;
	}
	is.clear();
	return is;
}
int main() {
	func(cin);
}

練習8.2

  • 測試函數,調用參數爲cin。

如上。

練習8.3

  • 什麼情況下,下面的while循環會終止?
while (cin >> i) /*...*/

當輸入的是一個錯誤的狀態時,循環會終止;如eofbit,failbit和badbit。

輸入的不是類型i時,輸入文件停止符時,輸入終止符時等。

8.2.1 節練習

練習8.4

  • 編寫函數,以讀模式打開一個文件,將其內容讀入到一個string的vector中,將每一行作爲一個獨立的元素存於vector中。
#include <fstream>
int main(int argc,char *argv[]){
    ifstream in(argv[1]);
    vector<string> v;
    if (in){
        string s;
        while(getline(in, s)){
            v.push_back(s);
        }else{
            cerr << "got wrong filename." << endl;
        }
    }
    return 0;
}

練習8.5

  • 重寫上面的程序,將每個單詞作爲一個獨立的元素進行存儲。
#include <fstream>
int main(int argc,char *argv[]){
    ifstream in(argv[1]);
    vector<string> v;
    if (in){
        string s;
        while(in >> s){
            v.push_back(s);
        }else{
            cerr << "got wrong filename." << endl;
        }
    }
    return 0;
}

練習8.6

  • 重寫7.1.1節的書店程序(第229頁),從一個文件中讀取交易記錄。將文件名作爲一個參數傳遞給main(參見6.2.5節,第196頁)。
int main(int argc,char *argv[]){
    Sales_data total;
    ifstream in(argv[1]);
    if (in){
		if (read(in, total)) {
			Sales_data trans;
			while(read(in ,trans)) {
				if(total.isbn() == trans.isbn())
					total.combine(trans);
				else {
					print(cout, total) << endl;
					total =trans;
				}
			}
			print(cout, total)<<endl;
		}
		else {
			cerr<<" No data?!"<<endl;
		}
    }
    return 0;
}

8.2.2 節練習

練習8.7

  • 修改上一節的書店程序,將結果保存到一個文件中。將輸出文件名作爲第二個參數傳遞給main函數。
int main(int argc,char *argv[]){
    Sales_data total;
    ifstream in(argv[1]);
    ofstream out(argv[2]);
    if (in){
		if (read(in, total)) {
			Sales_data trans;
			while(read(in ,trans)) {
				if(total.isbn() == trans.isbn())
					total.combine(trans);
				else {
					print(out, total) << endl;
					total =trans;
				}
			}
			print(out, total)<<endl;
		}
		else {
			cerr<<" No data?!"<<endl;
		}
    }
    return 0;
}

練習8.8

  • 修改上一題的程序,將結果追加到給定的文件末尾。對同一個輸出文件,運行程序至少兩次,檢驗數據是否得以保留。
int main(int argc,char *argv[]){
    Sales_data total;
    ifstream in(argv[1]);
    ofstream out(argv[2], ofstream::app);
    if (in){
		if (read(in, total)) {
			Sales_data trans;
			while(read(in ,trans)) {
				if(total.isbn() == trans.isbn())
					total.combine(trans);
				else {
					print(out, total) << endl;
					total =trans;
				}
			}
			print(out, total)<<endl;
		}
		else {
			cerr<<" No data?!"<<endl;
		}
    }
    return 0;
}

8.3.1 節練習

練習8.9

  • 使用你爲8.1.2節(第281頁)第一個練習所編寫的函數打印一個istringstream對象的內容。

練習8.10

  • 編寫程序,將來自一個文件中的行保存在一個vector中。然後使用一個istringstream從vector讀取數據元素,每次讀取一個單詞。
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <fstream>
using namespace std;
int main(int argc, char *argv[]) {
	vector<string> v;
	fstream in(argv[1]);
	if (in) {
		string line;
		while (getline(in, line)) {
			cout << line << endl;
			v.push_back(line);
		}
	}
	string oneWord;
	for (const string& s : v) {
		istringstream word(s);
		while (word >> oneWord) {
			cout << oneWord << endl;
		}
	}
}

練習8.11

  • 本節的程序在外層while循環中定義了istringstream 對象。如果record 對象定義在循環之外,你需要對程序進行怎樣的修改?重寫程序,將record的定義移到while循環之外,驗證你設想的修改方法是否正確。
struct PersonInfo {
	string name;
	vector<string> phones;
};
int main(int argc, char const *argv[]) {
	string line, word;
	vector<PersonInfo> people;
	istringstream record;
	while (getline(cin, line)) {
		PersonInfo info;
		record.str(line);
		record >> info.name;
		while (record >> word)
			info.phones.push_back(word);
		people.push_back(info);
	}
	return 0;
}


練習8.12

  • 我們爲什麼沒有在PersonInfo中使用類內初始化。

每個人的號碼數量不同,默認初始化有利於後續添加號碼,減少計算開銷。

8.3.3 節練習

練習8.13

  • 重寫本節的電話號碼程序,從一個命名文件而非cin讀取數據。
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <fstream>
using namespace std;

struct PersonInfo {
	string name;
	vector<string> phones;
};
bool valid(const string& str) {
	return (str.size() > 0) ? true : false;
}
string format(const string& str) {
	return str;
}
int main(int argc, char const *argv[]) {
	string line, word;
	vector<PersonInfo> people;
	ifstream in(argv[1]);
	while (getline(in, line)) {
		PersonInfo info;
		istringstream record(line);
		record >> info.name;
		while (record >> word)
			info.phones.push_back(word);
		people.push_back(info);
	}
	ostringstream os;
	for (const auto &entry : people)
	{
		ostringstream formatted, badNums;
		for (const auto &nums : entry.phones)
		{
			if (!valid(nums))
			{
				badNums << " " << nums;
			}
			else
				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() << endl;
	return 0;
}


練習8.14

  • 我們爲什麼將entry和nums定義爲const auto&?

避免不必要的string類型的複製,同時因爲是引用,需要加上常量避免被誤操作修改原string。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章