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;
}
Comments | NOTHING