C++读取二进制存储的类对象打印字符串出现乱码 如何解决?
问题根因
- 核心原因是
std::string不属于可直接二进制序列化的POD(普通旧数据)类型:std::string内部只持有指向堆内存的字符串指针,你直接将类对象内存整块写入文件时,存储的是指针地址而非实际的字符串内容。读取时该指针指向的内存已经失效,自然输出乱码。 - 次要原因是读取逻辑的
while(!fin.eof())判断错误:eof标记是在读取操作失败后才会被置位,该写法会导致最后一次读取失败后,依然执行一次st.showData(),输出无效内容。
修复方案
最适合小型数据库场景的修复方式是将动态的std::string替换为固定长度的字符数组,让Student类成为POD类型,支持直接整块读写,同时修正读取判断逻辑即可:
- 将
string name替换为char name[N](N为你需要的最大名字长度,比如64),保证类内存储的是实际的字符串内容,没有外部指针。 - 移除
setData冗余的传参和返回值逻辑,直接修改当前类的成员变量即可。 - 将读取逻辑的判断条件改为直接判断
read操作的返回值,只有读取成功才输出数据。
修正后可正常运行的代码
#include<iostream> #include<fstream> #include<cstring> using namespace std; class Student { // 数据成员 int adm; // 固定长度字符数组,存储实际字符串内容 char name[64]; public: Student() { adm = 0; memset(name, 0, sizeof(name)); } Student(int a, const char* n) { adm = a; strncpy(name, n, sizeof(name)-1); // 保证字符串以\0结尾 name[sizeof(name)-1] = '\0'; } // 优化冗余逻辑,直接修改当前对象成员 void setData() { cout << "\nEnter admission no. "; cin >> adm; cout << "Enter name of student "; cin.ignore(); cin.getline(name, sizeof(name)); } void showData() { cout << "\nAdmission no. : " << adm; cout << "\nStudent Name : " << name << endl; } int retAdmno() { return adm; } }; /* * 二进制文件读写函数 */ void demo() { ofstream f; f.open("student.dat",ios::binary); for(int i = 0;i<4;i++) { Student st; st.setData(); f.write((char*)&st,sizeof(st)); } f.close(); ifstream fin; fin.open("student.dat",ios::binary); Student st; // 修正读取判断逻辑,读取成功才执行输出 while(fin.read((char*)&st,sizeof(st))) { st.showData(); } fin.close(); } int main() { demo(); return 0; }
可选变长字符串方案
如果你不希望限制名字长度,可以自行实现序列化逻辑,不需要用固定长度数组:
- 写入时依次写入:
adm的int值、name的长度值、name的实际字符内容 - 读取时依次读取:
adm的int值、name的长度值、对应长度的字符,赋值给std::string即可
内容的提问来源于stack exchange,提问作者Suraj Joshi
相关产品推荐
相关产品推荐

