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

双向链表节点交换函数触发Segmentation Fault,请求排查问题

分析双向链表节点交换函数的段错误问题

看起来你的交换函数忽略了几种关键边界情况,而且赋值顺序也存在问题,这直接导致了段错误。咱们一步步拆解问题:

原函数的核心问题

  • 未处理头节点的情况:如果node1是链表的头节点,那么node1->prev是NULL。当你执行node2->prev = node1->prev后,node2->prev也变成NULL,最后一行(node2->prev)->next = node2就会尝试访问NULL指针的成员,直接触发段错误。
  • 未处理节点相邻的情况:如果node1和node2是相邻节点(比如node1是node2的直接前驱),你的赋值顺序会破坏链表的关联关系,导致指针指向混乱,甚至出现野指针。
  • 未处理节点相同的情况:如果传入的node1和node2是同一个节点,函数会导致自循环,虽然不一定直接触发段错误,但也是逻辑bug。
  • 赋值顺序错误:你先修改了node1->next,后续操作依赖的原链表结构已经被破坏,导致后续指针赋值出错。

修正后的交换函数

先处理特殊情况,再按正确顺序修改指针:

void swap_node(punt node1, punt node2) {
    // 处理两个节点相同的情况,直接返回
    if (node1 == node2) {
        return;
    }

    // 先保存原指针,避免修改后丢失链表关联信息
    punt prev1 = node1->prev;
    punt next1 = node1->next;
    punt prev2 = node2->prev;
    punt next2 = node2->next;

    // 情况1:node1是node2的直接前驱
    if (next1 == node2) {
        // 调整node1的前驱和后继
        node1->prev = node2;
        node1->next = next2;
        // 调整node2的前驱和后继
        node2->prev = prev1;
        node2->next = node1;
        // 调整node1后继的前驱(如果存在)
        if (next2 != NULL) {
            next2->prev = node1;
        }
        // 调整node2前驱的后继(如果存在)
        if (prev1 != NULL) {
            prev1->next = node2;
        }
    }
    // 情况2:node2是node1的直接前驱
    else if (next2 == node1) {
        // 复用上面的逻辑,交换两个节点即可
        swap_node(node2, node1);
        return;
    }
    // 情况3:两个节点不相邻
    else {
        // 调整node1的前驱和后继
        node1->prev = prev2;
        node1->next = next2;
        // 调整node2的前驱和后继
        node2->prev = prev1;
        node2->next = next1;

        // 调整node1原前驱的后继(如果存在)
        if (prev1 != NULL) {
            prev1->next = node2;
        }
        // 调整node1原后继的前驱(如果存在)
        if (next1 != NULL) {
            next1->prev = node2;
        }
        // 调整node2原前驱的后继(如果存在)
        if (prev2 != NULL) {
            prev2->next = node1;
        }
        // 调整node2原后继的前驱(如果存在)
        if (next2 != NULL) {
            next2->prev = node1;
        }
    }
}

关键说明

  1. 先保存原指针:在修改任何指针之前,先把所有需要用到的原前驱、后继指针保存下来,避免修改后丢失原链表的关联信息。
  2. 分情况处理相邻节点:相邻节点的交换逻辑和非相邻节点不同,需要单独处理,避免指针混乱。
  3. 空指针检查:所有涉及->next或->prev的访问前,都先检查指针是否为NULL,避免访问空指针导致段错误。
  4. 处理相同节点:直接返回,避免无意义的操作和潜在的自循环问题。

这样修改后,你的函数就能正确处理所有边界情况,不会再触发段错误了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 06:57:54