本文为《C++程序设计:原理与实践》第10章的练习题答案,代码是自己写的,可能会存在不少缺陷,但是基本的功能是可以实现的,仅供参考。
题目描述:
1. 编写一个程序来处理平面中的点。首先定义包含两个表示坐标成员x,y的数据类型Point;
2.提示用户输入7个(x,y)值对。当用户输入数据是,将其保存在一个名为original_points的向量中;
3.打印original_points中的数据查看结果;
4.打开一个ofstream,将每个点输出到名为mydata.txt的文件中;
5.关闭ofstream,然后打开一个ifstream,使其与mydata.txt关联。从mydata.txt中读取数据,保存在一个名为processed_points的新的向量中;
6.比较两个向量,如果发现元素数目或值不一致,打印“Something's wrong!"。
代码如下:
1. 定义一个Point数据类型
struct Point{
int x;
int y;
};
2. 自定义输入流
istream& operator>>(istream& is, Point& p){
char ch1;
cin>> ch1;
if((ch1!='(') && (ch1!='\n')) // 允许输入换行
perror("Error:'('");
char ch2;
int x, y;
cin>> x>> ch2>> y;
if(ch2!=',')
perror("Error:','");
char ch3;
cin>> ch3;
if(ch3!=')')
perror("Error:')'");
p.x = x;
p.y = y;
return is;
}
3. 自定义输出流
ostream& operator<<(ostream& os, Point& p){
return os<< "("<< p.x<< ","<< p.y<< ")"<< endl;
}
4. 写文件
void Write_to_file(vector<Point>& points, string& name){
ofstream ost{name};
if(!ost) perror("Can't open file.\n");
for(int i=0;i<points.size();i++){
ost<< points[i];
}
}
这里没有显式地打开或关闭文件,因为这里将其包含在了Write_to_file的ofstream的作用域中,当文件流离开了其作用域,与之关联的文件会被关闭。当文件被关闭时,与之关联的缓冲区会被刷新,即缓冲区中的字符会被写入文件中。
一般来说,最好在程序的一开始位置,在任何计算都尚未开始之前就打开文件。因为如果在完成计算后才发现无法保存结果,将会是对计算资源的巨大浪费。
理想的方式:在创建ostream或istream对象时,隐式打开文件,并依靠流对象的作用域关闭文件。
// 如果使用文件的范围不能简单地包含域任何流对象的作用域中,需要显示使用open()、close()操作
ost.open(filename, iOS_base::out);
// ......
ost.close();
5. 读文件
void Read_from_file(vector<Point>& points, string& name){
ifstream ist{name};
if(!ist) perror("Can't open file\n");
while(!ist.ios_base::eof()){
Point p;
char ch1, ch2, ch3;
int x, y;
ist>> ch1>> x>> ch2>> y>> ch3;
// 增加对eof的判断,防止文件最后一行被读2次
if(ist.ios_base::eof())
return;
if((ch1!='(') && (ch2!=',') && (ch3!=')'))
return;
p.x = x;
p.y = y;
points.push_back(p);
}
}
读文件这里遇到了一个问题:使用EOF判断读取文件是否结束时,会造成文件最后一行被读了两遍。
这是因为:当文件刚刚读到文件尾时,eof()不会返回true。只有在文件尾部再次进行一次读操作,eof()才会返回真。
所以在程序中,对eof()判断了两次。
The extraction will only set the EOF bit on the stream if you attempt to extract the end-of-file, not if your extraction just stops at the end-of-file.
file.eof()
will only tell you if the previous read hit the end-of-file and not if the next one will. After the last line has been extracted, the EOF bit is still not set and the iteration occurs one more time. However, on this last iteration, the extraction fails andline
still has the same content as before, i.e. the last line is duplicated.file.eof()只会告诉我们上一次读取是否命中文件末尾,而不会告诉我们下一次读取是否命中,提取最后一行后,eof()仍未置true,再迭代一次,才会置true。但在最后一次迭代中,提取到文件结束标志符,但行内容不变,因此最后一行被复制。
6. 比较两个向量
bool is_equal(vector<Point>& original, vector<Point>& processed){
if(original.size() != processed.size()){
perror("Something's wrong. Size is not equal!");
return false;
}
long v_size = original.size();
for(int i=0;i<v_size;i++){
if((original[i].x != processed[i].x)
&&(original[i].y != processed[i].y)){
perror("Something's wrong");
return false;
}
}
return true;
}
7. 完整代码
#include <iostream>
#include <vector>
#include <string>
#include <fstream> // !否则ifstream/ofstream会报错
using namespace std;
struct Point{
int x;
int y;
};
istream& operator>>(istream& is, Point& p);
ostream& operator<<(ostream& os, Point& p);
void Write_to_file(vector<Point>& points, string& name);
void Read_from_file(vector<Point>& points, string& name);
bool operator!=(Point& p1, Point& p2);
bool is_equal(vector<Point>& original, vector<Point>& processed);
int main(int argc, const char * argv[]) {
// 提示用户输入
vector<Point> original_points;
cout<< "Please input 7 set of Point(x,y):\n";
int num = 0;
while(num<7){
Point p;
cin>> p;
original_points.push_back(p);
num++;
}
// 打印验证
cout<< "Print the original_points:\n";
for(int i=0;i<original_points.size();i++)
cout<< original_points[i];
// 写文件
string filename = "my_data.txt";
Write_to_file(original_points, filename);
// 读文件
vector<Point> processed_points;
Read_from_file(processed_points, filename);
// 验证读入是否正确
cout<< "Verify reading\n";
for(int i=0;i<processed_points.size();i++){
cout<< processed_points[i];
}
// 比较两个向量是否相等
if(is_equal(original_points, processed_points))
cout<< "It's right!\n";
return 0;
}
istream& operator>>(istream& is, Point& p){
char ch1;
cin>> ch1;
if((ch1!='(') && (ch1!='\n'))
perror("Error:'('");
char ch2;
int x, y;
cin>> x>> ch2>> y;
if(ch2!=',')
perror("Error:','");
char ch3;
cin>> ch3;
if(ch3!=')')
perror("Error:')'");
p.x = x;
p.y = y;
return is;
}
ostream& operator<<(ostream& os, Point& p){
return os<< "("<< p.x<< ","<< p.y<< ")"<< endl;
}
void Write_to_file(vector<Point>& points, string& name){
ofstream ost{name};
if(!ost) perror("Can't open file.\n");
for(int i=0;i<points.size();i++){
ost<< points[i];
}
}
void Read_from_file(vector<Point>& points, string& name){
ifstream ist{name};
if(!ist) perror("Can't open file\n");
while(!ist.ios_base::eof()){
Point p;
char ch1, ch2, ch3;
int x, y;
ist>> ch1>> x>> ch2>> y>> ch3;
if(ist.ios_base::eof())
return;
if((ch1!='(') && (ch2!=',') && (ch3!=')'))
return;
p.x = x;
p.y = y;
points.push_back(p);
}
}
bool is_equal(vector<Point>& original, vector<Point>& processed){
if(original.size() != processed.size()){
perror("Something's wrong. Size is not equal!");
return false;
}
long v_size = original.size();
for(int i=0;i<v_size;i++){
if((original[i].x != processed[i].x)
&&(original[i].y != processed[i].y)){
perror("Something's wrong");
return false;
}
}
return true;
}