c++ Primer 第八章:IO库 练习答案记录

c++ Primer 第八章:IO库 练习答案记录

练习题导航

下面的练习别忘记都加上下面这一语句

#include<iostream>

8.1 IO类

8.1.1 IO对象无拷贝或赋值

8.1.1 IO对象无拷贝或赋值

8.1.2 条件状态

练习8.1 编写函数,接受一个istream&参数,返回值类型也是istream&。此函数须从给定流中读取数据,直至遇到文件结束标识时停止。它将读取的数据打印在标准输出上。完成这些操作后,在返回流之前,对流进行复位,使其处于有效状态。

using namespace std;

istream& is(istream& is)
{
	string s;
	while (is >> s)
		cout << s << endl;
	is.clear();
	return is;
}

练习8.2 测试函数,调用参数为cin

using namespace std;

istream& is(istream& is)
{
	string s;
	while (is >> s)
		cout << s << endl;
	is.clear();
	return is;
}

int main()
{
	is(cin);

	string s1;
	while (cin >> s1)
		cout << s1 << endl;
}

在这里插入图片描述

练习8.3 什么情况下,下面的while循环会终止?

badbit、failbit和eofbit任一个被置位,则检测流状态的条件会失败。

while(cin>>i) 

8.1.3 管理输出缓冲

8.2 文件输入输出

8.2.1 使用文件流对象

练习8.4 编写函数,以读模式打开一个文件,将其内容读入到一个string的vector中,将每一行作为一个独立的元素存于vector中

首先在一个目录下创建一个txt文件,我这里在E:\C++练习\test8目录下创建了一个input的txt文件

在这里插入图片描述

文件内容如下

在这里插入图片描述

点击另存为,编码选择ANSI(不然中文打出来会乱码)

在这里插入图片描述

主程序,记住文件名处是两个斜杠才能识别

#include<fstream>   //文件输入输出
#include<string>
#include<vector>
using namespace std;
int main()
{
	vector<string> inp;
	string input;
	ifstream in("E:\\C++练习\\test8\\input.txt");   //路径这里要加两个\\单独一个\无法读取文件

	if (in) {
		while (getline(in, input))
		{
			inp.push_back(input);
		}
	}

	for (const auto& s : inp)
		cout << s << endl;
}

输出:

在这里插入图片描述

练习8.5 重写上面的程序,将每个单词作为一个独立的元素进行存储

#include<fstream>
#include<string>
#include<vector>
using namespace std;
int main()
{
	string input;
	vector<string> inp;
	ifstream in("E:\\C++练习\\test8\\input.txt");
	if (in) {
		while (in >> input) {
			inp.push_back(input);
		}
	}
	for (const auto& s : inp)
		cout << s << endl;
}

在这里插入图片描述

练习8.6 重写7.1.1节的书店程序(第229页),从一个文件中读取交易记录。将文件名作为一个参数传递给main(参见6.2.5节,第196页)

头文件

#ifndef SALES_DATA_H
#define SALES_DATA_H
#include<iostream>
#include<vector>
#include<string>
using namespace std;
//声明
class Sales_data;
Sales_data add(const Sales_data& s1, const Sales_data& s2);    //执行两个Sales_data对象的加法
istream& read(istream& is, Sales_data& item);   //将数据从istream读入到Sales_data中
ostream& print(ostream& os, const Sales_data& item);  //将Sales_data对象的值输出到ostream

class Sales_data
{
	//友元
	friend Sales_data add(const Sales_data& s1, const Sales_data& s2);
	friend istream& read(istream& is, Sales_data& item);
	friend ostream& print(ostream& os, const Sales_data& item);

public:
	//构造默认内联函数
	Sales_data(const string& s, unsigned un, double re) :bookNo(s), units_sold(un), revenue(un* re) {};
	//委托构造函数
	Sales_data() :Sales_data(" ", 0, 0) {}             //赋一个空,初始化
	Sales_data(const string& s) :Sales_data(s, 0, 0) {}        //赋予书名字
	Sales_data(istream& is) :Sales_data() { read(is, *this); }   //委托给了默认构造参数变成了Sales_data(" ", 0, 0),之后再read

	Sales_data& combine(const Sales_data& s);    //用于将一个Sales_data对象加到另一个对象上,加个引用是为了能够改变原对象,不让其返回临时版本
	string isbn() const { return bookNo; }   //返回对象的ISBN编号

private:
	string bookNo;   //书名
	unsigned units_sold;   //书单价
	double revenue;     //总售价
	inline double avg_price()const;  //平均价格,内联函数
};

Sales_data& Sales_data::combine(const Sales_data& s)
{
	units_sold += s.units_sold;
	revenue += s.revenue;
	return *this;
}

Sales_data add(const Sales_data& s1, const Sales_data& s2)  //执行两个Sales_data对象的加法
{
	Sales_data sum = s1;
	sum.units_sold += s2.units_sold;
	sum.revenue += s2.revenue;
	return sum;
}

istream& read(istream& is, Sales_data& item)
{
	double price;
	is >> item.bookNo >> item.units_sold >> price;
	item.revenue = item.units_sold * price;
	return is;
}

ostream& print(ostream& os, const Sales_data& item)
{
	os << item.isbn() << " " << item.units_sold << " " << item.revenue << " " << item.avg_price();
	return os;
}

inline double Sales_data::avg_price()const
{
	double price = 0;
	price = (units_sold == 0) ? 0 : revenue / units_sold;
	return price;
}
#endif // ! SALES_DATA_H

主函数

#include<fstream>
#include<string>
#include<vector>
#include"Sales_data.h"
using namespace std;
int main(int argc, char** argv)
{
	ifstream ifs(argv[1]);

	if (!ifs) return 1;

	Sales_data total(ifs);

	if (!total.isbn().empty())
	{
		Sales_data trans; //当使用 argv 中的实参时, 一定要记得可选的实参从 argv[1] 开始; argv[0] 保存程序的名字, 而非用户输入

		while (read(ifs, trans))
		{
			if (total.isbn() == trans.isbn())
			{
				total.combine(trans);
			}
			else
			{
				print(cout, total);
				cout << endl;
				total = trans;
			}
		}
		print(cout, total);
		cout << endl;

		return 0;
	}
	else
	{
		cerr << "No data?!" << endl;
		return -1;  // indicate failure
	}
}

输出结果:

在这里插入图片描述

操作过程:第一步点属性

在这里插入图片描述

第二步:点调试后选择文件

在这里插入图片描述

文本内容:

在这里插入图片描述

8.2.2 文件模式

练习8.7 修改上一节的书店程序,将结果保存到一个文件中。将输出文件名作为第二个参数传递给main函数

#include<fstream>
#include<string>
#include<vector>
#include"Sales_data.h"
using namespace std;
int main(int argc, char** argv)
{
	ifstream input(argv[1]);  // "../data/book.txt"
	ofstream output("E:\\C++练习\\test8\\output.txt"); // "../data/out.txt"

	Sales_data total;
	if (read(input, total)) {
		Sales_data trans;
		while (read(input, trans)) {
			if (total.isbn() == trans.isbn())
				total.combine(trans);
			else {
				print(output, total) << endl;
				total = trans;
			}
		}
		print(output, total) << endl;
	}
	else {
		cerr << "No data?!" << endl;
	}
}

首先我新建一个E:\C++练习\test8\output.txt文档,并且内容如下:

在这里插入图片描述

运行程序后:结果存了进去

在这里插入图片描述

练习8.8 修改上一题的程序,将结果追加到给定的文件末尾。对用一个输出文件,运行程序至少两次,检验数据是否得到保留

#include<fstream>
#include<string>
#include<vector>
#include"Sales_data.h"
using namespace std;
int main(int argc, char** argv)
{
	ifstream input(argv[1]);  // "../data/book.txt"
	ofstream output("E:\\C++练习\\test8\\output.txt",ofstream::app); // 模式为输出和追加

	Sales_data total;
	if (read(input, total)) {
		Sales_data trans;
		while (read(input, trans)) {
			if (total.isbn() == trans.isbn())
				total.combine(trans);
			else {
				print(output, total) << endl;
				total = trans;
			}
		}
		print(output, total) << endl;
	}
	else {
		cerr << "No data?!" << endl;
	}
}

原先txt内容:

在这里插入图片描述

运行一次后:

在这里插入图片描述

运行两次后:

在这里插入图片描述

8.3 string流

8.3.1 使用istringstream

练习8.9 使用你为8.1.2节(第281页)第一个练习所编写的函数打印一个istringstream对象的内容

#include<sstream>
#include<string>
#include<fstream>
using namespace std;

istream& input(istream& is)
{
	string s;
	while (is >> s)
		cout << s << endl;
	is.clear();
	return is;
}

int main()
{
	istringstream s("aa\nbb\ncc\ndd");
	input(s);
}

在这里插入图片描述

练习8.10 编写程序,将来自一个文件中的行保存在一个vector中。然后使用一个istringstream从vector读取数据元素,每次读取一个单词。

文档内容:

在这里插入图片描述

主程序

#include<string>
#include<vector>
#include<fstream>
#include<sstream>
using namespace std;

int main()
{
	ifstream in("E:\\C++练习\\test8\\8.10.txt");
	string str;
	vector<string> hold;

	while (getline(in, str)) {
		hold.push_back(str);
	}

	for (auto i : hold) {
		istringstream record(i);
		while (record >> str)
			cout << str << endl;
	}
}

运行结果:

在这里插入图片描述

练习8.11 本节的程序在外层while循环中定义了istringstream对象。如果record对象定义在循环之外,你需要对程序进行怎样的修改?

重写程序,将record的定义移到while循环之外,验证你设想的修改方法是否正确。

#include<string>
#include<vector>
#include<fstream>
#include<sstream>
using namespace std;
struct PersonInfo {
	string name;
	vector<string> phones;
};

int main()
{
	string line, word;
	vector<PersonInfo>peoples;
	istringstream record;
	while (getline(cin, line)) {
		PersonInfo people;
		record.str(line);
		record >> people.name;
		while (record >> word) {
			people.phones.push_back(word);
		}
		record.clear();
		peoples.push_back(people);
	}
}

练习8.12 我们为什么没有在PersonInfo中使用类内初始化?

string和vector可以自己初始化,并不会出现未定义的情况。

8.3.2 使用ostringstream

练习8.13 重写本节的电话号码程序,从一个命名文件而非cin读取数据

在这里插入图片描述

#include<string>
#include<vector>
#include<fstream>
#include<sstream>
using namespace std;
struct PersonInfo {
	string name;
	vector<string> phones;
};

bool valid(const string& s)
{
	for (const auto c : s)
		if (!isdigit(c)) return false;
	return true;
}

string format(const string& s)
{
	return s;
}

int main()
{
	ifstream in("E:\\C++练习\\test8\\phones.txt");
	string line, word;
	vector<PersonInfo>peoples;
	istringstream record;
	while (getline(in, line)) {
		PersonInfo people;
		record.str(line);
		record >> people.name;
		while (record >> word) {
			people.phones.push_back(word);
		}
		record.clear();
		peoples.push_back(people);
	}

	for (const auto& entry : peoples) {
		ostringstream formatted, badNums;
		for (const auto& nums : entry.phones) {
			if (!valid(nums)) {
				badNums<<" "<<nums;
			}
			else {
				formatted << " " << format(nums);
			}
		}
		if (badNums.str().empty())
			cout << entry.name << " " << formatted.str() << endl;
		else
			cerr << "input error:" << entry.name << "invalid numbers(s)" << badNums.str() << endl;
	}
}

在这里插入图片描述

练习8.14 我们为什么将entry和nums定义为 const auto & ?

它们都是类类型,因此使用引用避免拷贝,提高了效率;在循环当中不会改变它们的值,因此用const。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Is_LiuYiZheng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值