二进制读写的问题

Watermelon_Bigger 2013-08-07 07:47:37
调试时,到的这一条语句st.update(age,name);出现错误,恳请各位大侠指出错误。
原意是想更新第一条记录的,可是老出现错误。


#include<iostream>
#include<fstream>
#include<cstdlib>
using namespace std;
class student
{
private:
int age; //年龄
string name; //姓名
public:
student()=default;
student(int a,string n):age(a),name(n){}
void update(int a,string n) //更新学生数据
{
age=a;
name=n;
}
friend ostream& operator<<(ostream &os,student stu) //重载==操作符
{
os<<"age : "<<stu.age<<ends<<"name : "<<stu.name<<endl;
}
};

void print(fstream &f) //打印所有数据
{
f.seekg(0,f.end);
int n=f.tellg()/sizeof(student);
f.seekg(0,f.beg);
student st;
for(int i=0;i<n;i++)
{

f.read((char*)&st,sizeof(student));
cout<<st;
}
}

int main(int argc, char** argv)
{
fstream f("test.dat",ios::in|ios::out|ios::trunc|ios::binary);
if(!f)
{
cerr<<"file can't open!"<<endl;
exit(-1);
}

student st(18,"nobody");
for(int i=0;i<5;i++) //初始化5条记录
{

f.write((char*)&st,sizeof(student));

}

print(f);

int age;string name;
cout<<"input age,name to update"<<endl;
cin>>age>>name;
st.update(age,name);
f.seekg(0*sizeof(student),f.beg);
f.write((char*)&st,sizeof(student));
print(f);



return 0;
}
...全文
204 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
max_min_ 2013-08-08
  • 打赏
  • 举报
回复
引用 4 楼 u010958072 的回复:
[quote=引用 3 楼 mujiok2003 的回复:]
 
class student
 {
 private:
 int age;  //年龄 
string name; //姓名 
//..
  
f.read((char*)&st,sizeof(student));

 f.write((char*)&st,sizeof(student));

你可以知道name是较复杂的c++对象。
能说得简单点不,直接指明问题所在,本人菜鸟。[/quote] string 类型比较复杂,在类中如果有字符串的成员,最好还是用char数组 比较实在靠谱,string很容易出问题!
Watermelon_Bigger 2013-08-08
  • 打赏
  • 举报
回复
引用 5 楼 ananluowei 的回复:
string是对象,里面包含一些指针,不能直接读写。指针是内存地址,直接写地址到文件,下次再读出来的地址是没有意义的。
string按二进制读写,要读写string实际的内容,而不是读写string本身。
写:先写一个string.size(),然后把string.data()用二进制方式写进去。
读:先读一个长度(4字节),根据这个长度,决定后面应该读几个字节的内容,再生成一个string。


引用 6 楼 mujiok2003 的回复:
[quote=引用 4 楼 u010958072 的回复:]
能说得简单点不,直接指明问题所在,本人菜鸟。


给你改好了
#include<iostream>
#include<fstream>
//#include<cstdlib>
#include <string>
#include <cstring>
........
........
}
[/quote]



用VS2012重新调试了一下,原来问题不是出现在st.update(age,name);
而是在运行完print(f);
运行结果:


VS提示:First-chance exception at 0x6774CCD2 (msvcp110d.dll) in Hello.exe: 0xC0000005: Access violation writing location 0x00000001.
调试停止在(*_Pnext)->_Myproxy = 0;

问题:是文件指针超出了范围吗?该怎么解决?(50分)

inline void _Container_base12::_Orphan_all()
{ // orphan all iterators
#if _ITERATOR_DEBUG_LEVEL == 2
if (_Myproxy != 0)
{ // proxy allocated, drain it
_Lockit _Lock(_LOCK_DEBUG);

for (_Iterator_base12 **_Pnext = &_Myproxy->_Myfirstiter;
*_Pnext != 0; *_Pnext = (*_Pnext)->_Mynextiter)
(*_Pnext)->_Myproxy = 0;
_Myproxy->_Myfirstiter = 0;
}
#endif /* _ITERATOR_DEBUG_LEVEL == 2 */
}



源代码:

#include<iostream>
#include<fstream>
#include<string>
using namespace std;
class student
{
private:
int age; //年龄
string name; //姓名
public:
student(){}
student(int a,string n):age(a),name(n){}
void update(int a,string n) //更新学生数据
{
age=a;
name=n;
}
friend ostream& operator<<(ostream &os,student stu) //重载==操作符
{
os<<"age : "<<stu.age<<ends<<"name : "<<stu.name<<endl;
return os;
}
};

void print(fstream &f) //打印所有数据
{
f.seekg(0,f.end);
int n=f.tellg()/sizeof(student);
f.seekg(0,f.beg);
student st;
for(int i=0;i<n;i++)
{

f.read((char*)&st,sizeof(student));
cout<<st;
}
}

int main(int argc, char** argv)
{
fstream f("test.dat",ios::in|ios::out|ios::trunc|ios::binary);
if(!f)
{
cerr<<"file can't open!"<<endl;
exit(-1);
}

student st(18,"nobody");
for(int i=0;i<2;i++) //初始化5条记录
{

f.write((char*)&st,sizeof(student));

}

print(f);

int age;string name;
cout<<"input age,name to update"<<endl;
cin>>age>>name;
st.update(age,name);
f.seekg(0*sizeof(student),f.beg);
f.write((char*)&st,sizeof(student));
print(f);



return 0;
}
赵4老师 2013-08-08
  • 打赏
  • 举报
回复
string是对象,不是一段内存。
ri_aje 2013-08-08
  • 打赏
  • 举报
回复
引用 7 楼 u010958072 的回复:
[quote=引用 5 楼 ananluowei 的回复:] string是对象,里面包含一些指针,不能直接读写。指针是内存地址,直接写地址到文件,下次再读出来的地址是没有意义的。 string按二进制读写,要读写string实际的内容,而不是读写string本身。 写:先写一个string.size(),然后把string.data()用二进制方式写进去。 读:先读一个长度(4字节),根据这个长度,决定后面应该读几个字节的内容,再生成一个string。
引用 6 楼 mujiok2003 的回复:
[quote=引用 4 楼 u010958072 的回复:] 能说得简单点不,直接指明问题所在,本人菜鸟。
给你改好了
#include<iostream>
#include<fstream>
//#include<cstdlib>
#include <string>
#include <cstring>
........
........
} 
[/quote] 用VS2012重新调试了一下,原来问题不是出现在st.update(age,name); 而是在运行完print(f);后 运行结果: VS提示:First-chance exception at 0x6774CCD2 (msvcp110d.dll) in Hello.exe: 0xC0000005: Access violation writing location 0x00000001. 调试停止在(*_Pnext)->_Myproxy = 0; 问题:是文件指针超出了范围吗?该怎么解决?(50分) inline void _Container_base12::_Orphan_all() { // orphan all iterators #if _ITERATOR_DEBUG_LEVEL == 2 if (_Myproxy != 0) { // proxy allocated, drain it _Lockit _Lock(_LOCK_DEBUG); for (_Iterator_base12 **_Pnext = &_Myproxy->_Myfirstiter; *_Pnext != 0; *_Pnext = (*_Pnext)->_Mynextiter) (*_Pnext)->_Myproxy = 0; _Myproxy->_Myfirstiter = 0; } #endif /* _ITERATOR_DEBUG_LEVEL == 2 */ } 源代码:

#include<iostream>
#include<fstream>
#include<string>
 using namespace std;
class student
{
private:
int age;  //年龄 
string name; //姓名 
public:
	student(){}
    student(int a,string n):age(a),name(n){}
    void update(int a,string n) //更新学生数据 
    {
        age=a;
        name=n;
    }
 friend ostream& operator<<(ostream &os,student stu) //重载==操作符 
 {
   os<<"age : "<<stu.age<<ends<<"name : "<<stu.name<<endl;
   return os;
 }
}; 

void print(fstream &f) //打印所有数据 
{
f.seekg(0,f.end);
int n=f.tellg()/sizeof(student);
f.seekg(0,f.beg);
student st;
 for(int i=0;i<n;i++)
    {
    
       f.read((char*)&st,sizeof(student));
        cout<<st;
    }
}

int main(int argc, char** argv) 
{
fstream f("test.dat",ios::in|ios::out|ios::trunc|ios::binary);
if(!f)
{
cerr<<"file can't open!"<<endl;
exit(-1);
}

student st(18,"nobody");
    for(int i=0;i<2;i++) //初始化5条记录 
    {
    	
    	f.write((char*)&st,sizeof(student));
    	
    }
   
    print(f);
   
    int age;string name;
    cout<<"input age,name to update"<<endl;
	cin>>age>>name;
    st.update(age,name);
   	f.seekg(0*sizeof(student),f.beg);
   	f.write((char*)&st,sizeof(student));
    print(f);
    	
   
   
return 0;
}
[/quote] 错误太多,不一一说了,写了个例子,希望对你有帮助。重点就是 std::string 不能直接复制内存,需要将字符串的大小和内容分别通过二进制格式输出。 ps. 如果你的编译器不认 {...} 的语法,自己改成相应的构造函数即可。

#include<iostream>
#include<fstream>
#include<string>
#include<vector>
using namespace std;
struct student
{
 int    age;
 string name;

 student(){}
 student(int a,string const& n):age(a),name(n){}

 friend ostream& operator<<(ostream &os,student const& stu)
 {
  os<<"age : "<<stu.age<<ends<<"name : "<<stu.name;
  return os;
 }
};

// read a binary file as a sequence of student object.
// assuming no memory gaps between objects.
void read (fstream& f, std::vector<student>& students)
{
 while (f)
 {
  students.push_back({});
  student& s = students.back();

  f.read(reinterpret_cast<char*>(&s.age),sizeof(s.age));

  int size = 0;
  f.read(reinterpret_cast<char*>(&size),sizeof(size));

  s.name.resize(size);
  f.read(&s.name[0],size);
 }
}

// write a sequence of student objects in binary format.
// all memory laid out immediately without gaps between objects.
void write (fstream& f, std::vector<student>const& students)
{
 for (size_t i = 0, I = students.size(); i != I; ++i)
 {
  student const& s = students[i];

  f.write(reinterpret_cast<char const*>(&s.age),sizeof(s.age));

  int const size = s.name.size();
  f.write(reinterpret_cast<char const*>(&size),sizeof(size));

  f.write(&s.name[0],size);
 }
}

int main ()
{
 fstream f("test.dat",ios::in|ios::out|ios::trunc|ios::binary);
 if(!f)
 {
  cerr<<"file can't open!"<<endl;
  exit(-1);
 }

 std::vector<student> students;
 students.push_back({18,"nobody"});
 students.push_back({19,"somebody"});

 std::cout << students[0] << std::endl;
 std::cout << students[1] << std::endl;

 // write to file in binary format.
 write(f,students);

 // delete all students.
 students.clear();

 // read back students previously stored in file.
 f.seekg(0,ios::beg);
 std::cout << "read binary" << std::endl;
 read(f,students);
 std::cout << students[0] << std::endl;
 std::cout << students[1] << std::endl;
}
mujiok2003 2013-08-07
  • 打赏
  • 举报
回复
引用 4 楼 u010958072 的回复:
能说得简单点不,直接指明问题所在,本人菜鸟。
给你改好了
#include<iostream>
#include<fstream>
//#include<cstdlib>
#include <string>
#include <cstring>

using namespace std;
class student
{
private:
	int age;  //年龄 
	//string name; //姓名 
	char name[64];
public:
	student(){}
	student(int a,string n):age(a)
	{
		strncpy_s(name, n.c_str(), n.length());
	}
	void update(int a,string n) //更新学生数据 
	{
		age=a;
		strncpy_s(name, n.c_str(), n.length());
	}
	friend ostream& operator<<(ostream &os,student stu) //重载==操作符 
	{
		return os<<"age : "<<stu.age<<ends<<"name : "<<stu.name<<endl;
	}
}; 

void print(fstream &f) //打印所有数据 
{
	f.seekg(0,f.end);
	int n=f.tellg()/sizeof(student);
	f.seekg(0,f.beg);
	student st;
	for(int i=0;i<n;i++)
	{

		f.read((char*)&st,sizeof(student));
		cout<<st;
	}
}

int main(int argc, char** argv) 
{
	fstream f("test.dat",ios::in|ios::out|ios::trunc|ios::binary);
	if(!f)
	{
		cerr<<"file can't open!"<<endl;
		exit(-1);
	}

	student st(18,"nobody");
	for(int i=0;i<5;i++) //初始化5条记录 
	{

		f.write((char*)&st,sizeof(student));

	}

	print(f);

	int age;string name;
	cout<<"input age,name to update"<<endl;
	cin>>age>>name;
	st.update(age,name);
	f.seekg(0*sizeof(student),f.beg);
	f.write((char*)&st,sizeof(student));
	print(f);
       return 0;
} 
大尾巴猫 2013-08-07
  • 打赏
  • 举报
回复
string是对象,里面包含一些指针,不能直接读写。指针是内存地址,直接写地址到文件,下次再读出来的地址是没有意义的。 string按二进制读写,要读写string实际的内容,而不是读写string本身。 写:先写一个string.size(),然后把string.data()用二进制方式写进去。 读:先读一个长度(4字节),根据这个长度,决定后面应该读几个字节的内容,再生成一个string。
Watermelon_Bigger 2013-08-07
  • 打赏
  • 举报
回复
引用 3 楼 mujiok2003 的回复:
 
class student
 {
 private:
 int age;  //年龄 
string name; //姓名 
//..
  
f.read((char*)&st,sizeof(student));

 f.write((char*)&st,sizeof(student));

你可以知道name是较复杂的c++对象。
能说得简单点不,直接指明问题所在,本人菜鸟。
mujiok2003 2013-08-07
  • 打赏
  • 举报
回复
 
class student
 {
 private:
 int age;  //年龄 
string name; //姓名 
//..
  
f.read((char*)&st,sizeof(student));

 f.write((char*)&st,sizeof(student));

你可以知道name是较复杂的c++对象。
Watermelon_Bigger 2013-08-07
  • 打赏
  • 举报
回复
[quote=引用 1 楼 max_min_ 的回复:] 简化了下你的代码,测试 没有问题阿! ........ ........ 分开测试确实没有问题,可结合起来就出问题了,单步调试时,运行到st.update(age,name); 这条语句就运行不下去了,我用的是devC++ 5.4.2。
max_min_ 2013-08-07
  • 打赏
  • 举报
回复
简化了下你的代码,测试 没有问题阿!

using namespace std;
class student
{
    private:
        int age;  //年龄 
        string name; //姓名 
    public:
        student()=default;
        student(int a,string n):age(a),name(n){
        }   
        void update(int a,string n) //更新学生数据 
        {   
            age=a;
            name=n;
        }   
        friend ostream& operator<<(ostream &os,student stu) //重载==操作符 
        {   
            os<<"age : "<<stu.age<<endl<<"name : "<<stu.name<<endl;
        }   
};

int main(void)
{
    student st(18,"nobody");
    int age;
    string name;
    cout<<"input age,name to update"<<endl;
    cin>>age>>name;

    st.update(age,name);

    cout << st << endl;
}
结果:

input age,name to update
100
csdn
age : 100
name : csdn

33,311

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 新手乐园
社区管理员
  • 新手乐园社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧