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

如何初始化双向链表尾指针以避免段错误?

双向链表段错误修复及插入功能实现

问题根源

你的代码中tail指针始终未被正确赋值,一直保持初始的NULL状态:

  • show_last函数直接访问tail->value,对空指针解引用触发段错误;
  • 所有节点的prev_link被错误赋值为NULL,双向链表的反向关联完全失效;
  • 内存释放逻辑错误,仅释放了个别节点,存在严重内存泄漏。

修复后的完整代码

#include <stdio.h>
#include <stdlib.h>

typedef struct Node
{
    int value;
    struct Node *next_link;
    struct Node *prev_link;
} Node;

Node *create_node(int value)
{
    Node *new_node = malloc(sizeof(Node));
    new_node->value = value;
    new_node->next_link = NULL;
    new_node->prev_link = NULL;

    return new_node;
}

void forward_traversing(Node *head)
{
    Node *temp = head;

    while (temp != NULL)
    {
        printf("%d ", temp->value);
        temp = temp->next_link;
    }
    printf("\n");
}

void backward_traversing(Node *tail)
{
    Node *temp = tail;

    while (temp != NULL)
    {
        printf("%d ", temp->value);
        temp = temp->prev_link;
    }
    printf("\n");
}

void show_first(Node *head)
{
    if (head == NULL) {
        printf("List is empty\n");
        return;
    }
    printf("%d is the first value\n", head->value);
}

void show_last(Node *tail)
{
    if (tail == NULL) {
        printf("List is empty\n");
        return;
    }
    printf("%d is the last value\n", tail->value);
}

// 头部插入函数
void insert_at_head(Node **head, Node **tail, int value) {
    Node *new_node = create_node(value);
    if (*head == NULL) {
        *head = new_node;
        *tail = new_node;
    } else {
        new_node->next_link = *head;
        (*head)->prev_link = new_node;
        *head = new_node;
    }
}

// 尾部插入函数
void insert_at_tail(Node **head, Node **tail, int value) {
    Node *new_node = create_node(value);
    if (*tail == NULL) {
        *head = new_node;
        *tail = new_node;
    } else {
        new_node->prev_link = *tail;
        (*tail)->next_link = new_node;
        *tail = new_node;
    }
}

// 在指定节点后插入
void insert_after_node(Node **tail, Node *prev_node, int value) {
    if (prev_node == NULL) {
        printf("Previous node cannot be NULL\n");
        return;
    }
    Node *new_node = create_node(value);
    new_node->next_link = prev_node->next_link;
    prev_node->next_link = new_node;
    new_node->prev_link = prev_node;
    
    // 如果原节点是尾节点,更新tail指针
    if (new_node->next_link == NULL) {
        *tail = new_node;
    } else {
        new_node->next_link->prev_link = new_node;
    }
}

int main()
{
    Node *head = NULL , *temp = NULL , *tail = NULL;

    // 修复链表创建逻辑
    for (int i = 25; i >= 0; i--){
        temp = create_node(i);
        if (head == NULL) {
            // 第一个节点,同时作为头和尾
            head = temp;
            tail = temp;
        } else {
            // 新节点的next指向当前头
            temp->next_link = head;
            // 当前头的prev指向新节点
            head->prev_link = temp;
            // 更新头指针
            head = temp;
        }
    }
    
    printf("Forward traversal: ");
    forward_traversing(head);
    printf("Backward traversal: ");
    backward_traversing(tail);
    show_first(head);
    show_last(tail);

    // 测试头部插入
    insert_at_head(&head, &tail, -1);
    printf("\nAfter inserting -1 at head:\n");
    forward_traversing(head);
    show_first(head);

    // 测试尾部插入
    insert_at_tail(&head, &tail, 26);
    printf("\nAfter inserting 26 at tail:\n");
    forward_traversing(head);
    show_last(tail);

    // 测试指定节点后插入(找value为10的节点)
    Node *target = head;
    while (target != NULL && target->value != 10) {
        target = target->next_link;
    }
    if (target != NULL) {
        insert_after_node(&tail, target, 100);
        printf("\nAfter inserting 100 after node 10:\n");
        forward_traversing(head);
    }

    // 正确释放所有节点
    Node *current = head;
    while (current != NULL) {
        Node *next = current->next_link;
        free(current);
        current = next;
    }
    
    return 0;
}

关键修改说明

  1. 链表创建逻辑:
    • 首次创建节点时,同时初始化head和tail,确保尾部指针有效;
    • 每次插入头部时,同步维护原头节点的prev_link,保证双向关联正确。
  2. 空指针防护:
    • 在show_first和show_last中增加空指针判断,避免链表为空时触发错误。
  3. 内存释放:
    • 遍历整个链表逐个释放节点,彻底避免内存泄漏和重复释放问题。

插入功能说明

  • 头部插入:传入head和tail的指针(因为需要修改指针本身),处理空链表和非空链表两种情况;
  • 尾部插入:同理,维护尾节点的next_link和新节点的prev_link,并更新tail;
  • 指定节点插入:找到目标节点后,插入新节点并维护前后关联,若插入位置在尾部则同步更新tail。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 05:34:57