C++ Primer (第五版) 课后习题 Unit8

8.1.2节练习

练习8.1:


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


#include <iostream>
using namespace std;

istream& func(istream & is){
    string buf;
    while(is>>buf)
        cout<<buf<<endl;
    is.clear();
    return is;
}
int main() {
    func(cin);
    return 0;
}

练习8.2

问题:测试函数,调用参数为cin


练习8.3

问题:什么情况下,下面的while循环会终止?

while(cin>>i) /*...*/


当failbit  或者badbit  或者 eofbit 为1时,会终止。

8.2.1节练习

练习8.4

问题:编写函数,以读模式打开一个文件,将其内容读入到一个stringvector中,将每一行作为一个独立的元素存于vector中。


void read_line(const string &filename,vector<string> &vec){
    //创建一个文件流
    ifstream ifs;
    ifs.open(filename);
    //判断是否文件打开成功
    if(ifs) {
        cout<<"Open file successfully"<<endl;
        while (!ifs.eof()) {
            //定义一个临时变量,用来读取数据并将数据传入到vector中
            string temp;
            getline(ifs, temp);
            vec.push_back(temp);
        }
    }
}

练习8.5

问题:重写上面的程序,将每个单词作为一个独立的元素进行存储。 解:


void read_words(const string &filename,vector<string> &vec){
    //创建一个文件流
    ifstream ifs;
    ifs.open(filename);
    //判断是否文件打开成功
    if(ifs) {
        cout << "Open file successfully" << endl;
        while (!ifs.eof()) {
            //定义一个临时变量,用来读取数据并将数据传入到vector中
            string temp;
            ifs >> temp;
            vec.push_back(temp);
        }
    }
}

练习8.6

问题:重写7.1.1节的书店程序,从一个文件中读取交易记录。将文件名作为一个参数传递给main


这个问题我在自己写的时候遇到了一些问题。之后参考github上的代码:

Sales_data.h

//
// Created by YUSEN JIA on 2020/10/19.
//

#ifndef C__P_U8_8_6_2__SALES_DATA_H
#define C__P_U8_8_6_2__SALES_DATA_H
#include <string>
#include <iostream>

class Sales_data {
    friend std::istream &read(std::istream &is, Sales_data &item);
    friend std::ostream &print(std::ostream &os, const Sales_data &item);
    friend Sales_data add(const Sales_data &lhs, const Sales_data &rhs);

public:
    Sales_data() = default;
    Sales_data(const std::string &s):bookNo(s) { }
    Sales_data(const std::string &s, unsigned n, double p):bookNo(s), units_sold(n), revenue(n*p){ }
    Sales_data(std::istream &is) { read(is, *this); }

    std::string isbn() const { return bookNo; };
    Sales_data& combine(const Sales_data&);

private:
    inline double avg_price() const;

private:
    std::string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;
};

inline
double Sales_data::avg_price() const
{
    return units_sold ? revenue/units_sold : 0;
}

// declarations for nonmember parts of the Sales_data interface.
std::istream &read(std::istream &is, Sales_data &item);
std::ostream &print(std::ostream &os, const Sales_data &item);
Sales_data add(const Sales_data &lhs, const Sales_data &rhs);

#endif //C__P_U8_8_6_2__SALES_DATA_H

Sales_data.cpp

//
// Created by YUSEN JIA on 2020/10/19.
//

#include "Sales_data.h"

// member functions.
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
    units_sold += rhs.units_sold;
    revenue += rhs.revenue;
    return *this;
}

// friend functions
std::istream &read(std::istream &is, Sales_data &item)
{
    double price = 0;
    is >> item.bookNo >> item.units_sold >> price;
    item.revenue = price * item.units_sold;
    return is;
}

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

Sales_data add(const Sales_data &lhs, const Sales_data &rhs)
{
    Sales_data sum = lhs;
    sum.combine(rhs);
    return sum;
}

main.cpp

#include <fstream>
#include <iostream>
#include"Sales_data.h"

using std::ifstream; using std::cout; using std::endl; using std::cerr;

int main(int argc, char **argv)
{
    ifstream input(argv[1]);

    Sales_data total;
    if (read(input, total))
    {
        Sales_data trans;
        while (read(input, 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;
}

最后通过input文件,将要输入的参数放到input中即可。

 

8.2.2节练习

练习8.7

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


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

int main(int argc,char * argv[]) {

    ifstream input(argv[1]);
    ofstream output;
    output.open(argv[2]);
    Sales_data total;
    if(input){
        Sales_data trans;
        while(read(input,trans)){

                print(output, trans) << endl;

            }
    }
    else{
        cerr<<"No data!"<<endl;
    }
    return 0;
}

将上一节main程序修改成这个

练习8.8:

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


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

int main(int argc,char * argv[]) {

    ifstream input(argv[1]);
    ofstream output;
    output.open(argv[2],ofstream::app);
    Sales_data total;
    if(input){
        Sales_data trans;
        while(read(input,trans)){

                print(output, trans) << endl;

            }
    }
    else{
        cerr<<"No data!"<<endl;
    }
    return 0;
}

这次给output加上app模式

最终连续运行程序两次后输出的结果:

可以看到上一次数据得到了保留

8.3.1节练习

练习8.9

问题:使用你为8.1.2节第一个练习所编写的函数打印一个istringstream对象的内容。


#include <iostream>
#include<sstream>
using std::istream,std::cout,std::string,std::endl,std::cin;
using std::istringstream;

istream& func(istream & is){
    string buf;
    while(is>>buf)
        cout<<buf<<" ";
    is.clear();
    return is;
}
int main() {
    string ss("hello");
    istringstream is(ss);
    func(is);
    return 0;
}

练习8.10

问题:编写程序,将来自一个文件中的行保存在一个vector中。然后使用一个istringstreamvector读取数据元素,每次读取一个单词。


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

istream &read(istream &is,vector<string> &vec){
    string temp;
    getline(is,temp);
    vec.push_back(temp);
    return is;
}

int main() {
    vector<string> line;
    ifstream input("C++p_u8_8.10/input");//这里是存放input的路径
    if(input){
        while(read(input,line)){}
    }
    for(auto i=line.begin();i!=line.end();i++){
        istringstream a(*i);
        string buf;
        a>>buf;
        cout<<buf<<endl;
    }

    return 0;
}

练习8.11

问题:本节的程序在外层while循环中定义了istringstream对象。如果record对象定义在循环之外,你需要对程序进行怎样的修改?重写程序,将record的定义移到while循环之外,验证你设想的修改方法是否正确


#include <iostream>
#include "PersonInfo.h"
#include<sstream>
using std::string;
using std::vector;
using std::cin;
using std::cout,std::istringstream;

int main() {
    string line,word;
    vector<PersonInfor> people;
    istringstream record;
    while(getline(cin,line) ){
        PersonInfor info;
        record.clear();//因为是继承自iostream,这里的clear是将流中所有的条件状态位复位,将流的状态设置为有效。
        record.str(line);
        record>>info.name;
        while(record>>word){
            info.phones.push_back(word);
        }
        people.push_back(info);
    }
    for(auto i:people){
        i.print();
    }
    return 0;
}

如果这里缺少了clear,那么只能输出一行的值。需要每次对输入流复位。

练习8.12

问题:我们为什么没有在PersonInfo中使用类内初始化?


答:因为这里只是需要聚合类,没必要对其类内初始化。

 

8.3.2节练习

练习8.13

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


main.cpp

#include <iostream>
#include "PersonInfo.h"
#include<sstream>
#include<fstream>
using std::string;
using std::vector;
using std::cin;
using std::cout,std::istringstream;
using std::istream;
using std::ifstream;


istream &read(istream &is,string &copy){
    getline(is,copy);
    return is;
}

int main() {
    ifstream input("/Users/jason/CLionProjects/C++p_u8_8.13/input");
    string line,word;
    vector<PersonInfor> people;
    istringstream record;
    while(read(input,line) ){
        PersonInfor info;
        record.clear();//因为是继承自iostream,这里的clear是将流中所有的条件状态位复位,将流的状态设置为有效。
        record.str(line);
        record>>info.name;
        while(record>>word){
            info.phones.push_back(word);
        }
        people.push_back(info);
    }
    for(auto i:people){
        i.print();
    }
    return 0;
}

PersonInfo.cpp

#include "PersonInfo.h"
void PersonInfor::print()const{
    std::cout<<"name:"<<this->name<<std::endl;
    std::cout<<"Phone number:";
    for(auto phone : this->phones){
        std::cout<<phone<<std::endl;
    }
    std::cout<<std::endl;
}

PersonInfo.h

#include<iostream>
#include<vector>
#include<sstream>
struct PersonInfor{
    void print()const;

    std::string name;
    std::vector<std::string> phones;
};

练习8.14

问题:我们为什么将entrynums定义为const auto&


答:因为我们不希望修改people中的值,所以这里使用const。因为是类类型,避免拷贝,所以使用了引用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值