二进制读取Dog类时程序崩溃,写入代码正常求解决
问题分析与解决方案
嘿,我来帮你搞定这个崩溃问题!你的写入代码运行正常,但读取逻辑里有两个关键错误导致了程序崩溃,咱们一个个来看:
1. 未初始化的野指针导致内存访问错误
在读取代码里,你只声明了Dog* dog;,但这个指针并没有指向任何有效的内存空间——它的值是随机的垃圾地址。当你调用fread(dog, sizeof(Dog), 1, file);时,程序会尝试把文件数据写入这个随机地址,直接触发内存访问违规,这就是崩溃的直接原因。
修复方法:
你需要给指针分配有效的内存,或者直接使用栈上的对象:
方式一:使用栈对象+拷贝到堆(推荐,更安全)
FILE* file = fopen(filePath.toStdString().c_str(), "rb"); if (file == NULL) { QMessageBox::critical(this, "Ошибка!", "Ошибка при открытии файла!"); return; } Dog tempDog; // 栈上分配对象,自动管理内存 while (fread(&tempDog, sizeof(Dog), 1, file) == 1) { _list->emplace_back(new Dog(tempDog)); // 拷贝到堆内存,加入列表 } fclose(file);
方式二:直接在堆上分配内存
FILE* file = fopen(filePath.toStdString().c_str(), "rb"); if (file == NULL) { QMessageBox::critical(this, "Ошибка!", "Ошибка при открытии файла!"); return; } Dog* dog; while (true) { dog = new Dog(); // 分配堆内存 if (fread(dog, sizeof(Dog), 1, file) != 1) { delete dog; // 读取失败时释放内存,避免泄漏 break; } _list->emplace_back(dog); } fclose(file);
2. while (!feof(file))的错误用法
feof()函数只有在尝试读取超出文件末尾之后才会返回true,所以你的原循环会多执行一次:当最后一次fread已经读取失败时,你仍然会把无效的dog指针加入列表,这也可能导致后续的崩溃或异常行为。
正确的做法是直接判断fread的返回值——fread会返回成功读取的元素个数,当返回值不等于1时,说明已经读到文件末尾或者读取失败,此时应该退出循环。
额外注意事项
如果你的Dog类包含非POD类型的成员(比如std::string、QString、动态分配的数组等),直接用fread/fwrite二进制读写会导致问题:这些成员存储的是内存指针,写入文件后,再读取时指针指向的地址已经无效,会引发未定义行为。
这种情况下,建议使用Qt的序列化机制(比如QDataStream)来处理对象的读写,它能正确处理Qt类型和自定义类型的序列化。
内容的提问来源于stack exchange,提问作者garbart
相关产品推荐
相关产品推荐

