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。