I have a memory leak when I try to merge two linked lists in another one. I tried to use list_destroy(&merge) however the memory was already gone by the time I did that. Thus, I don't know what to do.
#ifndef LIST_H
#define LIST_H
#include <stdlib.h>
// define a structure for a node
typedef struct ListElmt_ {
void* data;
struct ListElmt_* next;
} ListElmt;
// define a structure for a list
typedef struct List_ {
int size;
ListElmt* head;
ListElmt* tail;
void (*destroy)(void* data);
} List;
// public interface
void list_init(List *list, void (*destroy)(void *data));
void list_destroy(List *list);
int list_ins_next(List *list, ListElmt *element, const void *data);
int list_rem_next(List *list, ListElmt *element, void **data);
int list_concat(List* merge, List* list1, List* list2);
// macros
#define list_size(list) ((list)->size)
#define list_head(list) ((list)->head)
#define list_tail(list) ((list)->tail)
#define list_data(element) ((element)->data)
#define list_next(element) ((element)->next)
#define list_is_tail(element) ((element)->next == NULL ? 1 : 0)
#define list_is_head(element) ((element) == (list)->head ? 1 : 0)
#endif /* LIST_H */
#include "list.h"
#include <string.h>
/* initialize all the list data */
void list_init(List* list, void (*destroy)(void* data)) {
list->size = 0;
list->destroy = destroy;
list->head = NULL;
list->tail = NULL;
}
// attempt to insert a new node into the list
int list_ins_next(List* list, ListElmt* element, const void* data) {
ListElmt* new_element;
if((new_element = malloc(sizeof(ListElmt))) == NULL)
return -1;
/* insert new data inside a new element */
new_element->data = (void*) data;
/* insert the new element at the head of the list */
if (element == NULL) {
if (list_size(list) == 0)
list->tail = new_element;
new_element->next = list->head;
list->head = new_element;
}
/* insert new element at another place other than the head */
else {
if (element->next == NULL)
list->tail = new_element;
new_element->next = element->next;
element->next = new_element;
}
/* update the list size */
list->size++;
return 0;
}
// attempt to remove a node of the list
int list_rem_next(List *list, ListElmt *element, void **data) {
ListElmt* old_element;
/* verify if the list is already empty */
if (list_size(list) == 0)
return -1;
/* remove from the head of the list */
if (element == NULL) {
/* keep data and reference of the head to be removed */
*data = list->head->data;
old_element = list->head;
/* remove the head of the list */
list->head = list->head->next;
/* verify if there is only one node */
if (list_size(list) == 1)
list->tail = NULL;
}/* remove from somewhere other than the head */
else {
/* verify if there is a node to be removed */
if (element->next == NULL)
return -1;
/* keep data and reference of the element to be removed*/
*data = element->next->data;
old_element = element->next;
/* remove the element from the list */
element->next = element->next->next;
/* verify if the element is the last one */
if (element->next == NULL)
list->tail = element;
}
/* free old element's memory*/
free(old_element);
/* adjust the size of the list */
list->size--;
return 0;
}
// remove all nodes of the list
void list_destroy(List* list) {
void* data;
/* remove each element until there are no more elements*/
while (list_size(list) > 0) {
/* deallocate memory from data */
if (list_rem_next(list, NULL, (void**) &data) == 0 && list->destroy != NULL) {
list->destroy(data);
}
}
/* make sure there's no more allocated data */
memset(list, 0, sizeof (List));
}
int list_concat(List* merge, List* list1, List* list2)
{
ListElmt* element;
// insert each element of the first list into the merge list
for(element = list_head(list1); element != NULL; element = list_next(element))
{
if(list_ins_next(merge, NULL, list_data(element)) != 0)
return -1;
}
// insert each element of the second list into the merge list
for(element = list_head(list2); element != NULL; element = list_next(element))
{
if(list_ins_next(merge, list_tail(merge), list_data(element)) != 0)
return -1;
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
static void print_list(List* list) {
ListElmt* element;
int* data;
int i = 0;
/* display the size of the list */
fprintf(stdout, "List size is %d\n", list_size(list));
/* display each data of the elements of the list */
for (element = list_head(list); element != NULL; element = list_next(element)) {
data = list_data(element);
fprintf(stdout, "list[%03d] = %03d\n", i, *data);
i++;
}
}
int main(void) {
List list1;
List list2;
List merge;
int i;
int* data;
/* initialize the lists */
list_init(&list1, free);
list_init(&list2, free);
list_init(&merge, free);
/* insert numbers at the head of the list */
for(i = 9; i >= 0; i--)
{
if((data = malloc(sizeof(int))) == NULL)
return EXIT_FAILURE;
*data = i;
if(list_ins_next(&list1, NULL, data) != 0)
return EXIT_FAILURE;
}
/* print the first list */
print_list(&list1);
for(i = 19; i >= 10; i--)
{
if((data = malloc(sizeof(int))) == NULL)
return EXIT_FAILURE;
*data = i;
if(list_ins_next(&list2, NULL, data) != 0)
return EXIT_FAILURE;
}
/* print the second list */
print_list(&list2);
list_concat(&merge, &list1, &list2);
// print the merge list
print_list(&merge);
// deallocate all the remaining memory of the lists
list_destroy(&list1);
list_destroy(&list2);
return EXIT_SUCCESS;
}
==2936== HEAP SUMMARY: ==2936== in use at exit: 320 bytes in 20 blocks ==2936== total heap usage: 60 allocs, 40 frees, 720 bytes allocated ==2936== ==2936== 320 (16 direct, 304 indirect) bytes in 1 blocks are definitely lost in loss record 3 of 3 ==2936== at 0x4C2B3F8: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==2936== by 0x400869: list_ins_next (list.c:17) ==2936== by 0x400AAB: list_concat (list.c:102) ==2936== by 0x4007E1: main (listapp.c:56) ==2936== ==2936== LEAK SUMMARY: ==2936== definitely lost: 16 bytes in 1 blocks ==2936== indirectly lost: 304 bytes in 19 blocks