C、 逐个元素的空闲子列表会导致意外行为
我在另一个链表中有一个链表,typedef如下所示:C、 逐个元素的空闲子列表会导致意外行为,c,free,C,Free,我在另一个链表中有一个链表,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_execu
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\u run\u str
是另一个链接列表:
typedef struct struct_run_str { //run element
char car;
struct struct_run_str *next;
struct struct_run_str *prev;
} list_run_str;
我实现了一个insert()。我尝试运行一个简单的测试代码,看看内存管理是否正常:
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);
}
}
谢谢你的帮助
编辑
下面是导致问题的确切代码,我尽量简化它
代码:
#包括
#包括
#包括
类型定义结构结构运行结构{
炭车;
struct struct_run_str*next;
struct struct_run_str*prev;
}列出"跑步"路线;;
类型定义结构执行队列{
list_run_str*runstr;//这将与malloc()一起分配
list_run_str*marker;//这只是指向runstr中某个元素的指针
国际汇算;
结构执行队列*下一步;
}列表(例如);;
作废自由运行列表(列表运行列表*头){//释放“列表运行列表”列表
列出_run _str*tmp;
while(head!=NULL){
tmp=头部;
头部=头部->下一步;
免费(tmp);
}
}
作废自由列表(列表头){//释放“列表头”列表
列表_ex*tmp;
while(head!=NULL){
tmp=头部;
自由运行列表(tmp->runstr);
头部=头部->下一步;
免费(tmp);
}
}
list_run_str*loadrunstr(list_run_str*head,char c){//在“list_run_str”列表的ed处添加一项
列出运行模式*tmp、*tmphead;
if((tmp=(list\u run\u str*)malloc(sizeof(list\u run\u str))){
tmp->car=c;
tmp->next=NULL;
if(head==NULL){
tmp->prev=NULL;
水头=tmp;
}
否则{
for(tmphead=head;tmphead->next!=NULL;tmphead=tmphead->next);
tmphead->next=tmp;
tmp->prev=tmphead;
}
}
其他的
printf(“loadrunstr mem error\n”);
回流头;
}
list_run_str*复制(list_run_str*头,list_run_str*标记,list_run_str**新标记){//将复制头换成新标记并调整新标记
列出新头、新头、tmphead;
内特马克波斯,莱恩,i;
//查找列表长度
for(len=0,tmphead=head;tmphead!=NULL;len++,tmphead=tmphead->next);
//查找标记位置
markerpos=0;
如果(标记!=NULL)
for(tmphead=marker;tmphead->prev!=NULL;markerpos++,tmphead=tmphead->prev);
//创建新的“列表\u运行\u str”列表
如果((newhead=(list\u run\u str*)malloc(sizeof(list\u run\u str)*len))){
i=0;
//加载头部
newtmhead=newhead;
tmphead=头部;
(newtmphead+i)->prev=NULL;
(newtmhead+i)->next=(newtmhead+i+1);
(newtmhead+i)->car=tmphead->car;
//加载其他元素
对于(i++,tmphead=tmphead->next;tmphead!=NULL;i++,tmphead=tmphead->next){
(newtmhead+i)->car=tmphead->car;
(newtmhead+i)->next=(newtmhead+i+1);
(newtmhead+i)->prev=(newtmhead+i-1);
}
((newtmphead)+len-1)->next=NULL;
//更新新标记位置
对于(i=0,newtmhead=newhead;inext);
*newmarker=newtmhead;
}
其他的
printf(“重复的内存错误\n”);
返回newhead;
}
list_ex*insert(list_ex*exhead,list_run_str*rhead,list_run_str*marker,int count){//在“list_ex”列表的头部插入新元素
列表_ex*tmp;
列表\u run\u str*tmphead,*tmpmarker;
if((tmp=(list_ex*)malloc(sizeof(list_ex))){
tmphead=重复(rhead、标记器和TMP标记器);
tmp->runstr=tmphead;
tmp->marker=tmpmarker;
tmp->excount=计数;
tmp->next=挖掘;
挖掘=tmp;
}
其他的
printf(“插入内存错误\n”);
返回tmp;
}
int main(){
列明(例如)劝谕;;
列出rheadone、*markerone、*rheadtwo、*markertwo;
告诫=无效;
rheadone=NULL;
rheadtwo=NULL;
//在rheadone中加载一些项目
rheadone=loadrunstr(rheadone,'a');
rheadone=loadrunstr(rheadone,'b');
rheadone=loadrunstr(rheadone,'c');
//在rheadtwo中加载一些项目
rheadtwo=loadrunstr(rheadtwo,'d');
rheadtwo=loadrunstr(rheadtwo,'e');
rheadtwo=loadrunstr(rheadtwo,'f');
//将markerone设置为指向rheadone中的某个字符
markerone=rheadone->next;//指向“b”
//将markertwho设置为指向rheadtwo中的某个字符
markertwo=rheadtow2;//指向“d”
//在摘要中插入两个新元素
启封=插入(启封,雷亚东,马克罗恩,10);
exhead=插入(exhead,rheadone,markerone,20);
//试着释放他们
免费除名名单(摘要);
返回0;
}
从您发布的代码中,问题出在函数复制中。它将变量len
设置为要复制的列表的长度,并调用malloc
来分配list\u run\u str
的len
元素块。然后,它填充这些元素并将它们连接到一个链表中,链表包含list\u run\u str
,执行其他操作并返回指向第一个元素的指针
据推测,函数duplicate
的返回值会在列表的runstr
成员中结束
从free\u list\u ex
调用的free\u run\u str\u list
函数对链接列表的每个项目调用free
。如果此链表是由函数duplicate
构建的,则对free
的第一次调用将释放整个块。然而,
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;
}