双向链表指定位置插入/删除函数问题:程序崩溃求助
双向链表插入/删除崩溃问题排查与修复
首先看你的代码,有好几处明显的错误导致崩溃和内存泄漏,咱们一步步捋清楚:
最致命的参数顺序错误(直接触发崩溃)
在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
相关产品推荐
相关产品推荐

