啦啦啦,断更了大半年,我胡汉三又回来了。这次争取一周更一章,把这本书的笔记更完。
从第8章到第12章主要是介绍标准库的一些相关知识。第8章主要介绍的是IO库。
IO库定义了一些输入输出类型,我们能够通过这些类型具体的对象完成输入输出。
iostream定义了用于读写流的基本类型,fstream定义了读写命名文件的类型,sstream定义了读写内存string对象的类型。
标准库定义了一组类型和对象来操纵wchar_t类型的数据。宽字符版本的类型和函数以一个w开始。所谓宽字符可见:宽字符
不能拷贝或对IO对象赋值,所以不能将形参或返回类型设为流类型,可以设为引用类型。
IO库定义了一个与机器无关的iostate类型,它提供了表达流状态的完整功能,这个类型应作为一个位集合来使用。
每个输出流都管理一个缓冲区,所以输出不一定立即打印,可能会先存在缓冲区中。endl可以刷新缓冲。flush和ends也有类似的效果。 可以直接使用unitbuf操作符告诉流每次输出都刷新缓冲区。
标准库将cin和cout关联在一起,因此在使用cin的时候cout的缓冲区会被刷新。
tie函数可以将流之间关联。
头文件fstream定义了三个流来读写文件,可以按照IO的方式<<>>来读写文件(因为其继承的是iostream)。
对于形参是istream&和ostream&的函数,我们可以传ifstream和ofstream。
对于每个流打开时都可以关联相应的文件模式,如果没有关联会有默认的文件模式。
sstream定义了三个类型来支持对内存的string进行IO。
标准库中主要定义了三个流来进行IO操作。iostream处理控制台IO;fstream处理命名文件IO;stringstream处理内存string的IO。后面两个继承自第一个。所以第一个的操作后面两个也是可以用的。例如>><<,限制也一样存在,在>><<中遇到空格和换行会进行下一条输入输出。两个最主要的点就在于这三个IO都可以方便的使用操作符进行操作且有对应的函数判断操作的状态,二是要理解流的含义,即从流中输入,输出到流中,具体与控制台或者文件或者内存string是通过流来交互的。
部分答案参考:答案
8.1 8.2
#include
std::istream& func(std::istream& temp) {
std::string buf;
while (!temp.eof()) {
temp>>buf;
std::cout << buf << std::endl;
}
temp.clear();
return temp;
}
int main() {
func(std::cin);
return 0;
}
8.3
遇到了文件结束符,或者遇到了 IO 流错误,或者读入了无效数据。
8.4
#include
#include
#include
int main() {
std::ifstream in("/home/watson/test.txt");
std::string temp;
std::vector<std::string> vec;
if (!in) {
std::cerr << "读取文件错误" << std::endl;
return 0;
}
while (getline(in, temp)) {
vec.push_back(temp);
}
for (auto &str : vec) {
std::cout << str << std::endl;
}
return 0;
}
8.5
将8.4中程序的getline(in, temp)改为in>>temp
8.6
头文件见练习7.26
输入文件内容为:
0-201-78345-X 3 20.00 19.00
0-201-78345-X 4 20.00 19.00
0-202-78345-X 4 30.00 29.00
0-202-78345-Y 2 200.00 199.00
#include "Sales_data.h"
#include
using namespace std;
int main(int argc, char* argv[]) {
if (argc < 2) {
cerr << "请输入文件路径" << endl;
}
ifstream in(argv[1]);
if (!in) {
cerr << "文件读取失败" << endl;
return 0;
}
Sales_data total; // 保存当前求和结果的变量
if (total.read(in, total)) { // 读入第一笔交易记录
Sales_data trans; // 保存下一条交易数据的变量
while (trans.read(in, trans)) { // 读入剩余的交易
if (total.isbn() == trans.isbn()) // 检查 isbn
total = total.add(total, trans); // 更新变量 total 当前的值
else {
total.print(cout, total) << endl; // 输出结果
total = trans; // 处理下一本
}
}
total.print(cout, total) << endl; // 输出最后一条交易
}
else { // 没有输入任何信息
cerr << "没有数据" << endl; // 通知用户
return -1;
}
return 0;
}
8.7
#include
#include
#include "Sales_data.h"
using namespace std;
int main(int argc, char *argv[]) {
if (argc != 3) {
cerr << "文件数量不对" << endl;
return -1;
}
ifstream in(argv[1]);
if (!in) {
cerr << "无法打开输入文件" << endl;
return -1;
}
ofstream out(argv[2]);
if (!out) {
cerr << "无法打开输出文件" << endl;
return -1;
}
Sales_data total; // 保存当前求和结果的变量
if (total.read(in, total)) { // 读入第一笔交易记录
Sales_data trans; // 保存下一条交易数据的变量
while (trans.read(in, trans)) { // 读入剩余的交易
if (total.isbn() == trans.isbn()) // 检查 isbn
total = total.add(total, trans); // 更新变量 total 当前的值
else {
total.print(out, total) << endl; // 输出结果
total = trans; // 处理下一本
}
}
total.print(out, total) << endl; // 输出最后一条交易
}
else { // 没有输入任何信息
cerr << "没有数据" << endl; // 通知用户
return -1;
}
return 0;
}
8.8
将ofstream out(argv[2]);改为ofstream out(argv[2], ofstream::app);
8.9
#include
#include
std::istream& func(std::istream& temp) {
std::string buf;
while (!temp.eof()) {
temp>>buf;
std::cout << buf << std::endl;
}
temp.clear();
return temp;
}
int main() {
std::string str = "hello world";
std::istringstream in(str);
func(in);
return 0;
}
8.10
#include
#include
#include
#include
using namespace std;
int main() {
ifstream in("input.txt");
vector<string> vec;
string line;
while (getline(in, line)) {
vec.push_back(line);
}
in.close();
for (auto &str : vec) {
istringstream in(str);
string temp;
while (in >> temp) {
cout << temp << " ";
}
cout << endl;
}
return 0;
}
8.11
#include
#include
#include
#include
using namespace std;
struct PersonInfo {
string name;
vector<string> phones;
};
int main() {
string line, word; // 分别保存来自输入的一行和单词
vector<PersonInfo> people; // 保存来自输入的所有记录
istringstream record;
// 逐行从输入读取数据,直至 cin 遇到文件尾(或其他错误)
while (getline(cin, line) && line != "Q") {
PersonInfo info; // 创建一个保存此记录数据的对象
record.clear(); // 重复使用字符串流时,每次都要调用 clear
record.str(line); // 将记录绑定到刚读入的行(将 line 拷贝到 record 中)
record >> info.name; // 读取名字
while (record >> word) // 读取电话号码
info.phones.push_back(word); // 保持它们
people.push_back(info); // 将此记录追加到 people 末尾
}
for (auto &p : people) {
cout << p.name << " ";
for (auto &s : p.phones)
std::cout << s << " ";
cout << endl;
}
return 0;
}
8.12
电话号码数量不确定
8.13 8.14
答案