我在另一个链表中有一个链表,typedef如下:
typedef struct struct_execution_queue {
list_run_str *runstr;
list_run_str *marker; //just a pointer to a specific element in runstr (it was not allocated with `malloc()`)
int excount;
struct struct_execution_queue *next;
}list_ex;
list_run_str
是另一个链接列表:
typedef struct struct_run_str { //run element
char car;
struct struct_run_str *next;
struct struct_run_str *prev;
} list_run_str;
我实现了一个insert()
方法,该方法创建一个新的list_ex
元素并将其插入列表的开头。我试图运行一个简单的测试代码来查看内存管理是否正常:
int main(){
/*read data from input file and insert into lists (this part is ok)
I have all data I need: two rheads and two markers
*/
list_ex *exhead = NULL;
exhead = insert(exhead, rheadone, markerone, 10);
exhead = insert(exhead, rheadtwo, markertwo, 20);
free_ex_list(exhead);
}
要释放所有exhead
元素,我需要首先释放相对子列表。
由于rhead
(exhead
的子列表)也是一个链表(与malloc()
一起分配),我认为可以逐个元素地释放它。这是我使用的代码:
void free_run_str_list(list_run_str *head) { //free a list_run_str list
list_run_str *tmp;
while (head != NULL) {
tmp = head;
head = head->next;
free(tmp);
} // <--------------------- breackpoint triggered here
}
void free_ex_list(list_ex *head) { //free a list_ex list
list_ex *tmp;
while (head != NULL) {
tmp = head;
free_run_str_list(tmp->runstr);
head = head->next;
free(tmp);
}
}
问题是,当我编译此代码时,Visual Studio在指定的行中触发一个断点。当我逐步调试时,代码将运行直到free_run_str_list(tmp->runstr);
进入调用并执行第一个free(tmp)
。现在tmp
里面有随机值(确实如此),但是head
也有相同的随机值,并且在第二次迭代中,行free(temp)
试图释放已经释放的内存,从而导致(我猜)会发生错误。
所以我的问题是:
exhead
的正确方法吗?我搜索了类似的解决方案,但我认为问题有所不同。
malloc()
没有分配足够的空间来终止字符(不是我的情况:我有一个喜欢的字符列表作为子列表,而不是字符串指针)。free_run_str_list(tmp->runstr);
中将free(tmp->runstr)
替换为free_ex_list()
,则不会触发断点(但是我不保证这是正确的方法:仅释放子链接列表?)。插入代码:
list_ex *insert(list_ex *exhead, list_run_str *rhead, list_run_str *marker, int count) {
list_ex *tmp;
list_run_str *tmphead, *tmpmarker;
if ((tmp = (list_ex *)malloc(sizeof(list_ex)))) {
tmphead = duplicate(rhead, marker, &tmpmarker);
tmp->runstr = tmphead;
tmp->marker = tmpmarker;
tmp->excount = count;
tmp->next = exhead;
exhead = tmp;
}
else
printf("insert mem error\n");
return tmp;
}
list_run_str *duplicate(list_run_str *head, list_run_str *marker, list_run_str **newmarker) { //duplicate a list_run_str_list and the relative marker
list_run_str *newhead, *newtmphead, *tmphead;
int markerpos, len, i;
//find list length
for (len = 0, tmphead = head; tmphead != NULL; len++, tmphead = tmphead->next);
//find marker position in head
markerpos = 0;
if (marker != NULL)
for (tmphead = marker; tmphead->prev != NULL; markerpos++, tmphead = tmphead->prev);
//create new list_run_str list
if ((newhead = (list_run_str *)malloc(sizeof(list_run_str) * len))) {
i = 0;
//load the new head
newtmphead = newhead;
tmphead = head;
(newtmphead + i)->prev = NULL;
(newtmphead + i)->next = (newtmphead + i + 1);
(newtmphead + i)->car = tmphead->car;
//load other elements
for (i++, tmphead = tmphead->next; tmphead != NULL; i++, tmphead = tmphead->next) {
(newtmphead + i)->car = tmphead->car;
(newtmphead + i)->next = (newtmphead + i + 1);
(newtmphead + i)->prev = (newtmphead + i - 1);
}
((newtmphead)+len - 1)->next = NULL;
//update the new marker
for (i = 0, newtmphead = newhead; i < markerpos; i++, newtmphead = newtmphead->next);
*newmarker = newtmphead;
}
else
printf("duplicate mem error\n");
return newhead;
}
感谢帮助。
编辑
这是导致此问题的确切代码,我试图尽我所能简化代码。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct struct_run_str {
char car;
struct struct_run_str *next;
struct struct_run_str *prev;
} list_run_str;
typedef struct struct_execution_queue {
list_run_str *runstr; //this will be allocated with malloc()
list_run_str *marker; //this is only a pointer to a certain element in runstr
int excount;
struct struct_execution_queue *next;
}list_ex;
void free_run_str_list(list_run_str *head) { //free a "list_run_str" list
list_run_str *tmp;
while (head != NULL) {
tmp = head;
head = head->next;
free(tmp);
}
}
void free_ex_list(list_ex *head) { //free a "list_ex" list
list_ex *tmp;
while (head != NULL) {
tmp = head;
free_run_str_list(tmp->runstr);
head = head->next;
free(tmp);
}
}
list_run_str *loadrunstr(list_run_str *head, char c) { //add an item at the ed of a "list_run_str" list
list_run_str *tmp, *tmphead;
if ((tmp = (list_run_str *)malloc(sizeof(list_run_str)))) {
tmp->car = c;
tmp->next = NULL;
if (head == NULL) {
tmp->prev = NULL;
head = tmp;
}
else {
for (tmphead = head; tmphead->next != NULL; tmphead = tmphead->next);
tmphead->next = tmp;
tmp->prev = tmphead;
}
}
else
printf("loadrunstr mem error\n");
return head;
}
list_run_str *duplicate(list_run_str *head, list_run_str *marker, list_run_str **newmarker) { //duplicte head to newhed and adjust newmarker
list_run_str *newhead, *newtmphead, *tmphead;
int markerpos, len, i;
//find list length
for (len = 0, tmphead = head; tmphead != NULL; len++, tmphead = tmphead->next);
//find marker position
markerpos = 0;
if (marker != NULL)
for (tmphead = marker; tmphead->prev != NULL; markerpos++, tmphead = tmphead->prev);
//create new "list_run_str" list
if ((newhead = (list_run_str *)malloc(sizeof(list_run_str) * len))) {
i = 0;
//load the head
newtmphead = newhead;
tmphead = head;
(newtmphead + i)->prev = NULL;
(newtmphead + i)->next = (newtmphead + i + 1);
(newtmphead + i)->car = tmphead->car;
//load the other elements
for (i++, tmphead = tmphead->next; tmphead != NULL; i++, tmphead = tmphead->next) {
(newtmphead + i)->car = tmphead->car;
(newtmphead + i)->next = (newtmphead + i + 1);
(newtmphead + i)->prev = (newtmphead + i - 1);
}
((newtmphead)+len - 1)->next = NULL;
//update new marker position
for (i = 0, newtmphead = newhead; i < markerpos; i++, newtmphead = newtmphead->next);
*newmarker = newtmphead;
}
else
printf("duplicate mem error\n");
return newhead;
}
list_ex *insert(list_ex *exhead, list_run_str *rhead, list_run_str *marker, int count) { //insert new element in the head of a "list_ex" list
list_ex *tmp;
list_run_str *tmphead, *tmpmarker;
if ((tmp = (list_ex *)malloc(sizeof(list_ex)))) {
tmphead = duplicate(rhead, marker, &tmpmarker);
tmp->runstr = tmphead;
tmp->marker = tmpmarker;
tmp->excount = count;
tmp->next = exhead;
exhead = tmp;
}
else
printf("insert mem error\n");
return tmp;
}
int main() {
list_ex *exhead;
list_run_str *rheadone, *markerone, *rheadtwo, *markertwo;
exhead = NULL;
rheadone = NULL;
rheadtwo = NULL;
//load some items in rheadone
rheadone = loadrunstr(rheadone, 'a');
rheadone = loadrunstr(rheadone, 'b');
rheadone = loadrunstr(rheadone, 'c');
//load some items in rheadtwo
rheadtwo = loadrunstr(rheadtwo, 'd');
rheadtwo = loadrunstr(rheadtwo, 'e');
rheadtwo = loadrunstr(rheadtwo, 'f');
//set markerone to point at some char in rheadone
markerone = rheadone->next; //points to 'b'
//set markertwho to point at some char in rheadtwo
markertwo = rheadtwo; //points to 'd'
//insert two new elements into exhead
exhead = insert(exhead, rheadone, markerone, 10);
exhead = insert(exhead, rheadone, markerone, 20);
//try to free them
free_ex_list(exhead);
return 0;
}
答案 0 :(得分:2)
在您发布的代码中,问题出在功能duplicate
中。它将变量len
设置为要复制的列表的长度,并调用malloc
来分配len
的{{1}}个元素的块。然后,它会填充这些元素,并将它们连接到list_run_str
的链接列表中,执行其他操作并返回指向第一个元素的指针。
大概,函数list_run_str
的返回值以duplicate
的{{1}}成员结尾。
从runstr
调用的list_ex
函数在链接列表的每个项目上调用free_run_str_list
。如果此链接列表是由函数free_list_ex
构造的,则对free
的第一次调用将释放整个块。但是,即使它们都是从一次调用duplicate
中分配的,您也要分别释放链表中的每一项。
要解决此问题,您应该将free
函数更改为malloc
链表的每个项目,因为这正是duplicate
函数所期望的。