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

C++双向链表实现异常:仅能存储首个值,请求排查问题

你的双向链表实现核心问题分析与修正

我仔细梳理了你的代码,确实是LookingforRecord函数里存在几个关键错误,导致你只能保存第一个值,还无法找到已有的ID记录。下面逐个拆解问题并给出修正方案:

1. 新增节点时的data赋值完全错误

在LookingforRecord的add分支里,你写了:

p_node->data = m_p_node;

这明显是笔误!你本来要把传入的data值存在节点里,结果却把链表头指针m_p_node赋值给了uint8_t类型的data——这不仅会导致数据存储错乱,还可能触发类型转换的未定义行为。

正确写法:

p_node->data = data; // 使用add函数传入的data参数赋值

2. 新增节点时未正确更新链表头指针m_p_node

当向非空链表添加新节点时,你只设置了原头节点的p_prev指向新节点,但没有把m_p_node更新为新的头节点。这就导致后续遍历链表时,永远从最初的第一个节点开始,根本看不到新添加的节点。

原错误代码片段:

if ((p_node = new node) != 0) {
    memset(p_node, 0, sizeof(node));
    p_node->ID = ID;
    p_node->data = m_p_node; // 这里也错了
    p_node->p_next = m_p_node;
    if (m_p_node != 0)
        m_p_node->p_prev = p_node;
    else
        m_p_node = p_node;
}

修正后,不管链表是否为空,都要把m_p_node指向新节点(因为你是在头部插入新节点):

if ((p_node = new node) != nullptr) {
    // 逐个初始化成员,比memset更安全(避免未来结构体添加非POD成员出问题)
    p_node->ID = ID;
    p_node->data = data; // 修正data赋值
    p_node->p_prev = nullptr;
    p_node->p_next = m_p_node;
    
    if (m_p_node != nullptr) {
        m_p_node->p_prev = p_node;
    }
    // 必须更新头指针为新节点
    m_p_node = p_node;
}

3. LookingforRecord函数返回类型拼写错误

在List.cpp中,你写了:

list::Node * list::LookingforRecord(uint16_t ID, bool add)

但你的结构体是小写的node,不是大写的Node,这会导致编译错误。正确返回类型应为:

list::node * list::LookingforRecord(uint16_t ID, bool add)

4. 类成员函数printf与全局函数重名

你的类成员函数void list::printf(uint16_t ID)和标准库的全局printf重名了,会导致调用歧义。建议把成员函数名改成print或printRecord,同时在函数内部明确调用全局printf:

修正后的print函数:

void list::print(uint16_t ID) {
    node * p_node = LookingforRecord(ID, false);
    if (p_node != nullptr) {
        ::printf("p_node->ID %d \r\n", p_node->ID);
        ::printf("p_node->data %d \r\n", p_node->data);
    }
}

5. 冗余全局变量需删除

你在List.cpp顶部定义的uint16_t ID = 0;完全没有被使用,建议删掉,避免混淆。

修正后的关键函数代码

LookingforRecord修正版

list::node * list::LookingforRecord(uint16_t targetID, bool add) {
    node * p_node = m_p_node;
    while (p_node != nullptr) {
        if (p_node->ID == targetID) {
            return p_node;
        }
        p_node = p_node->p_next;
    }

    if (add) {
        node* newNode = new node;
        if (newNode != nullptr) {
            newNode->ID = targetID;
            newNode->data = 0; // 先初始化,后续add函数会覆盖
            newNode->p_prev = nullptr;
            newNode->p_next = m_p_node;

            if (m_p_node != nullptr) {
                m_p_node->p_prev = newNode;
            }
            m_p_node = newNode;
        }
        return newNode;
    }

    return nullptr;
}

add函数修正版

uint8_t list::add(uint16_t ID, uint8_t data) {
    node * p_node = LookingforRecord(ID, true);
    if (p_node != nullptr) {
        p_node->data = data;
        return ID; // 按你原逻辑返回ID作为batch_size
    }
    return 0; // 添加失败返回0
}

额外优化建议

  • 尽量用nullptr代替0/NULL表示空指针,这是C++11及以后的标准写法,类型更安全。
  • 可以给node结构体添加构造函数,简化初始化:
    struct node {
        uint16_t ID;
        uint8_t data;
        node * p_prev;
        node * p_next;
        
        node(uint16_t id, uint8_t d) : ID(id), data(d), p_prev(nullptr), p_next(nullptr) {}
    };
    
    新增节点时直接写new node(ID, data),代码更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:21:59