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

双向链表节点移除异常求助:指定位置移除返回错误值

双向链表移除节点返回值不符合预期的问题分析

问题说明

我在main函数中对双向链表执行以下操作:

  • 调用dll_push_front添加若干元素
  • 调用dll_push_back添加若干元素
    随后移除pos=0和pos=1位置的节点,但输出显示移除pos=0返回值为5、移除pos=1返回值为7,与预期的4和2不符,无法定位错误。

完整代码

#ifndef MYDLL_H
#define MYDLL_H

#include <stdlib.h>

typedef struct node
{
    int data;
    struct node *next;
    struct node *previous;
} node_t;

typedef struct DLL
{
    int count;     
    node_t *head; 
    node_t *tail; 
} dll_t;

dll_t *create_dll()
{
    dll_t *myDLL = (dll_t*)malloc(sizeof(dll_t));
    if (myDLL == NULL) {
        return NULL;
    }
    myDLL->count = 0;
    myDLL->head = NULL;
    myDLL->tail = NULL;
    return myDLL;
}

int dll_empty(dll_t *l)
{
    if (l == NULL) {
        return -1;
    }
    if (l->count == 0 && l->head == NULL) {
        return 1;
    } else {
        return 0;
    }
}

int dll_push_front(dll_t *l, int item)
{
    if (l == NULL) {
        return -1;
    }
    node_t* new = (node_t*)malloc(sizeof(node_t));
    if (new == NULL) {
        return -1;
    }
    new->data = item;
    new->next = l->head;
    new->previous = NULL;

    if (l->head != NULL) { //set new prev for the previous head before pushing. 
        l->head->previous = new;
    } 
    l->head = new; // reset the new head for l.
    l->count++;
    return 1;
}

int dll_push_back(dll_t *l, int item)
{
    if (l == NULL) {
        return -1;
    }
    node_t* new = (node_t*)malloc(sizeof(node_t));
    if (new == NULL) {
        return -1;
    }
    new->data = item;
    new->previous = l->tail;
    new->next = NULL;

    if(l->tail != NULL) {
        l->tail->next = new;
    } else {
        l->head = new;
    }
    l->tail = new;
    l->count++;
    return 1;
}

int dll_pop_front(dll_t *t)
{
    if (t == NULL || t->head == NULL) {
        return -1;
    }

    node_t* pop_pointer = t->head; 
    int pop_item = pop_pointer->data; 
    t->head = pop_pointer->next; // set new head. 
    if (t->head != NULL) {
        t->head->previous = NULL;
    } else { // t->head = NULL cuz only one item and after popping, the t->head is null. 
        t->tail = NULL; // else if t->head = NULL, then t->tail also should be NULL.
    }
    if (t->head == NULL) {
        t->tail = NULL;
    }
    t->count--;
    free(pop_pointer);
    return pop_item;
}

int dll_pop_back(dll_t *t)
{
    if (t == NULL || t->head == NULL) {
        return -1;
    }
    node_t* pop_pointer = t->tail;
    int pop_item = pop_pointer->data; 
    t->tail = pop_pointer->previous; 
    if (t->tail != NULL) {
        t->tail->next = NULL;
    } else {
        t->head = NULL;
    }
    if (t->head == NULL) {
        t->tail = NULL;
    }
    t->count--;
    free(pop_pointer);
    return pop_item;
}

int dll_insert(dll_t *l, int pos, int item)
{
    if (l == NULL) {
        return -1;
    }
    if (pos >= l->count || pos < 0) {
        return 0;
    }
    node_t* new = (node_t*)malloc(sizeof(node_t));
    if (new == NULL) {
        return 0;
    }
    new->data = item;
    if(pos == 0) {
        return dll_push_front(l, item);
    }

    node_t* pointer = l->head;
    for (int i = 0; i < pos - 1; i++) {
        pointer = pointer->next; 
    }
    //ex: pos = 1, no for loop, pointer still head. 
    new->previous = pointer; 
    new->next = pointer->next; 
    pointer->next->previous = new; 
    pointer->next = new; 
    l->count++;
    return 1;
}

int dll_get(dll_t *l, int pos)
{
   if (l == NULL) {
    return -1;
   } 
   if (pos < 0 || pos >= l->count) {
    return 0;
   }
   node_t* pointer = l->head;
   for (int i = 0; i < pos - 1; i++) {
    pointer = pointer->next;
   }
   return pointer->data;
}

int dll_remove(dll_t *l, int pos)
{
    if (l == NULL) {
        return -1;
    }
    if (pos < 0 || pos >= l->count) {
        return 0;
    }
    node_t* pointer = l->head;
    node_t* prev = NULL; // first node prev is null. 
    for (int i = 0; i < pos; i++) {
        prev = pointer;
        pointer = pointer->next;
    }
    if (prev == NULL) { // first item.
        l->head = pointer->next;
    } else {
        prev->next = pointer->next;
    }
    if (pointer->next != NULL) {
        pointer->next->previous = prev;
    }
    // if we are removing the tail node
    if (pointer == l->tail) {
        l->tail = prev;
    }
    int removed_value = pointer->data;
    free(pointer);
    l->count--;
    return removed_value;
}

int dll_size(dll_t *t) {   
    if (t == NULL) {
        return -1;
    }
    return t->count;
}

void free_dll(dll_t *t)
{
    if (t == NULL) {
        return;
    }
    if (t == NULL) {
        free(t);
        return;
    }
    node_t* pointer = t->head;
    while(pointer != NULL) {
        node_t* pointer2 = pointer; 
        pointer = pointer->next;
        free(pointer2); 
    }
    free(t);
}

#endif

错误定位与修复

1. dll_push_front函数未维护tail指针

当链表为空时,添加第一个节点后,该节点既是头节点也是尾节点,但当前代码仅更新了head指针,未同步更新tail指针,导致后续push_back操作逻辑错误,破坏链表结构。

修复后的代码:

int dll_push_front(dll_t *l, int item)
{
    if (l == NULL) {
        return -1;
    }
    node_t* new = (node_t*)malloc(sizeof(node_t));
    if (new == NULL) {
        return -1;
    }
    new->data = item;
    new->next = l->head;
    new->previous = NULL;

    if (l->head != NULL) {
        l->head->previous = new;
    } else {
        // 链表为空时,新节点同时作为尾节点
        l->tail = new;
    }
    l->head = new;
    l->count++;
    return 1;
}

2. dll_get函数遍历逻辑错误

原代码中循环条件for (int i = 0; i < pos - 1; i++)无法正确定位目标节点,例如pos=1时,循环不会执行,返回的是头节点数据而非第二个节点的数据。

修复后的代码:

int dll_get(dll_t *l, int pos)
{
   if (l == NULL) {
    return -1;
   } 
   if (pos < 0 || pos >= l->count) {
    return 0;
   }
   node_t* pointer = l->head;
   for (int i = 0; i < pos; i++) {
    pointer = pointer->next;
   }
   return pointer->data;
}

辅助调试建议

可以添加打印链表所有元素的函数,方便调试过程中验证链表结构:

#include <stdio.h>
void print_dll(dll_t *l) {
    if (l == NULL || l->head == NULL) {
        printf("Empty list\n");
        return;
    }
    node_t* ptr = l->head;
    printf("List elements: ");
    while (ptr != NULL) {
        printf("%d ", ptr->data);
        ptr = ptr->next;
    }
    printf("\n");
}

修复上述问题后,链表的结构维护会恢复正常,移除节点的返回值即可符合预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 08:30:50