C++链表写入二进制文件时email字段随机丢失问题求助
问题分析:二进制文件保存链表时email字段随机失效
我尝试用agregar_cliente函数把链表写入二进制文件,但email字段会随机无法保存,没改代码的情况下有时正常有时出错。
用到的链表结构体代码:
struct Client_node { string name; string alias; string telefono; string email; int numero_de_ventas; Client_node* siguiente; }; Client_node* principio; Client_node* actual;
agregar_cliente函数代码:
void agregar_cliente(string name, string alias, string telefono, string email) { if (principio == nullptr) { principio = new Client_node; principio->name = name; principio->alias = alias; principio->telefono = telefono; principio->email = email; principio->numero_de_ventas = 0; principio->siguiente = nullptr; actual = principio; } else { actual = principio; while (actual->siguiente != nullptr) { actual = actual->siguiente; } actual->siguiente = new Client_node; actual->siguiente->siguiente = nullptr; actual = actual->siguiente; actual->name = name; actual->alias = alias; actual->telefono = telefono; actual->email = email; actual->numero_de_ventas = 0; } ofstream escritura_clientes; escritura_clientes.open("clientes.bin",ios::out,ios::binary); if (escritura_clientes.is_open()) { actual = principio; while (actual != nullptr) { escritura_clientes.write(reinterpret_cast<char*> (actual), sizeof(Client_node)); actual = actual->siguiente; } } escritura_clientes.close(); }
问题根源
直接把Client_node结构体整体写入二进制文件的方式完全错误。原因有两点:
std::string是非POD类型,它内部不存储真实字符串内容,只保存指向堆内存的指针、字符串长度等元数据。用sizeof(Client_node)写入文件时,实际写的是这些指针和元数据,而非字符串本身。当程序重启或内存布局变化时,这些指针指向的地址早已无效,读取时自然无法还原字符串,表现为字段随机失效。- 结构体里的
Client_node* siguiente指针也会被写入文件,这个指针仅在当前程序运行时有效,下次启动后完全是无效数据,毫无意义。
解决方案:序列化有效数据
要正确保存链表,需要手动序列化每个节点的有效内容(字符串真实值、数值字段),而非直接写入结构体。
1. 单独实现链表保存函数
void guardar_clientes() { ofstream escritura_clientes("clientes.bin", ios::out | ios::binary); if (!escritura_clientes.is_open()) { return; } // 先写入节点总数,方便读取时批量处理 int count = 0; Client_node* cnt_temp = principio; while (cnt_temp != nullptr) { count++; cnt_temp = cnt_temp->siguiente; } escritura_clientes.write(reinterpret_cast<char*>(&count), sizeof(count)); Client_node* temp = principio; while (temp != nullptr) { // 序列化string:先写长度,再写内容 size_t len = temp->name.size(); escritura_clientes.write(reinterpret_cast<char*>(&len), sizeof(len)); escritura_clientes.write(temp->name.c_str(), len); len = temp->alias.size(); escritura_clientes.write(reinterpret_cast<char*>(&len), sizeof(len)); escritura_clientes.write(temp->alias.c_str(), len); len = temp->telefono.size(); escritura_clientes.write(reinterpret_cast<char*>(&len), sizeof(len)); escritura_clientes.write(temp->telefono.c_str(), len); len = temp->email.size(); escritura_clientes.write(reinterpret_cast<char*>(&len), sizeof(len)); escritura_clientes.write(temp->email.c_str(), len); // 序列化int字段 escritura_clientes.write(reinterpret_cast<char*>(&temp->numero_de_ventas), sizeof(temp->numero_de_ventas)); temp = temp->siguiente; } escritura_clientes.close(); }
2. 实现链表读取(反序列化)函数
void cargar_clientes() { // 先清空原有链表,避免内存泄漏 Client_node* temp = principio; while (temp != nullptr) { Client_node* next = temp->siguiente; delete temp; temp = next; } principio = nullptr; actual = nullptr; ifstream lectura_clientes("clientes.bin", ios::in | ios::binary); if (!lectura_clientes.is_open()) { return; } int count; lectura_clientes.read(reinterpret_cast<char*>(&count), sizeof(count)); for (int i = 0; i < count; i++) { string name, alias, telefono, email; int numero_de_ventas; // 反序列化name size_t len; lectura_clientes.read(reinterpret_cast<char*>(&len), sizeof(len)); name.resize(len); lectura_clientes.read(&name[0], len); // 反序列化alias lectura_clientes.read(reinterpret_cast<char*>(&len), sizeof(len)); alias.resize(len); lectura_clientes.read(&alias[0], len); // 反序列化telefono lectura_clientes.read(reinterpret_cast<char*>(&len), sizeof(len)); telefono.resize(len); lectura_clientes.read(&telefono[0], len); // 反序列化email lectura_clientes.read(reinterpret_cast<char*>(&len), sizeof(len)); email.resize(len); lectura_clientes.read(&email[0], len); // 反序列化numero_de_ventas lectura_clientes.read(reinterpret_cast<char*>(&numero_de_ventas), sizeof(numero_de_ventas)); // 将读取的数据添加到链表 if (principio == nullptr) { principio = new Client_node; principio->name = name; principio->alias = alias; principio->telefono = telefono; principio->email = email; principio->numero_de_ventas = numero_de_ventas; principio->siguiente = nullptr; actual = principio; } else { actual = principio; while (actual->siguiente != nullptr) { actual = actual->siguiente; } actual->siguiente = new Client_node; actual->siguiente->siguiente = nullptr; actual = actual->siguiente; actual->name = name; actual->alias = alias; actual->telefono = telefono; actual->email = email; actual->numero_de_ventas = numero_de_ventas; } } lectura_clientes.close(); }
3. 修改原agregar_cliente函数
去掉函数内的文件保存逻辑,改为调用单独的guardar_clientes函数:
void agregar_cliente(string name, string alias, string telefono, string email) { if (principio == nullptr) { principio = new Client_node; principio->name = name; principio->alias = alias; principio->telefono = telefono; principio->email = email; principio->numero_de_ventas = 0; principio->siguiente = nullptr; actual = principio; } else { actual = principio; while (actual->siguiente != nullptr) { actual = actual->siguiente; } actual->siguiente = new Client_node; actual->siguiente->siguiente = nullptr; actual = actual->siguiente; actual->name = name; actual->alias = alias; actual->telefono = telefono; actual->email = email; actual->numero_de_ventas = 0; } // 调用单独的保存函数 guardar_clientes(); }
内容的提问来源于stack exchange,提问作者Mario Lopez
相关产品推荐
相关产品推荐

