第 8 章

8.1

#include <iostream>
using namespace std;

istream& func(istream &is)
{
    std::string buf;
    while (is >> buf)
        std::cout << buf << std::endl;
    is.clear();
    return is;
}

int main() {
    cout << "请输入一些整数,按 Ctrl+Z 结束" << endl;
    func(cin);

    return 0;
}
// 运行结果
// 32 4 5
// 3 sffd f
// Ctrl+Z(macOS 用户 commad+D)
// 以上三行是用户输入的测试数据,第三个数据是快捷键。
请输入一些整数,按 Ctrl+Z 结束
32 4 5
32
4
5
3 sffd f
3
sffd
f
^D

Process finished with exit code 0

8.2

上题已实现

8.3

【出题思路】

进一步理解流的状态的检测方式。

【解答】

遇到了文件结束符,或者遇到了 IO 流错误,或者读入了无效数据。

8.4

【出题思路】

本题练习文件输入和流的逐行输入,还练习了使用迭代器遍历容器中的元素。

【解答】

创建文件 data,并向其中写入测试数据。我这里写入的是:

C++ Primer
5th

main.cpp

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

using namespace std;

int main() {
    // ../data 为文件data的文件名及其相对路径(是相对于可执行程序所在目录的相对路径)
    ifstream in("../data");         // 打开文件
    if (!in) {
        cerr << "无法打开输入文件" << endl;
        return -1;
    }

    string line;
    vector<string> words;
    while (getline(in, line))       // 从文件中读取一行
        words.push_back(line);      // 添加到 vector 中

    in.close();                     // 输入完毕,关闭文件

    vector<string>::const_iterator it = words.begin();  // 迭代器
    while (it != words.end()) {     // 遍历 vector
        cout << *it << endl;        // 输出 vector 中的元素
        ++it;
    }

    return 0;
}
// 运行结果
C++ Primer
5th

Process finished with exit code 0

【其他解题思路】

vector 的遍历还可使用范围 for 循环来实现。程序如下所示:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

using namespace std;

int main() {
    ifstream in("../data");
    if (!in) {
        cerr << "无法打开输入文件" << endl;
        return -1;
    }

    string line;
    vector<string> words;
    while (getline(in, line))
        words.push_back(line);

    in.close();

    for (auto str : words)
        cout << str << endl;

    return 0;
}
// 运行结果
C++ Primer
5th

Process finished with exit code 0

8.5

【出题思路】

本题练习逐个数据的输入方式。

【解答】

将练习 8.5 中的 while (getline(in, line)) 改为 while (in >> line) 即可,其它保持不变。修改后的程序执行结果如下所示:

// 运行结果
C++
Primer
5th

Process finished with exit code 0

8.6

【出题思路】

通过一个较大的例子继续练习文件输入,并练习从命令行获取参数及参数合法性的检测。

【解答】

Sales_data.h 头文件代码与练习 7.7 一样。

main.cpp 代码如下所示:

#include <iostream>
#include <fstream>
#include "Sales_data.h"
using namespace std;

int main(int argc, char *argv[]) {
    if (argc != 2) {
        cerr << "请给出文件名" << endl;
        return -1;
    }
    ifstream in(argv[1]);
    if (!in) {
        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(cout, total) << endl;    // 输出结果
                total = trans;                 // 处理下一本
            }
        }
        total.print(cout, total) << endl;            // 输出最后一条交易
    }
    else {                              // 没有输入任何信息
        cerr << "没有数据" << endl;    // 通知用户
        return -1;
    }
    return 0;
}

运行程序前,在 CLion -> Run -> Edit Configurations 下配置 Program arguments 为 ../temp

注:../temp 即为文件 temp 的文件名及其相对路径(是相对于可执行程序所在目录的相对路径)。

并在文件 temp 中写入如下内容(文件 temp 与 main.cpp 在同一目录下):

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

运行程序,程序执行结果如下所示:

/Users/macOS/CLionProjects/test/cmake-build-debug/test ../temp
0-201-78345-X 7 20 19 0.95
0-202-78345-X 4 30 29 0.966667
0-202-78345-Y 2 200 199 0.995

Process finished with exit code 0

注:可参考练习 6.26

8.7

【出题思路】

本题练习文件输出。

【解答】

Sales_data.h 文件代码同 8.6

main.cpp 代码如下所示:

#include <iostream>
#include <fstream>
#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;
}

运行程序前,在 CLion -> Run -> Edit Configurations 下配置 Program arguments 为 ../temp ../temp2

注:../temp ../temp2 即为文件 temp 和 temp2 的文件名及其相对路径(是相对于可执行程序所在目录的相对路径)。

并在文件 temp 中写入如下内容:

  • temp

    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
  • temp2 内容为空

程序执行后两文件内容为:

  • temp

    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
  • temp2
    0-201-78345-X 7 20 19 0.95
    0-202-78345-X 4 30 29 0.966667
    0-202-78345-Y 2 200 199 0.995
    

接着我们运行程序两次,观察 temp 和 temp2 文件内容。如下所示:

  • temp

    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
  • temp2
    0-201-78345-X 7 20 19 0.95
    0-202-78345-X 4 30 29 0.966667
    0-202-78345-Y 2 200 199 0.995
    

    注:temp2 文件内容没变

8.8

【出题思路】

本题练习文件的追加模式。

【解答】

将上一题程序中代码 ofstream out(argv[2]); 改为 ofstream out(argv[2], ofstream::app);

运行程序前,在 CLion -> Run -> Edit Configurations 下配置 Program arguments 为 ../temp ../temp2

注:../temp ../temp2 即为文件 temp 和 temp2 的文件名及其相对路径(是相对于可执行程序所在目录的相对路径)。

并在文件 temp 中写入如下内容:

  • temp

    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
  • temp2 内容为空

程序执行后两文件内容为:

  • temp

    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
  • temp2
    0-201-78345-X 7 20 19 0.95
    0-202-78345-X 4 30 29 0.966667
    0-202-78345-Y 2 200 199 0.995
    

接着我们运行程序两次,观察 temp 和 temp2 文件内容。如下所示:

  • temp

    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
  • temp2
    0-201-78345-X 7 20 19 0.95
    0-202-78345-X 4 30 29 0.966667
    0-202-78345-Y 2 200 199 0.995
    0-201-78345-X 7 20 19 0.95
    0-202-78345-X 4 30 29 0.966667
    0-202-78345-Y 2 200 199 0.995
    0-201-78345-X 7 20 19 0.95
    0-202-78345-X 4 30 29 0.966667
    0-202-78345-Y 2 200 199 0.995
    

    注:temp2 实现了程序执行结果的追加

8.9

【出题思路】

本题练习字符串流的输入。

【解答】

#include <iostream>
#include <sstream>
#include <string>
#include <stdexcept>

using namespace std;

istream &f(istream &in) {
    string v;
    while (in >> v, !in.eof()) {
        if (in.bad())
            throw runtime_error("IO 流错误");
        if (in.fail()) {
            cerr << "数据错误,请重试" << endl;
            in.clear();
            in.ignore(100, '\0');
            continue;
        }
        cout << v << endl;
    }
    in.clear();
    return in;
}

int main() {
    ostringstream msg;
    msg << "C++ Primer 第五版" << endl;
    istringstream in(msg.str());
    f(in);
    return 0;
}
// 运行结果
C++
Primer
第五版

Process finished with exit code 0

8.10

【出题思路】

本题继续练习字符串流的输入。

【解答】

main.cpp

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

int main() {
    ifstream in("../data");     // 打开文件
    if (!in) {
        cerr << "无法打开输入文件" << endl;
        return -1;
    }

    string line;
    vector<string> words;
    while (getline(in, line))           // 从文件中读取一行
        words.push_back(line);          // 添加到 vector 中

    in.close();                         // 输入完毕,关闭文件

    vector<string>::const_iterator it = words.begin();  // 迭代器
    while (it != words.end()) {         // 遍历 vector
        istringstream line_str(*it);
        string word;
        while (line_str >> word)        // 通过 istringstream 从 vector 中读取数据
            cout << word << '\n';
        ++it;
    }

    return 0;
}
// 运行结果
C++
Primer
5th

Process finished with exit code 0

注:文件 data 与 main.cpp 文件在同一目录下。文件 data 内容为:

C++ Primer 5th

8.11

【出题思路】

本题练习字符串流的重复使用,每次通过 str 成员将流绑定到不同的字符串,同时还要调用 clear 来重置流的状态。

【解答】

#include <iostream>
#include <sstream>
#include <string>
#include <vector>

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;
}
// zhangsan 23443 34432
// lisi 23423434
// wangwu 234324
// Q
// 上面四行是从控制台输入的测试数据,Q 用于结束输入
// 运行结果
zhangsan 23443 34432
lisi 23423434
wangwu 234324
Q
zhangsan 23443 34432
lisi 23423434
wangwu 234324 

Process finished with exit code 0

8.12

【出题思路】

体会根据应用特点决定程序设计策略。

【解答】

由于每个人的电话号码数量不固定,因此更好的方式不是通过类内初始化指定人名和所有电话号码,而是在缺省初始化之后,在程序中设置人名并逐个添加电话号码。

8.13

【出题思路】

本题练习文件流和字符串流输入输出的综合应用。

【解答】

运行程序前,在 CLion -> Run -> Edit Configurations 下配置 Program arguments 为 ../data

注:../data 即为输入文件的文件名及其相对路径(是相对于可执行程序所在目录的相对路径)。

并在文件 data 中写入如下内容:

  • data

    zhangsan 23443 34432
    lisi 23423434
    wangwu 234324

main.cpp

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

struct PersonInfo {
    string name;
    vector<string> phones;
};

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

bool valid(const string &s) {
    // 如何验证电话号码将在第 17 章介绍
    // 现在简单返回 true
    return true;
}

int main(int argc, char *argv[]) {
    string line, word;              // 分别保存来自输入的一行和单词
    vector<PersonInfo> people;      // 保存来自输入的所有记录
    istringstream record;

    if (argc != 2) {
        cerr << "请给出文件名" << endl;
        return -1;
    }
    ifstream in(argv[1]);
    if (!in) {
        cerr << "无法打开输入文件" << endl;
        return -1;
    }

    // 逐行从输入读取数据,直至 cin 遇到文件尾(或其他错误)
    while (getline(in, line)) {
        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 末尾
    }

    ostringstream os;
    for (const auto &entry : people) {  // 对 people 中每一项
        ostringstream formatted, badNums;   // 每个循环步创建的对象
        for (const auto &nums : entry.phones) {     // 对每个数
            if (!valid(nums))
                badNums << " " << nums;     // 将数的字符串形式存入 badNums
            else
                // 将格式化的字符串"写入" formatted
                formatted << " " << format(nums);
        }
        if (badNums.str().empty())      // 没有错误的数
            // 打印名字和格式化的数
            os << entry.name << " " << formatted.str() << endl;
        else
            // 否则,打印名字和错误的数
            cerr << "input error: " << entry.name
            << " invalid numbers(s) " << badNums.str() << endl;
    }
    cout << os.str() << endl;

    return 0;
}
// 运行结果
zhangsan  23443 34432
lisi  23423434
wangwu  234324

Process finished with exit code 0

8.14

【出题思路】

回顾范围 for 语句的相关内容。

【解答】

这两条语句分别使用范围 for 语句枚举 people 中所有项(人)和每项的 phones 中的所有项(电话号码)。使用 const 表明在循环中不会改变这些项的值:auto 是请求编译器依据 vector 元素类型来推断出 entry 和 nums 的类型,即简化代码又避免出错。

使用引用的原因是,people 和 phones 的元素分别是结构对象和字符串对象,使用引用可避免对对象的拷贝。

原文地址:https://www.cnblogs.com/kafffka/p/11132832.html

时间: 2024-10-16 09:43:35

第 8 章的相关文章

C#认证第一章1 题 11题

C#第一章第一题 C#认证第一章  11题

C#图解教程 第二十四章 反射和特性

反射和特性元数据和反射Type 类获取Type对象什么是特性应用特性预定义的保留的特性Obsolete(废弃)特性Conditional特性调用者信息特性DebuggerStepThrough 特性其他预定义特性有关应用特性的更多内容多个特性其他类型的目标全局特性自定义特性声明自定义特性使用特性的构造函数指定构造函数使用构造函数构造函数中的位置参数和命名参数限制特性的使用自定义特性的最佳实践访问特性使用IsDefined方法使用GetCustomAttributes方法 Note 类的元数据包含

【机器学习实战】第2章 K-近邻算法(k-NearestNeighbor,KNN)

第2章 k-近邻算法 <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=default"></script> KNN 概述 k-近邻(kNN, k-NearestNeighbor)算法主要是用来进行分类的. KNN 场景 电影可以按照题材分类,那么如何区分 动作片 和 爱情片 呢? 动作片:打斗次数更多 爱情片

计算机网络安全第一章

计算机网络不安全因素:偶发因素.自然因素.认为因素(被动攻击.主动攻击.邻近攻击.内部人员攻击.分发攻击) 不安全的主要原因: 1.互联网具有不安全性:开放的网络,国际性的网络,自由性的网络 2.操作系统存在的安全问题:操作系统软件自身的不安全性,留下"后门".操作 系统体系结构造成的不安全隐患.操作系统可以创建进程.操作系统的无口令入口及隐蔽通道 3.数据安全问题 4.传输线路安全问题 5.网络应用存在的安全问题 6.网络安全管理问题 计算机网络安全是一门涉及计算机科学.网络技术.通

数据库系统实现 第六章 查询执行

第六章 查询执行 查询执行也就是操作数据库的算法 一次查询的过程: 查询-->查询编译(第七章)-->查询执行(第六章)-->数据 查询编译预览 查询编译可以分为三个步骤: a)分析:构造分析树,用来表达查询和它的结构 b)查询重写,分析树被转化为初始查询计划,通常是代数表达式,之后初始的查询计划会被优化为一个时间更小的计划 c)物理计划生成,将查询计划转化成物理的计划, 为了选择更好的查询计划,需要判断 1)查询哪一个代数的等价形式是最有效的 2)对选中形式的每一个操作,所使用的算法选

Java编程思想读书笔记_第三章

本章提到的关于==的部分,一个完整的实验如下: 1 class Test { 2 public static void main(String[] args) { 3 Integer i = new Integer(47); 4 Integer j = new Integer(47); 5 Integer i1 = 47; 6 Integer j1 = 47; 7 int i2 = new Integer(47); 8 int j2 = new Integer(47); 9 int i3 = 4

第九章、文件与文件系统的压缩与打包

1. 压缩文件的用途与技术 2. Linux 系统常见的压缩命令 2.1 compress 2.2 gzip, zcat 2.3 bzip2, bzcat 3. 打包命令: tar 4. 完整备份工具:dump, restore 5. 光盘写入工具 5.1 mkisofs:创建映像档 5.2 cdrecord:光盘烧录工具 6. 其他常见的压缩与备份工具 6.1 dd 6.2 cpio 7. 重点回顾 1. 压缩文件的用途与技术 2. Linux 系统常见的压缩命令 压缩文件的扩展名大多是:『*

《TCP/IP具体解释》读书笔记(22章)-TCP的坚持定时器

TCP通过让接收方指明希望从发送方接收的数据字节数(即窗体大小)来进行流量控制. 假设窗体大小为0会发生什么情况呢?这将有效阻止发送方传送数据,直到窗体变为非0为止. ACK的传输并不可靠,也就是说,TCP不正确ACK报文段进行确认,TCP仅仅确认那些包括有数据的ACK报文段. 1.坚持定时器 假设一个场景:假设一个确认丢失了,则两方就有可能由于等待对方而使连接终止,接收方等待接收数据(由于它已经向发送方通告了一个非0的窗体),而发送方在等待同意它继续发送数据的窗体更新.为防止这种死锁情况的发生

第三章随笔

本章为软件工程师的成长,主要介绍了评价软件工程师水平的主要方法,技能的反面,TSP对个人的要求. 软件开发流程:软件开发流程包括团队的流程,也包括个人的流程 初级软件工程师有几方面成长: 1.积累软件开发相关的知识,提升技术技能2.积累问题领域的知识和经验3.对通用的软件设计思想和软件工程思想的理解4.提升职业技能5.实际成果 衡量软件开发的工作量和质量的因素: 1.项目/任务有多大2.花了多少时间3.质量如何4.是否按时交付 相对来说,交付时间的平均时间反应平均水平,而标准方差更为重要,在团队

java第15章示例代码

import java.util.Scanner; /** * * @author asus第15章示例代码1 全桂群2017.4.9 * */public class Registter { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Scanner input = new Scanner(System.in); String uname, pw