C++ Primer Plus习题及答案-第十七章

2023-02-26 11:02:12 浏览数 (1)

习题选自:C Primer Plus(第六版) 内容仅供参考,如有错误,欢迎指正 ! cout格式化输出 使用cin进行输入 文件的输入和输出

复习题

1. iostream文件在C I/O中扮演何种角色?

iostream文件定义了用于管理输入和输出的类、常量和操作符,这些对象用于I/O的流和缓冲区。该文件还创建了一些用于处理标准输入输出流的标准对象(如cin、cout、cerr和clog以及对应的宽字符对象)。

2. 为什么键入数字(如121)作为输入要求程序进行转换?

键盘输入会生成一系列字符,输入121将会生成3个字符,每个字符都由一个字节的二进制码表示。要将这个值存储为int类型,则必须将这3个字符转换为121值的二进制表示。

3. 标准输出与标准错误之间有什么区别?

默认情况下两者都将输出发给标准输出设备(通常为显示器)。然而,如果要求操作系统操作系统将输出重定向到文件,则标准输出将与文件相连,但标准错误仍与显示器相连。

4. 为什么在不为每个类型提供明确指示的情况下,cout仍能够显示不同的C 类型?

ostream类为每种C 基本类型定义了一个operator <<()函数的版本。编译器将类似cout << spot的表达式解释为cout.operator<<(spot),这样,它便能够将该方法调用与具有相同参数类型的函数原型匹配。

5. 输出方法的定义的哪一特征让您能够拼接输出?

返回ostream &类型的输出方法能够拼接输出。通过一个对象调用方法时,将返回该对象。然后,返回对象将可以调用序列中的下一个方法

6. 编写一个程序,要求用户输入一个整数,然后以十进制、八进制和十六进制显示该整数。在宽度为15个字符的字段中显示每种形式,并将它们显示在同一行上,同时使用C 数基前缀。

代码语言:javascript复制
#include <iomanip>
#include <iostream>

int main() {
  using namespace std;
  cout << "Enter an interger: ";
  int n;
  cin >> n;
  cout << setw(15) << "base ten" << setw(15) << "base sixteen" << setw(15)
       << "base eight"
       << "n";
  cout.setf(ios::showbase);
  cout << setw(15) << n << hex << setw(15) << n << oct << setw(15) << n << "n";
  return 0;
}

7. 编写一个程序,请求用户输入下面的信息,并按下面的格式显示它们:

代码语言:javascript复制
Enter your name: Billy Gruff
Enter your hourly wages: 12
Enter number of hours worked: 7.5
First format:
             Billy Gruff: $ 12.00: 7.5
Second format:
Billy Gruff             : $12.00 :7.5

main.cpp:

代码语言:javascript复制
#include <iomanip>
#include <iostream>
int main() {
    using namespace std;
    char name[20];
    float hourly;
    float hours;
    cout << "Enter your name: ";
    cin.get(name, 20).get();
    cout << "Enter your hourly wages: ";
    cin >> hourly;
    cout << "Enter number of hours worked: ";
    cin >> hours;
    cout.setf(ios::showpoint);
    cout.setf(ios::fixed, ios::floatfield);
    cout.setf(ios::right, ios::adjustfield);
    // or cout << showpoint << fixed << right;
    cout << "First format:n";
    cout << setw(30) << name << ": $" << setprecision(2) << setw(10) << hourly
        << ":" << setprecision(1) << setw(5) << hours << "n";
    cout << "Second format:n";
    cout.setf(ios::left, ios::adjustfield);
    cout << setw(30) << name << ": $" << setprecision(2) << setw(10) << hourly
        << ":" << setprecision(1) << setw(5) << hours << "n";
    return 0;
}

8. 对于下面的程序:

代码语言:javascript复制
//rq17-8.cpp
#include <iostream>
int main()
{
    using namespace std;
    char ch;
    int ct1 = 0;
    cin >> ch;
    while (ch != 'q')
    {
        ct1  ;
        cin >> ch;
    }
    int ct2 = 0;
    cin.get(ch);
    while (ch != 'q')
    {
        ct2  ;
        cin.get(ch);
    }
    cout << "ct1 = " << ct1 << "; ct2 = " << ct2 << "n";
    return 0;
}

如果输入如下,该程序将打印什么内容?

代码语言:javascript复制
I see a q<Enter>
I see a q<Enter>

其中,表示按回车键。

使用cin >> ch;会自动忽略空格和换行符,因此ct1的值应为5。而cin.get(ch);不忽略空格和换行符,且第一次输入的回车键,也会被cin.get(ch);捕捉到,因此ct2的值应为9。打印内容如下:

代码语言:javascript复制
ct1 = 5; ct2 = 9

9. 下面的两条语句都读取并丢弃行尾之前的所有字符(包括行尾)。这两条语句的行为在哪方面不同?

代码语言:javascript复制
while (cin.get() != 'n')
    continue;
cin.ignore(80, 'n');

如果输入超过80个字符,且这80个字符中没有出现'n',则ignore()会将前80个字符都会抛弃掉,然后再开始执行后面的语句。也就是说当输入超过80个字符,且这80个字符中没有出现'n'cin.ignore(80, 'n');读取并丢弃行尾之前的所有字符(包括行尾)的作用可能会不符合预期。而第一条语句没有该限制。【注:可以将第二个语句中80改为numeric_limits<streamsize>::max()来解除该限制】

编程练习

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

main.cpp:

代码语言:javascript复制
#include <iostream>
//#include <ios>  //used to get stream size
//#include <limits>  //used to get numeric limits

int main() {
    using std::cin;
    using std::cout;
    using std::endl;

    cout << "Enter a string with a '$' in it: " << endl;
    int ct = 0;
    char ch;
    while ((ch = cin.get()) != '$') ct  ;
    cin.putback(ch);  // put $ back to stream

    while (cin.get() != 'n') continue;
    // or use cin.ignore(std::numeric_limits<std::streamsize>::max(),// 'n');

    cout << "There are " << ct << " characters before $" << endl;

    return 0;
}

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

main.cpp:

代码语言:javascript复制
#include <cstdlib>
#include <fstream>
#include <iostream>

using namespace std;

int main() {
    cout << "Please enter filename: ";
    char fname[30];
    cin >> fname;
    ofstream fout;
    fout.open(fname, std::ios_base::out);

    cout << "Please enter something: " << endl;
    char ch;
    while (cin.get(ch) && ch != EOF) fout << ch;

    fout.close();

    return 0;
}

:linux下键盘模拟输入文件结束符为Ctrl D

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

main.cpp:

代码语言:javascript复制
#include <cstdlib>
#include <fstream>
#include <iostream>

int main(int argc, char* argv[]) {
    using namespace std;

    if (argc < 3) {
        cerr << "Usage: " << argv[0] << " source-file target-file" << endl;
        exit(EXIT_FAILURE);
    }

    ifstream fin(argv[1], ios_base::in);
    if (!fin) {
        cerr << "Cant't open" << argv[1] << " for input" << endl;
        exit(EXIT_FAILURE);
    }

    ofstream fout(argv[2], ios_base::out);
    if (!fout) {
        cerr << "Can't open" << argv[2] << " for output" << endl;
        exit(EXIT_FAILURE);
    }

    char ch;
    while (fin.get(ch)) fout.put(ch);

    cout << "Content of " << argv[1] << " copied to " << argv[2] << "success."
        << endl;
    fin.close();
    fout.close();

    return 0;
}

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

代码语言:javascript复制
eggs kites donuts
balloons hammers
stones

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

代码语言:javascript复制
zero lassitude
finance drama

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

代码语言:javascript复制
eggs kites donuts zero lassitude
balloons hammers finance drama
stones

main.cpp:

代码语言:javascript复制
#include <fstream>
#include <iostream>

int main() {
    using namespace std;
    char* file1 = "input1.txt";
    char* file2 = "input2.txt";
    char* file3 = "output.txt";
    ifstream fin1(file1, ios_base::in);
    ifstream fin2(file2, ios_base::in);
    ofstream fout1(file3, ios_base::out);
    if (!fin1.is_open() || !fin2.is_open()) {
        cerr << file1 << " or " << file2 << "open fail.";
        exit(EXIT_FAILURE);
    }
    char ch;
    if (!fout1.is_open()) {
        cerr << "Can't open " << file3 << endl;
        exit(EXIT_FAILURE);
    } else {
        while (!fin1.eof() || !fin2.eof()) {
            if (!fin1.eof()) {
                while (fin1.get(ch) && ch != 'n') fout1 << ch;
                fout1 << ' ';
            }
            if (!fin2.eof()) {
                while (fin2.get(ch) && ch != 'n') fout1 << ch;
            }
            fout1 << 'n';
        }
    }
    fin1.close();
    fin2.close();
    fout1.close();

    return 0;
}

5. Mat和Pat想邀请他们的朋友来参加派对,就像第16章中的编程练习8那样,但现在他们希望程序使用文件。他们请您编写一个完成下述任务的程序。

  • 从文本文件mat.dat中读取Mat朋友的姓名清单,其中每行为一个朋友。姓名将被存储在容器,然后按顺序显示出来。
  • 从文本文件pat.dat中读取Pat朋友的姓名清单,其中每行为一个朋友。姓名将被存储在容器中,然后按顺序显示出来。
  • 合并两个清单,删除重复的条目,并将结果保存在文件matnpat.dat中,其中每行为一个朋友。

main.cpp:

代码语言:javascript复制
#include <algorithm>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <set>
#include <string>
#include <vector>

int main() {
    using namespace std;

    vector<string> mat;
    vector<string> pat;
    set<string> matnpat;

    ifstream fmat("mat.dat", ios_base::in), fpat("pat.dat", ios_base::in);
    if (!(fmat && fpat)) {
        cerr << "Failed to open input files" << endl;
        exit(EXIT_FAILURE);
    }

    ofstream fout("matnpat.at", ios_base::out);
    if (!fout) {
        cerr << "Failed to open output files" << endl;
        exit(EXIT_FAILURE);
    }

    string name;

    while (fmat >> name) mat.push_back(name);
    cout << "Mat's friends: ";
    for (auto it = mat.begin(); it != mat.end();   it) cout << *it << " ";
    cout << endl;

    while (fpat >> name) pat.push_back(name);
    cout << "Pat's friends: ";
    for (auto it = pat.begin(); it != pat.end();   it) cout << *it << " ";
    cout << endl;

    matnpat.insert(mat.begin(), mat.end());
    matnpat.insert(pat.begin(), pat.end());
    cout << "All friends: " << endl;
    for (auto& name : matnpat) cout << name << " ";
    cout << endl;

    return 0;
}

6. 考虑14章的编程练习5中的类定义。如果还没有完成这个练习,请现在就做,然后完成下面的任务。

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

代码语言:javascript复制
const int MAX = 10; // no more than 10 objects
...
employee * pc[MAX];

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

代码语言:javascript复制
pc[i]->setall(); // invokes function corresponding to type of object

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

代码语言:javascript复制
for (i = 0; i < index; i  )
pc[i]->writeall(fout);// fout ofstream connected to output file

注意】:

对于这个练习,应使用文本I/O,而不是二进制I/O(遗憾的是,虚对象包含指向虚函数指针表的指针,而write( )将把这种信息复制到文件中。使用read( )读取文件的内容,以填充对象时,函数指针值将为乱码,这将扰乱虚函数的行为)。可使用换行符将字段分隔开,这样在输入时将很容易识别各个字段。也可以使用二进制I/O,但不能将对象作为一个整体写入,而应该提供分别对每个类成员应用write( )和read( )的类方法。这样,程序将只把所需的数据保存到文件中。

比较难处理的部分是使用文件恢复数据。问题在于:程序如何才能知道接下来要恢复的项目是employee对象、manager对象、fink对象还是highfink对象?一种方法是,在对象的数据写入文件时,在数据前面加上一个指示对象类型的整数。这样,在文件输入时,程序便可以读取该整数,并使用switch语句创建一个适当的对象来接收数据:

代码语言:javascript复制
enum classkind{Employee, Manager, Fink, Highfink}; // in class header
...
    int classtype;
while((fin >> classtype).get(ch)){ // newline separates int from data
    switch(classtype) {
        case Employee : pc[i] = new employee;
            : break;

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

代码语言:javascript复制
pc[i  ]->getall();

emp.h:

代码语言:javascript复制
#ifndef EMP_H_
#define EMP_H_

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

enum classkind {Employee, Manager, Fink, HighFink};

class abstr_emp
{
private:
    std::string fname;
    std::string lname;
    std::string job;
public:
    abstr_emp();
    abstr_emp(const std::string & fn, const std::string & ln,
              const std::string & j);
    virtual void ShowAll() const;
    virtual void SetAll();
    virtual std::ofstream & WriteAll(std::ofstream & of) const;
    friend std::ostream & operator<<(std::ostream & os, const abstr_emp & e);
    virtual ~abstr_emp() = 0;
};

class employee : public abstr_emp
{
public:
    employee();
    employee(const std::string & fn, const std::string & ln,
             const std::string & j);
    virtual void ShowAll() const;
    virtual void SetAll();
    std::ofstream & WriteAll(std::ofstream & fout) const;
};

class manager : virtual public abstr_emp
{
private:
    int inchargeof;
protected:
    int InChargeOf() const { return inchargeof; }
    int & InChargeOf() { return inchargeof; }
public:
    manager();
    manager(const std::string & fn, const std::string & ln,
            const std::string & j, int ico = 0);
    manager(const abstr_emp & e, int ico);
    manager(const manager & m);
    virtual void ShowAll() const;
    virtual void SetAll();
    std::ofstream & WriteAll(std::ofstream & fout) const;
};

class fink : virtual public abstr_emp
{
private:
    std::string reportsto;
protected:
    const std::string ReportsTo() const { return reportsto; }
    std::string & ReportsTo() { return reportsto; }
public:
    fink();
    fink(const std::string & fn, const std::string ln,
         const std::string & j, const std::string rpo);
    fink(const abstr_emp & e, const std::string & rpo);
    fink(const fink & f);
    virtual void ShowAll() const;
    virtual void SetAll();
    std::ofstream & WriteAll(std::ofstream & fout) const;
};

class highfink : public manager, public fink
{
public:
    highfink();
    highfink(const std::string & fn, const std::string & ln,
             const std::string & j, const std::string & rpo,
             int ico);
    highfink(const abstr_emp & e, const std::string rpo, int ico);
    highfink(const fink & f, int ico);
    highfink(const manager & m, const std::string rpo);
    highfink(const highfink & h);
    virtual void ShowAll() const;
    virtual void SetAll();
    std::ofstream & WriteAll(std::ofstream & fout) const;
};

#endif

emp.cpp:

代码语言:javascript复制
#include "emp.h"

/*******************
 * abstr_emp methods
 *******************/
abstr_emp::abstr_emp()
{
    fname = "none";
    lname = "none";
    job = "none";
}

abstr_emp::abstr_emp(const std::string & fn, const std::string & ln,
                     const std::string & j) : fname(fn), lname(ln), job(j)
{
}

abstr_emp::~abstr_emp() {}

void abstr_emp::ShowAll() const
{
    std::cout << "firstname: " << fname << std::endl;
    std::cout << "lastname: " << lname << std::endl;
    std::cout << "job: " << job << std::endl;
}

void abstr_emp::SetAll()
{
    std::cout << "Enter firstname: ";
    std::getline(std::cin, fname);
    std::cout << "Enter lastname: ";
    std::getline(std::cin, lname);
    std::cout << "Enter job: ";
    std::getline(std::cin, job);
}

std::ofstream & abstr_emp::WriteAll(std::ofstream & fout) const
{
    fout << fname << " " << lname << " " << job;
    return fout;
}

// friend functions
std::ostream & operator<<(std::ostream & os, const abstr_emp & e)
{
    os << e.lname << " " << e.fname << ", " << e.job;
    return os;
}

/******************
 * employee methods
 ******************/
employee::employee() {}

employee::employee(const std::string & fn, const std::string & ln,
                   const std::string & j)
    : abstr_emp(fn, ln, j)
{
}

void employee::ShowAll() const
{
    abstr_emp::ShowAll();
}

void employee::SetAll()
{
    abstr_emp::SetAll();
}

std::ofstream & employee::WriteAll(std::ofstream & fout) const
{
    fout << Employee << " ";
    abstr_emp::WriteAll(fout);
    return fout;
}


/*****************
 * manager methods
 *****************/
manager::manager()
{
    inchargeof = 0;
}


manager::manager(const std::string & fn, const std::string & ln,
                 const std::string & j, int ico)
    : abstr_emp(fn, ln, j), inchargeof(ico)
{
}

manager::manager(const abstr_emp & e, int ico)
    : abstr_emp(e)
{
    inchargeof = ico;
}

manager::manager(const manager & m)
    : abstr_emp(m)
{
    inchargeof = m.inchargeof;
}

void manager::ShowAll() const
{
    abstr_emp::ShowAll();
    std::cout << "Inchargeof: " << inchargeof << std::endl;
}

void manager::SetAll()
{
    abstr_emp::SetAll();
    std::cout << "Enter inchargeof: ";
    std::cin >> inchargeof;
    std::cin.get();
}

std::ofstream & manager::WriteAll(std::ofstream & fout) const
{
    fout << Manager << " ";
    abstr_emp::WriteAll(fout);
    fout << " " << inchargeof;
    return fout;
}

/**************
 * fink methods
 **************/
fink::fink()
{
    reportsto = "none";
}

fink::fink(const std::string & fn, const std::string ln,
           const std::string & j, const std::string rpo)
    : abstr_emp(fn, ln, j), reportsto(rpo)
{
}

fink::fink(const abstr_emp & e, const std::string & rpo)
    : abstr_emp(e), reportsto(rpo)
{
}

fink::fink(const fink & f)
    : abstr_emp(f)
{
    reportsto = f.reportsto;
}

void fink::ShowAll() const
{
    abstr_emp::ShowAll();
    std::cout << "Reportsto: " << reportsto << std::endl;
}

void fink::SetAll()
{
    abstr_emp::SetAll();
    std::cout << "Enter reportsto: ";
    std::getline(std::cin, reportsto);
}

std::ofstream & fink::WriteAll(std::ofstream & fout) const
{
    fout << Fink << " ";
    abstr_emp::WriteAll(fout);
    fout << " " << reportsto;
    return fout;
}

/******************
 * highfink methods
 ******************/
highfink::highfink() {}

highfink::highfink(const std::string & fn, const std::string & ln,
                   const std::string & j, const std::string & rpo,
                   int ico)
    : abstr_emp(fn, ln, j), manager(fn, ln, j, ico), fink(fn, ln, j, rpo)
{
}

highfink::highfink(const abstr_emp & e, const std::string rpo, int ico)
    : abstr_emp(e), manager(e, ico), fink(e, rpo)
{
}

highfink::highfink(const fink & f, int ico)
    : abstr_emp(f), fink(f), manager((const abstr_emp &)f, ico)  // ????
{
}

highfink::highfink(const manager & m, const std::string rpo)
    : abstr_emp(m), manager(m), fink((const abstr_emp &)m, rpo)
{
}

highfink::highfink(const highfink & h)
    : abstr_emp(h), manager(h), fink(h)
{
}

void highfink::ShowAll() const
{
    abstr_emp::ShowAll();
    std::cout << "Inchargeof: " << manager::InChargeOf() << std::endl;
    std::cout << "Reportsto: " << fink::ReportsTo() << std::endl;
}

void highfink::SetAll()
{
    abstr_emp::SetAll();
    std::cout << "Enter reportsto: ";
    std::getline(std::cin, fink::ReportsTo());
    std::cout << "Enter Inchargeof: ";
    std::cin >> manager::InChargeOf();
    std::cin.get();
}

std::ofstream & highfink::WriteAll(std::ofstream & fout) const
{
    fout << HighFink << " ";
    abstr_emp::WriteAll(fout);
    fout << " " << manager::InChargeOf() << " " << fink::ReportsTo();
    return fout;
}

main.cpp:

代码语言:javascript复制
#include <fstream>
#include <iostream>

#include "emp.h"

using namespace std;

inline void show_line(int n);
void show_menu();
inline void eatline();

const int MAX = 10;

int main() {
    abstr_emp* pc[MAX];
    int ct = 0;  // number counter

    string fname, lname, job, reportsto;
    int inchargeof;

    ifstream fin("out.txt", ios_base::in);
    if (fin.good()) {  // read from file
        int kind;
        while (fin >> kind) {
            switch (kind) {
                case Employee:
                    fin >> fname;
                    fin >> lname;
                    fin >> job;
                    pc[ct] = new employee(fname, lname, job);
                    break;
                case Manager:
                    fin >> fname;
                    fin >> lname;
                    fin >> job;
                    fin >> inchargeof;
                    pc[ct] = new manager(fname, lname, job, inchargeof);
                    break;
                case Fink:
                    fin >> fname;
                    fin >> lname;
                    fin >> job;
                    fin >> reportsto;
                    pc[ct] = new fink(fname, lname, job, reportsto);
                    break;
                case HighFink:
                    fin >> fname;
                    fin >> lname;
                    fin >> job;
                    fin >> reportsto;
                    fin >> inchargeof;
                    pc[ct] = new highfink(fname, lname, job, reportsto, inchargeof);
            }
            ct  ;
        }

        // show content in file
        cout << "content in out.txt" << endl;
        for (int i = 0; i < ct;   i) pc[i]->ShowAll();
    }

    // fill the array
    show_menu();
    char choice;
    abstr_emp* p;
    while (cin >> choice && choice != 'q' && ct < MAX) {
        eatline();
        switch (choice) {
            case 'e':  // employee
                p = new employee;
                p->SetAll();
                pc[ct] = p;
                break;
            case 'm':  // manager
                p = new manager;
                p->SetAll();
                pc[ct] = p;
                break;
            case 'f':  // fink
                p = new fink;
                p->SetAll();
                pc[ct] = p;
                break;
            case 'h':  // highfink
                p = new highfink;
                p->SetAll();
                pc[ct] = p;
                break;
        }
        ct  ;
        show_menu();
    }

    // show all input
    for (int i = 0; i < ct;   i) pc[i]->ShowAll();

    // write to files
    ofstream fout("out.txt", ios_base::out);
    for (int i = 0; i < ct;   i) {
        pc[i]->WriteAll(fout);
        fout << endl;
    }
    fout.close();

    cout << "content in array are written to out.txt" << endl;

    // free memories
    for (int i = 0; i < ct;   i) delete pc[i];

    return 0;
}

void show_menu() {
    ios_base::fmtflags old_fmt = cout.setf(ios_base::left, ios_base::adjustfield);

    show_line(35);
    cout.width(20);
    cout << "e. employee";
    cout << "m. manager" << endl;
    cout.width(20);
    cout << "f. fink";
    cout << "h. highfink" << endl;
    cout << "q. quit" << endl;
    show_line(35);
    cout << "Select a type: " << endl;

    cout.setf(old_fmt);
}

inline void show_line(int n) {
    cout.fill('-');
    cout.width(n);
    cout << "-" << endl;
    cout.fill(' ');
}

inline void eatline() {
    while (cin.get() != 'n') continue;
}

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

代码语言:javascript复制
int main()
{
    using namespace std;
    vector<string> vostr;
    string temp;
    // acquire strings
    cout << "Enter strings (empty line to quit):n";
    while (getline(cin,temp) && temp[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();
    // recover 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( )来完成I/O。余下的工作如下所述。

  • 编写函数void ShowStr(const string &),它显示一个string对象,并在显示完后换行。
  • 编写函数符Store,它将字符串信息写入到文件中。Store的构造函数应接受一个指定ifstream对象的参数,而重载的operator( )(const string &)应指出要写入到文件中的字符串。一种可行的计划是,首先将字符串的长度写入到文件中,然后将字符串的内容写入到文件中。例如,如果len存储了字符串的长度,可以这样做:
代码语言:javascript复制
os.write((char *)&len, sizeof(std::size_t)); // store length
os.write(s.data(), len); // store characters

成员函数data( )返回一个指针,该指针指向一个其中存储了字符串中字符的数组。它类似于成员函数c_str( ),只是后者在数组末尾加上了一个空字符。

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

main.cpp:

代码语言:javascript复制
#include <algorithm>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Store {
    private:
    ostream& os;

    public:
    Store(ostream& o) : os(o){};
    void operator()(const string& s) {
        size_t len = s.length();

        // store string length
        os.write((char*)&len, sizeof(std::size_t));
        // store string data
        os.write(s.data(), len);
    }
};
inline void ShowStr(const std::string& s) { cout << s << endl; };
void GetStrs(std::ifstream& fin, std::vector<std::string>& vistr);

int main() {
    using namespace std;
    vector<string> vostr;
    string temp;

    // acquire strings
    cout << "Enter strings (empty line to quit):n";
    while (getline(cin, temp) && temp[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();

    // recover 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;
}

void GetStrs(std::ifstream& fin, std::vector<std::string>& vistr) {
    size_t len;  // string length
    while (fin.read((char*)&len, sizeof(std::size_t))) {
        string str;
        char ch;
        for (int i = 0; i < len;   i) {
            fin.read(&ch, sizeof(char));
            str.push_back(ch);
        }

        // put string to vector
        vistr.push_back(str);
    }
}

0 人点赞