双向链表节点交换函数触发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; } } }
关键说明
- 先保存原指针:在修改任何指针之前,先把所有需要用到的原前驱、后继指针保存下来,避免修改后丢失原链表的关联信息。
- 分情况处理相邻节点:相邻节点的交换逻辑和非相邻节点不同,需要单独处理,避免指针混乱。
- 空指针检查:所有涉及
->next或->prev的访问前,都先检查指针是否为NULL,避免访问空指针导致段错误。 - 处理相同节点:直接返回,避免无意义的操作和潜在的自循环问题。
这样修改后,你的函数就能正确处理所有边界情况,不会再触发段错误了。
内容的提问来源于stack exchange,提问作者Gibser
相关产品推荐
相关产品推荐

