C++ Primer Plus章节编程练习第十七章

1

题目

  编写一个程序计算输入流中第一个$之前的字符数目,并将$留在输入流中。

题解

#include<iostream>
using namespace std;
int main(){
    int cnt=0;
    while(cin.peek()!='$'){
        cin.get();
        cnt++;
    }
    cout<<"You have input "<<cnt<<" characters before '$'"<<endl;
    return 0;
}

2

题目

  编写一个程序,将键盘输入(直到模拟的文件尾)复制到通过命令行指定的文件中。

题解

#include<iostream>
#include<fstream>
int main(){
    using namespace std;
    fstream file;
    string filename;
    cout<<"Enter the file name you want to write to: ";
    getline(cin,filename);
    file.open(filename.c_str(),ios_base::out);
    char ch;
    cout<<"Enter what yout want to write to the file \""<<filename<<"\""<<endl;
    while(cin.peek()!=EOF){
        ch=cin.get();
        file<<ch;
    }
    file.close();
    cout<<"Done!"<<endl;
    return 0;
}

3

题目

  编写一个程序,将一个文件复制到另一个文件中。让程序通过命令行获取文件名。如果文件无法打开,程序将指出这一点。

题解

#include<iostream>
#include<fstream>
int main(){
    using namespace std;
    ifstream fin;
    ofstream fout;
    string fin_name,fout_name;
    cout<<"Enter the file name of input file: "<<endl;
    getline(cin,fin_name);
    cout<<"Enter the file name of output file: "<<endl;
    getline(cin,fout_name);
    fin.open(fin_name.c_str(),ios_base::in);
    if(!fin.is_open()) cout<<"input file open error!"<<endl;
    fout.open(fout_name.c_str(),ios_base::out);
    if(!fout.is_open()) cout<<"output file open error!"<<endl;
    while(fin.peek()!=EOF){
        char ch=fin.get();
        fout<<ch;
    }
    fin.close();
    fout.close();
    cout<<"Done!"<<endl;
    return 0;
}

4

题目

  编写一个程序,它打开两个文本文件进行输入,打开一个文本文件进行输出。该程序将两个输入文件中对应的行并接起来,并用空格分隔,然后将结果写入到输出文件中。如果一个文件比另一个短,则将较长文件中余下的几行直接复制到输出文件中。例如,假设第一个输入文件的内容如下:

eggs kites donuts
balloons hammers
stones

  而第二个输入文件的内容如下:

zero lassi tude
finance drama

  则得到的文件的内容将如下:

eggs kites donuts zero lassitude
balloons hammers finance drama
stones

题解

#include<iostream>
#include<fstream>
int main(){
    using namespace std;
    //分别打开三个文件
    fstream file1,file2,file3;
    file1.open("4_file1.txt",ios_base::in);
    if(!file1.is_open()) cout<<"file1 open error!"<<endl;
    file2.open("4_file2.txt",ios_base::in);
    if(!file2.is_open()) cout<<"file2 open error!"<<endl;
    file3.open("4_file3.txt",ios_base::out);
    if(!file3.is_open()) cout<<"file3 open error!"<<endl;
    //按照合并数组的方式合并两个文件
    string line1,line2;
    while(getline(file1,line1)&&getline(file2,line2))
        file3<<line1<<" "<<line2<<endl;
    while(!file2.fail()){
        getline(file2,line2);
        file3<<line2<<endl;
    } 
    while(!file1.fail()){
        getline(file1,line1);
        file3<<line1<<endl;
    } 
    file1.close(); file2.close(); file3.close();
    cout<<"Done!"<<endl;
    return 0;
}

5

题目

  Mat和Pat想邀请他们的朋友来参加派对,就像第16章中的编程练习8那样,但现在他们希望程序使用文件。他们请您编写一个完成下述任务的程序。
  ● 从文本文件mat.dat中读取Mat朋友的姓名清单,其中每行为一个朋友。姓名将被存储在容器中,然后按顺序显示出来。
  ● 从文本文件pat.dat中读取Pat朋友的姓名清单,其中每行为一个朋友。姓名将被存储在容器中,然后按顺序显示出来。
  ● 合并两个清单,删除重复的条目,并将结果保存在文件matnpat.dat中,其中每行为一个朋友。

题解

#include<set>
#include<string>
#include<fstream>
#include<iostream>
using namespace std;
void getName(set<string> &s,string str){
    fstream fin;
    if(str=="Mat") fin.open("mat.dat");
    else fin.open("pat.dat");
    if(!fin.is_open()){
        cout<<"Open file error!"<<endl;
        exit(EXIT_FAILURE);
    }
    while(getline(fin,str))
        s.insert(str);
}
int main(){
    set<string> MatFriend,PatFriend;
    string name;
    fstream fout("matnpat.dat",ios_base::out);
    getName(MatFriend,"Mat");
    getName(PatFriend,"Pat");
    set<string> finallist(MatFriend);
    finallist.insert(PatFriend.begin(),PatFriend.end());
    cout<<"All friend of you as following: "<<endl;
    for(auto &name: finallist){
        cout<<name<<" ";
        fout<<name<<endl;
    }
    cout<<endl;
    fout.close();
    return 0;
}

6

题目

  考虑14章的编程练习5中的类定义。如果还没有完成这个练习,请现在就做,然后完成下面的任务。
  编写一个程序,它使用标准C++I/O、文件I/O以及14章的编程练习5中定义的employee、manager、fink和highfink类型的数据。该程序应包含程序清单17.17中的代码行,即允许用户将新数据添加到文件中。该程序首次被运行时,将要求用户输入数据,然后显示所有的数据,并将这些信息保存到一个文件中。当该程序再次被运行时,将首先读取并显示文件中的数据,然后让用户添加数据,并显示所有的数据。差别之一是,应通过一个指向employee类型的指针数组来处理数据。这样,指针可以指向employee对象,也可以指向从employee派生出来的其他三种对象中的任何一种。使数组较小有助于检查程序,例如,您可能将数组限定为最多包含10个元素:

const int MAX=10;
...
employee* pc[MAX];

  为通过键盘输入,程序应使用一个菜单,让用户选择要创建的对象类型。菜单将使用一个switch,以便使用new来创建指定类型的对象,并将它的地址赋给pc数组中的一个指针。然后该对象可以使用虚函数setall()来提示用户输入相应的数据:

p[i]->setall();

  为将数据保存在文件中,应设计一个虚函数writeall():

for(int i=0; i<index;i++)
    pc[i]->writeall(fout);

  注意:对于这个练习,应使用文本I/O,而不是二进制I/O(遗憾的是,虚对象包含指向虛函数指针表的指针,而write()将把这种信息复制到文件中。使用read()读取文件的内容,以填充对象时,函数指针值将为乱码,这将扰乱虚函数的行为)。可使用换行符将字段分隔开,这样在输入时将很容易识别各个字段。也可以使用二进制I/O,但不能将对象作为一个整体写入,而应该提供分别对每个类成员应用write()和read()的类方法。这样,程序将只把所需的数据保存到文件中。
  比较难处理的部分是使用文件恢复数据。问题在于:程序如何才能知道接下来要恢复的项目是employee对象、manager对象、fink对象还是highfink对象?一种方法是,在对象的数据写入文件时,在数据前面加上一个指示对象类型的整数。这样,在文件输入时,程序便可以读取该整数,并使用switch语句创建一个适当的对象来接收数据:

enum classkind{Employee, Manager, Fink, Highfink};
...
int classtype;
while((fin>>classtype).get(ch)){
    switch(classtype){
        case Employee: pc[i]=new employee;
                       break;
    }
}

  然后便可以使用指针调用虚函数getall()来读取信息:

pc[i++]->getall();

题解

#include<iostream>
#include<string>
#include<fstream>
#include<vector>
#include<typeinfo>
using namespace std;
//**************abstr_emp的声明和实现**************
class abstr_emp{
private:
    string fname;
    string lname;
    string job;
public:
    abstr_emp(){};
    abstr_emp(const string &fn,const string &ln,const string &j):
                    fname(fn),lname(ln),job(j){}
    virtual void ShowAll()const;
    virtual void ShowAll(ostream& os)const;
    virtual void SetAll();
    friend ostream& operator<<(ostream& os,const abstr_emp &e);
    virtual ~abstr_emp()=0;
};
abstr_emp::~abstr_emp(){}

void abstr_emp::ShowAll()const{
    cout<<"Name: "<<fname<<", "<<lname<<endl;
    cout<<"Job: "<<job<<endl;
}
void abstr_emp::ShowAll(ostream& os)const{
    os<<fname<<" "<<lname<<" "<<job;
}
void abstr_emp::SetAll(){
    cout<<"Enter the firstname: ";
    cin>>fname;     cin.get();
    cout<<"Enter the lastname: ";
    cin>>lname;     cin.get();
    cout<<"Enter the job: ";
    getline(cin,job);
}
ostream& operator<<(ostream& os,const abstr_emp &e){
    os<<"Name: "<<e.fname<<", "<<e.lname<<endl;
    os<<"Job: "<<e.job<<endl;
    return os;
}

//**************employee的声明和实现**************
class employee:public abstr_emp{
public:
    employee(){};
    employee(const string &fn,const string &ln,const string &j):abstr_emp(fn,ln,j){}
    virtual void ShowAll()const;
    virtual void ShowAll(ostream &os)const;
    virtual void SetAll();
};
void employee::ShowAll()const{
    abstr_emp::ShowAll();
}
void employee::ShowAll(ostream &os)const{
    abstr_emp::ShowAll(os);
}
void employee::SetAll(){
    abstr_emp::SetAll();
}
//**************manager的声明和实现**************
class manager:virtual public abstr_emp{
private:
    int inchargeof;
protected:
    int InChargeof()const{return inchargeof;}
    int &InChargeof(){return inchargeof;}
public:
    manager(){};
    manager(const string &fn,const string &ln,const string &j,int ico=0):
            abstr_emp(fn,ln,j),inchargeof(ico){}
    manager(const abstr_emp& e,int ico):
            abstr_emp(e),inchargeof(ico){}
    manager(const manager& m):
            abstr_emp(m),inchargeof(m.inchargeof){}
    virtual void ShowAll()const;
    virtual void ShowAll(ostream &os)const;
    virtual void SetAll();
};
void manager::ShowAll()const{
    abstr_emp::ShowAll();
    cout<<"Inchargeof: "<<inchargeof<<endl;
}
void manager::ShowAll(ostream& os)const{
    abstr_emp::ShowAll(os);
    os<<" "<<inchargeof;
}
void manager::SetAll(){
    abstr_emp::SetAll();
    cout<<"Enter the number of employees managed: ";
    cin>>inchargeof;
    cin.get();
}
//**************Fink的声明和实现**************
class fink: virtual public abstr_emp{
private:
    string reportsto;
protected:
    const string ReportsTo()const{return reportsto;}
    string& ReportsTo(){return reportsto;}
public:
    fink(){};
    fink(const string &fn,const string &ln,const string &j,const string &rpo):
        abstr_emp(fn,ln,j),reportsto(rpo){}
    fink(const abstr_emp&e,const string &rpo):
        abstr_emp(e),reportsto(rpo){}
    fink(const fink& e):
        abstr_emp(e),reportsto(e.reportsto){}
    virtual void ShowAll()const;
    virtual void ShowAll(ostream& os)const;
    virtual void SetAll();
};
void fink::ShowAll()const{
    abstr_emp::ShowAll();
    cout<<"Reportsto: "<<reportsto<<endl;
}
void fink::ShowAll(ostream& os)const{
    abstr_emp::ShowAll(os);
    os<<" "<<reportsto;
}
void fink::SetAll(){
    abstr_emp::SetAll();
    cout<<"Enter the name of whom the fink should report to: ";
    getline(cin,reportsto);
}
//**************highfink的声明和实现**************
class highfink:public manager,public fink{
public:
    highfink(){};
    highfink(const string &fn,const string &ln,const string &j,const string& rpo,int ico):
            abstr_emp(fn,ln,j),manager(fn,ln,j,ico),fink(fn,ln,j,rpo){}
    highfink(const abstr_emp& e,const string& rpo,int ico):
            abstr_emp(e),manager(e,ico),fink(e,rpo){}
    highfink(const fink& f,int ico):
            abstr_emp(f),manager((const abstr_emp&)(f),ico),fink(f){}
    highfink(const manager& m,const string rpo):
            abstr_emp(m),manager(m),fink((const abstr_emp&)(m),rpo){}
    highfink(const highfink& h):abstr_emp(h),manager(h),fink(h){}
    virtual void ShowAll()const;
    virtual void ShowAll(ostream& os)const;
    virtual void SetAll();
};
void highfink::ShowAll()const{
    abstr_emp::ShowAll();
    cout<<"Inchargeof: "<<manager::InChargeof()<<endl;
    cout<<"Reportsto: "<<fink::ReportsTo()<<endl;
}
void highfink::ShowAll(ostream& os)const{
    abstr_emp::ShowAll(os);
    os<<" "<<fink::ReportsTo()<<" "<<manager::InChargeof();
}
void highfink::SetAll(){
    abstr_emp::SetAll();
    cout<<"Enter the number of employees managed: ";
    cin>>manager::InChargeof();
    cin.get();
    cout<<"Enter the name of whom the fink should report to: ";
    getline(cin,fink::ReportsTo());
}
enum classkind{Employee,Manager,Fink,Highfink};
int main(){
    fstream datafile("employee.dat");
    vector<abstr_emp*> allemployee;
    string fn,ln,job,report2;
    int inchargenum;
    if(!datafile.is_open())
        cout<<"Data file open error"<<endl;
    else{
        if(datafile.peek()!=EOF){
            cout<<"All employees are following: "<<endl;
            int classtype;
            while(datafile>>classtype){
                abstr_emp* temp;
                datafile>>fn>>ln>>job;
                switch(classtype){
                    case Employee:{
                        temp=new employee(fn,ln,job);
                        break;
                    }
                    case Manager:{
                        datafile>>inchargenum;
                        temp=new manager(fn,ln,job,inchargenum);
                        break;
                    }
                    case Fink:{
                        datafile>>report2;
                        temp=new fink(fn,ln,job,report2);
                        break;
                    }
                    case Highfink:{
                        datafile>>report2>>inchargenum;
                        temp=new highfink(fn,ln,job,report2,inchargenum);
                        break;
                    }
                    default:break;
                }
                temp->ShowAll();
                cout<<endl;
            }
        }
        else
            cout<<"There is no data now!"<<endl;
    }
    //读入新数据
    cout<<"Add a data to the list with following type: "<<endl
        <<"1. Employee      2.Manager"<<endl
        <<"3. Fink          4.Highfink"<<endl
        <<"5. Quit"<<endl;
    int classtype;
    while(cin>>classtype&&classtype!=5){
        classtype--;
        abstr_emp* temp;
        switch(classtype){
            case Employee:{
                temp=new employee;
                break;
            }
            case Manager:{
                temp=new manager;
                break;
            }
            case Fink:{
                temp=new fink;
                break;
            }
            case Highfink:{
                temp=new highfink;
                break;
            }
            default:break;
        }
        temp->SetAll();
        allemployee.push_back(temp);
        cout<<"Add next data to the list with following type: "<<endl
            <<"1. Employee      2.Manager"<<endl
            <<"3. Fink          4.Highfink"<<endl
            <<"5. Quit"<<endl;
    }
    //数据写回
    datafile.clear();       //打开时候的判定导致标记位置为fail,空文件到结尾了,所以要先清空
    for(abstr_emp* item:allemployee){
        int classtype;
        if(typeid(*item)==typeid(employee))
            classtype=Employee;
        else if(typeid(*item)==typeid(manager))
            classtype=Manager;
        else if(typeid(*item)==typeid(fink))
            classtype=Fink;
        else if(typeid(*item)==typeid(highfink))
            classtype=Highfink;
        datafile<<classtype<<" ";
        item->ShowAll(datafile);
        datafile<<endl;
    }
    datafile.close();
    cout<<"Bye!\nData Add Done!"<<endl;
    return 0;
}

7

题目

  7.下面是某个程序的部分代码。该程序将键盘输入读取到一个由string对象组成的vector中,将字符串内容(而不是string对象)存储到一个文件中,然后该文件的内容复制到另一个由string对象组成的vector中。

int main(){
    using namespace std;
    vector<string> vostr;
    string temp;
    cout<<"Enter strings (empty line to quit):\n";
    while(getline(cin,temp)&&temp[0]!='\0')
        vostr.push_back(temp);
    cout<<"Here is your input.\n";
    for_each(vostr.begin(),vostr.end(),ShowStr);
    //store in a file
    ofstream fout("strings.dat",ios_base::out|ios_base::binary);
    for_each(vostr.begin(),vostr.end(),Store(fout));
    fout.close();
    //revover file contents
    vector<string> vistr;
    ifstream fin("strings.dat",ios_base::in|ios_base::binary);
    if(!fin.is_open()){
        cerr<<"Could not open file for input.\n";
        exit(EXIT_FAILURE);
    }
    GetStrs(fin,vistr);
    cout<<"\nHere are the strings read from the file.\n";
    for_each(vistr.begin(),vistr.end(),ShowStr);
    return 0;
}

  该程序以二进制格式打开文件,并想使用read()和write()来完成1/O。余下的工作如下所述。
  ● 编写函数void ShowStr(const string &),它显示一个string对象,并在显示完后换行。
  ● 编写函数符Store,它将字符串信息写入到文件中。Store的构造函数应接受一个指定ifstream对象的参数,而重载的operator()(const string &)应指出要写入到文件中的字符串。一种可行的计划是,首先将字符串的长度写入到文件中,然后将字符串的内容写入到文件中。例如,如果len存储了字符串的长度,可以这样做:

os .write((char *)&len, sizeof(std::size_ _t)); // store length
os. write(s.datal),len);                        // store characters

  成员函数data()返回一个指针,该指针指向一个其中存储了字符串中字符的数组。它类似于成员函数c_str(),只是后者在数组末尾加上了一个空字符。
  ● 编写函数GetStrs(),它根据文件恢复信息。该函数可以使用read()来获得字符串的长度,然后使用一个循环从文件中读取相应数量的字符,并将它们附加到一个原来为空的临时string末尾。由于string的数据是私有的,因此必须使用string类的方法来将数据存储到string对象中,而不能直接存储。

题解

#include<string>
#include<fstream>
#include<iostream>
#include<vector>
#include<algorithm>
//ShowStr
void ShowStr(const std::string &str){
    std::cout<<str<<std::endl;
}
//Store
class Store{
private:
    std::ostream& fout;
public:
    Store(std::ostream &fout):fout(fout){   //必须通过初始化列表的方式进行赋值
    }
    void operator()(const std::string&str){
        size_t len=str.size();
        fout.write((char*)&len,sizeof(size_t));
        fout.write(str.data(),len);         //s.data返回的字符数组包含结尾的\0
    }
};
//GetStrs
void GetStrs(std::istream& fin,std::vector<std::string> &vstr){
    size_t len;
    while(fin.read((char*)&len,sizeof(size_t))){
        std::string temp;
        for(size_t i=0;i<len;i++){
            char ch=fin.get();
            temp+=ch;
        }
        vstr.push_back(temp);
    }
}
int main(){
    using namespace std;
    vector<string> vostr;
    string temp;
    cout<<"Enter strings (empty line to quit):\n";
    while(getline(cin,temp)&&temp[0]!='\0')
        vostr.push_back(temp);
    cout<<"Here is your input.\n";
    for_each(vostr.begin(),vostr.end(),ShowStr);
    //store in a file
    ofstream fout("strings.dat",ios_base::out|ios_base::binary);
    for_each(vostr.begin(),vostr.end(),Store(fout));
    fout.close();
    //revover file contents
    vector<string> vistr;
    ifstream fin("strings.dat",ios_base::in|ios_base::binary);
    if(!fin.is_open()){
        cerr<<"Could not open file for input.\n";
        exit(EXIT_FAILURE);
    }
    GetStrs(fin,vistr);
    cout<<"\nHere are the strings read from the file.\n";
    for_each(vistr.begin(),vistr.end(),ShowStr);
    return 0;
}

当珍惜每一片时光~