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

双向链表指定位置插入/删除函数问题:程序崩溃求助

双向链表插入/删除崩溃问题排查与修复

首先看你的代码,有好几处明显的错误导致崩溃和内存泄漏,咱们一步步捋清楚:

最致命的参数顺序错误(直接触发崩溃)

在main函数里调用popposition时,你把参数顺序写反了:

popposition(1, list);

而函数定义是void popposition(struct list2c * list, int index),正确的调用应该是先传链表指针,再传索引:

popposition(list, 1);

这个错误直接导致函数把整数1当成指针去访问,必然触发程序崩溃。

各函数的具体问题与修复

1. pushonposition函数的问题

  • 无意义的内存分配与泄漏:你一开始malloc了el和before,但马上把它们赋值为链表的节点指针,malloc的内存完全没用到,直接造成内存泄漏。
  • 插入逻辑错误:当poz==0或poz>=list->position时,你错误地修改了现有节点的x值,而不是插入新节点;空链表的判断逻辑也混乱。
  • 中间插入逻辑冗余:不需要两次遍历找节点,一次遍历到目标位置的前一个节点即可完成插入。

修复后的pushonposition:

void pushonposition(int newData, int poz, struct list2c * list){
    // 处理空链表的情况,直接调用push插入
    if (list->begining == NULL) {
        push(newData, list);
        return;
    }

    // 如果指定位置超出范围,直接插在链表末尾
    if (poz >= list->position) {
        push(newData, list);
        return;
    }

    struct ellist2c * newEl = (struct ellist2c *)malloc(sizeof(struct ellist2c));
    newEl->x = newData;

    // 插在链表头部
    if (poz == 0) {
        newEl->left = NULL;
        newEl->right = list->begining;
        list->begining->left = newEl;
        list->begining = newEl;
        list->position++;
        return;
    }

    // 插在中间位置:遍历到poz-1的节点
    struct ellist2c * prev = list->begining;
    for (int i = 0; i < poz - 1; i++) {
        prev = prev->right;
    }

    newEl->left = prev;
    newEl->right = prev->right;
    prev->right->left = newEl;
    prev->right = newEl;
    list->position++;
}

2. popposition函数的问题

  • 无意义的内存分配:malloc了el然后直接覆盖,造成内存泄漏。
  • 头节点删除逻辑完全错误:你在index==0的时候操作的是list->end(尾节点),完全搞反了,应该操作头节点。
  • 计数更新遗漏:只有头节点删除时更新了list->position,其他删除场景没更新,导致链表长度计数错误。
  • 空指针访问风险:遍历找节点时没有及时判断是否为空,可能导致后续访问el->left/el->right触发崩溃。

修复后的popposition:

void popposition(struct list2c * list, int index) {
    // 空链表或索引无效,直接返回
    if (list->begining == NULL || index < 0 || index >= list->position) {
        return;
    }

    struct ellist2c * toDelete = list->begining;

    // 删除头节点
    if (index == 0) {
        list->begining = list->begining->right;
        if (list->begining != NULL) {
            list->begining->left = NULL;
        } else {
            // 删除后链表为空,同步更新尾节点
            list->end = NULL;
        }
        free(toDelete);
        list->position--;
        return;
    }

    // 删除尾节点
    if (index == list->position - 1) {
        toDelete = list->end;
        list->end = list->end->left;
        list->end->right = NULL;
        free(toDelete);
        list->position--;
        return;
    }

    // 删除中间节点:遍历到目标节点
    for (int i = 0; i < index; i++) {
        toDelete = toDelete->right;
    }

    toDelete->left->right = toDelete->right;
    toDelete->right->left = toDelete->left;
    free(toDelete);
    list->position--;
}

3. print函数的问题

  • 内存泄漏:malloc了el然后直接覆盖,完全没必要。
  • 遍历方向错误:你用el = el->left是从尾往头遍历,而示例要求正序输出,应该用el = el->right。

修复后的print:

void print(struct list2c * list) {
    struct ellist2c * el = list->begining;
    while (el != NULL) {
        printf("%d ", el->x);
        el = el->right;
    }
    printf("\n");
}

4. push函数的小问题

原代码里push函数给newEl->right赋值的逻辑有误,往末尾插入的节点right应该是NULL,已经在修复后的完整代码里修正。

修正后的完整代码

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

struct ellist2c {
    int x;
    struct ellist2c * right;
    struct ellist2c * left;
};

struct list2c {
    struct ellist2c * begining;
    struct ellist2c * end;
    int position;
};

void push(int newdata, struct list2c * list) {
    struct ellist2c * newEl = (struct ellist2c *)malloc(sizeof(struct ellist2c));
    newEl->x = newdata;
    newEl->right = NULL;
    newEl->left = NULL;

    if (list->position == 0) {
        list->begining = newEl;
        list->end = newEl;
    } else {
        newEl->left = list->end;
        list->end->right = newEl;
        list->end = newEl;
    }
    list->position++;
}

void pushonposition(int newData, int poz, struct list2c * list){
    if (list->begining == NULL) {
        push(newData, list);
        return;
    }

    if (poz >= list->position) {
        push(newData, list);
        return;
    }

    struct ellist2c * newEl = (struct ellist2c *)malloc(sizeof(struct ellist2c));
    newEl->x = newData;

    if (poz == 0) {
        newEl->left = NULL;
        newEl->right = list->begining;
        list->begining->left = newEl;
        list->begining = newEl;
        list->position++;
        return;
    }

    struct ellist2c * prev = list->begining;
    for (int i = 0; i < poz - 1; i++) {
        prev = prev->right;
    }

    newEl->left = prev;
    newEl->right = prev->right;
    prev->right->left = newEl;
    prev->right = newEl;
    list->position++;
}

void popposition(struct list2c * list, int index) {
    if (list->begining == NULL || index < 0 || index >= list->position) {
        return;
    }

    struct ellist2c * toDelete = list->begining;

    if (index == 0) {
        list->begining = list->begining->right;
        if (list->begining != NULL) {
            list->begining->left = NULL;
        } else {
            list->end = NULL;
        }
        free(toDelete);
        list->position--;
        return;
    }

    if (index == list->position - 1) {
        toDelete = list->end;
        list->end = list->end->left;
        list->end->right = NULL;
        free(toDelete);
        list->position--;
        return;
    }

    for (int i = 0; i < index; i++) {
        toDelete = toDelete->right;
    }

    toDelete->left->right = toDelete->right;
    toDelete->right->left = toDelete->left;
    free(toDelete);
    list->position--;
}

void print(struct list2c * list) {
    struct ellist2c * el = list->begining;
    while (el != NULL) {
        printf("%d ", el->x);
        el = el->right;
    }
    printf("\n");
}

int main(){
    struct list2c * list = (struct list2c *)malloc(sizeof(struct list2c));
    list->begining = NULL;
    list->end = NULL;
    list->position = 0;

    push(5, list);
    push(6, list);
    push(7, list);
    pushonposition(1, 1, list);
    pushonposition(1, 1, list);
    popposition(list, 1); // 修正参数顺序
    print(list);

    // 释放链表内存,避免泄漏
    struct ellist2c * temp;
    while (list->begining != NULL) {
        temp = list->begining;
        list->begining = list->begining->right;
        free(temp);
    }
    free(list);

    return 0;
}

测试结果

运行修正后的代码,输出为:5 1 6 7,完全符合预期的插入和删除逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:16:06