You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将链表写入二进制文件并读取,避免程序崩溃丢失节点数据?

嘿,我来帮你搞定链表节点持久化到二进制文件的问题!先从你现有代码里的几个小问题说起,再一步步实现正确的保存和读取逻辑。

先修正现有代码的小错误

你的代码里有几个编译不过的小问题,得先搞定:

  • Node类里的doble是拼写错误,应该是double;
  • addNode方法里用了newnode->data,但Node类里并没有data成员,应该对应你定义的code(或者price/name,看你实际要存的数值);
  • 析构函数是空的,记得要遍历链表释放节点,不然会内存泄漏。

为什么你设想的saveOn方法不可行?

你当前的saveOn用的是文本输出(os << ...),而且只存了单个字段,既不是二进制格式,也没有保存节点的所有数据(比如price、name)。更关键的是:绝对不能保存next指针——程序重启后,内存地址是重新分配的,旧指针完全无效,我们只需要保存节点的业务数据,读取时重新构建链表结构。

实现二进制保存(saveOn)

要写入二进制文件,我们需要用ostream::write()方法,把每个节点的非指针数据序列化到文件。对于std::string,因为它是动态长度的,不能直接写入整个对象,得先写入字符串的长度,再写入字符内容。

修改后的核心代码如下:

#include <fstream>
#include <string>
#include <iostream>

// 修正Node类的拼写错误
class Node {
public:
    int code;
    double price;
    std::string name;
    Node* next;
};

class LinkedList{
public:
    LinkedList() : head(nullptr) {}
    ~LinkedList() {
        // 析构函数添加节点释放逻辑
        Node* temp = head;
        while (temp != nullptr) {
            Node* next = temp->next;
            delete temp;
            temp = next;
        }
    }
    void addNode(int code, double price, const std::string& name);
    void reverseList();
    void display();
    bool saveOn(const std::string& filename); 
    bool loadFrom(const std::string& filename); 

private:
    Node* head;
};

// 修正addNode方法,支持添加完整节点数据
void LinkedList::addNode(int code, double price, const std::string& name) {
    Node* newnode = new Node();
    newnode->code = code;
    newnode->price = price;
    newnode->name = name;
    newnode->next = nullptr;
    if (head == nullptr) {
        head = newnode;
    } else {
        Node* temp = head;
        while (temp->next != nullptr) {
            temp = temp->next;
        }
        temp->next = newnode;
    }
}

// 实现二进制保存方法
bool LinkedList::saveOn(const std::string& filename) {
    std::ofstream os(filename, std::ios::binary);
    if (!os.is_open()) {
        std::cerr << "Failed to open file for writing!" << std::endl;
        return false;
    }

    Node* temp = head;
    while (temp != nullptr) {
        // 写入int类型的code
        os.write(reinterpret_cast<const char*>(&temp->code), sizeof(temp->code));
        // 写入double类型的price
        os.write(reinterpret_cast<const char*>(&temp->price), sizeof(temp->price));
        // 处理string:先写入长度,再写入字符
        size_t nameLen = temp->name.size();
        os.write(reinterpret_cast<const char*>(&nameLen), sizeof(nameLen));
        os.write(temp->name.c_str(), nameLen);

        temp = temp->next;
    }

    os.close();
    return true;
}

实现从二进制文件读取(loadFrom)

读取的时候,我们需要按保存的顺序反向操作:先读code、price,再读字符串长度和字符,然后创建节点添加到链表。注意读取前要清空现有链表的节点,避免内存泄漏。

bool LinkedList::loadFrom(const std::string& filename) {
    // 先清空现有链表
    Node* temp = head;
    while (temp != nullptr) {
        Node* next = temp->next;
        delete temp;
        temp = next;
    }
    head = nullptr;

    std::ifstream is(filename, std::ios::binary);
    if (!is.is_open()) {
        std::cerr << "Failed to open file for reading!" << std::endl;
        return false;
    }

    while (true) {
        Node* newnode = new Node();
        // 读取code,读到文件末尾则退出
        if (!is.read(reinterpret_cast<char*>(&newnode->code), sizeof(newnode->code))) {
            delete newnode;
            break;
        }
        // 读取price
        is.read(reinterpret_cast<char*>(&newnode->price), sizeof(newnode->price));
        // 读取string长度和内容
        size_t nameLen;
        is.read(reinterpret_cast<char*>(&nameLen), sizeof(nameLen));
        char* nameBuf = new char[nameLen + 1];
        is.read(nameBuf, nameLen);
        nameBuf[nameLen] = '\0'; // 确保字符串以null结尾
        newnode->name = nameBuf;
        delete[] nameBuf;

        newnode->next = nullptr;
        // 添加到链表末尾
        if (head == nullptr) {
            head = newnode;
        } else {
            Node* tail = head;
            while (tail->next != nullptr) {
                tail = tail->next;
            }
            tail->next = newnode;
        }
    }

    is.close();
    return true;
}

使用示例

int main() {
    LinkedList list;
    list.addNode(1, 9.99, "Apple");
    list.addNode(2, 19.99, "Banana");
    list.display();

    // 保存到文件
    list.saveOn("linked_list_data.bin");

    // 创建新链表,读取文件内容
    LinkedList newList;
    newList.loadFrom("linked_list_data.bin");
    newList.display(); // 输出应该和原链表完全一致

    return 0;
}

注意事项

  • 打开文件时一定要加上std::ios::binary标志,避免系统自动转换换行符等文本格式;
  • 序列化和反序列化的顺序必须严格一致(先存的先读);
  • 如果你的Node类以后添加了新成员,要同步修改保存和读取逻辑,不然会导致数据错乱;
  • 可以考虑添加一个"节点数量"的头信息,先写入链表的节点总数,读取时按数量读取,这样比读到文件末尾更可靠。

内容的提问来源于stack exchange,提问作者josilva00

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 19:02:57