C++链表数据写入.dat文件后丢失乱码的解决方案咨询
Let's break down exactly why your data is getting lost or showing up as garbage, then fix it with clear, actionable solutions.
Core Issues in Your Code
1. You're Writing an Uninitialized Object
In your write_linky function, you call fp.write((char*)&nod,sizeof(node)); — but nod is a private member of your List class that you never assign any values to. You're writing random garbage memory to the file, not the actual user data you just added to the linked list.
2. Binary-Writing std::string Is Broken
Your node struct uses std::string for fields like name and nationality. When you write the entire struct as binary data, you're only saving the pointer that std::string uses to store its characters (not the actual string content). When you read this back later, that pointer points to invalid memory, causing garbage values or crashes.
Solution 1: Text-Based Storage (Simple & Debug-Friendly)
Text format is perfect for this use case — it's human-readable, easy to debug, and avoids the pitfalls of binary serialization for complex types like std::string.
Updated write_linky Function
void List::write_linky(string name,string surName,int idNum,string nation,int number) { // Add the new node to your linked list first this->AddNode(name, surName, idNum, nation, number); this->printList(); // Open file in text append mode fstream fp("Link.dat", ios::out | ios::app | ios::text); if (!fp.is_open()) { cout << "\nFailed to open file for writing!" << endl; return; } // Write each field on a new line for clarity fp << name << endl; fp << surName << endl; fp << idNum << endl; fp << nation << endl; fp << number << endl; fp.close(); cout << "\n\nThe Data Has Been Added "; }
Updated read_linky Function
void List::read_linky(){ fstream fp("Link.dat", ios::in | ios::text); if (!fp.is_open()) { cout << "\nNo saved data found, or failed to open file!" << endl; return; } string name, surName, nation; int idNum, number; // Read each field in order until end of file while (getline(fp, name)) { getline(fp, surName); fp >> idNum; fp.ignore(); // Skip the newline left by >> operator getline(fp, nation); fp >> number; fp.ignore(); // Skip the newline again // Add the loaded data to your linked list this->AddNode(name, surName, idNum, nation, number); } fp.close(); this->printList(); // Print all loaded data once }
Solution 2: Proper Binary Serialization (If You Need Binary Format)
If you must use binary storage, you need to manually serialize std::string values by writing their length first, then the actual character data.
Updated write_linky Function
void List::write_linky(string name,string surName,int idNum,string nation,int number) { this->AddNode(name, surName, idNum, nation, number); this->printList(); fstream fp("Link.dat", ios::out | ios::binary | ios::app); if (!fp.is_open()) { cout << "\nFailed to open file for writing!" << endl; return; } // Get the last node we just added curr = head; while (curr->next != nullptr) { curr = curr->next; } node* newNode = curr; // Serialize std::string: write length first, then characters // Write name size_t strLen = newNode->name.size(); fp.write((char*)&strLen, sizeof(strLen)); fp.write(newNode->name.c_str(), strLen); // Write surname strLen = newNode->surname.size(); fp.write((char*)&strLen, sizeof(strLen)); fp.write(newNode->surname.c_str(), strLen); // Write integer fields directly fp.write((char*)&newNode->idNum, sizeof(newNode->idNum)); // Write nationality strLen = newNode->nationality.size(); fp.write((char*)&strLen, sizeof(strLen)); fp.write(newNode->nationality.c_str(), strLen); // Write contact number fp.write((char*)&newNode->number, sizeof(newNode->number)); fp.close(); cout << "\n\nThe Data Has Been Added "; }
Updated read_linky Function
void List::read_linky(){ fstream fp("Link.dat", ios::in | ios::binary); if (!fp.is_open()) { cout << "\nNo saved data found, or failed to open file!" << endl; return; } string name, surName, nation; int idNum, number; size_t strLen; while (true) { // Read name length and content if (!fp.read((char*)&strLen, sizeof(strLen))) break; name.resize(strLen); fp.read(&name[0], strLen); // Read surname if (!fp.read((char*)&strLen, sizeof(strLen))) break; surName.resize(strLen); fp.read(&surName[0], strLen); // Read ID number if (!fp.read((char*)&idNum, sizeof(idNum))) break; // Read nationality if (!fp.read((char*)&strLen, sizeof(strLen))) break; nation.resize(strLen); fp.read(&nation[0], strLen); // Read contact number if (!fp.read((char*)&number, sizeof(number))) break; this->AddNode(name, surName, idNum, nation, number); } fp.close(); this->printList(); }
Additional Quick Fixes
- Remove the unused
nodmember: You have anode nod;in yourListclass that's never used — delete it to avoid confusion. - Simplify
isEmptyfunction: Sinceheadis a class member, you don't need to pass it as a parameter:bool isEmpty(){ return head == nullptr; } - Avoid global
fstream: Replace the globalfstream fpwith local instances insidewrite_linkyandread_linkyto prevent unexpected behavior.
内容的提问来源于stack exchange,提问作者gago

