是什么导致我的 C 通用链表内存泄漏

What is causing memory leaks in my generic linked list in C

我已经制作了自己的通用链表,但是在我的 removeStart 和 removeLast 函数中,根据 valgrind,我一直在发生内存泄漏。谁能告诉我为什么会这样,以及可能的解决方案吗?

头文件:LinkedList.h

  4 typedef struct LinkedListNode
  5 {
  6     void* data;
  7     struct LinkedListNode* next;
  8     struct LinkedListNode* previous;
  9 } LinkedListNode;
 10 
 11 typedef struct
 12 {
 13     LinkedListNode* head;
 14     LinkedListNode* tail;
 15     int size;
 16 } LinkedList;

代码:linkedlist.c

  5 /*******************************************
  6  * Name createLinkedList                   *
  7  * Imports: none                           *
  8  * Exports: list (LinkedList)              *
  9  * Assertion: Creates a new linked list    *
 10  ******************************************/
 11 
 12 LinkedList* createLinkedList()
 13 {
 14     LinkedList* list = (LinkedList*)malloc(sizeof(LinkedList));
 15     list->head = NULL;
 16     list->tail = NULL;
 17     list->size = 0;
 18 
 19     return list;
 20 }
 21 
 22 /****************************************************************
 23  * Name: insertStart                                            *
 24  * Imports: list (LinkedList*), entry (void*)                   *
 25  * Exports: none                                                *
 26  * Assertion: To insert a node at the beginning of the list     *
 27  ***************************************************************/
 28 
 29 void insertStart(LinkedList* list, void* entry)
 30 {
 31     LinkedListNode* newNode = (LinkedListNode*)malloc(sizeof(LinkedListNode));
 32 
 33     newNode->data = entry;
 34     newNode->next = list->head;
 35     newNode->previous = NULL;
 36 
 37     if (list -> head == NULL)
 38     {
 39         list->head = newNode;
 40         list->tail = newNode;
 41         list->size++;
 42     }
 43     else
 44     {
 45         list->head = newNode;
 46         newNode -> next -> previous = newNode;
 47         list->size++;
 48     }
 49 
 50 }
 51 
 52 /***********************************************************************
 53  * Name: removeStart                                                   *
 54  * Imports: list (LinkedList)                                          *
 55  * Exports: none                                                       *
 56  * Assertion: Deletes the first item, returns null if list is empty    *
 57  **********************************************************************/
 58 
 59 void* removeStart(LinkedList* list)
 60 {
 61     LinkedListNode* curr = (LinkedListNode*)malloc(sizeof(LinkedListNode));
 62 
 63     void* ptr;
 64 
 65     curr = list->head;
 66 
 67     if (curr->next == NULL)
 68     {
 69         free(curr);
 70         list->head = NULL;
 71     }
 72     if (curr->next != NULL)
 73     {
 74         ptr = curr -> data;
 75 
 76         list -> head = curr -> next;
 77 
 78         free(curr);
 79         curr = NULL;
 80 
 81         list -> head -> previous = NULL;
 82         list->size--;
 83     }
 84 
 85 
 86     return ptr;
 87 }
 88 
 89 /************************************************************
 90  * Name: insertLast                                         *
 91  * Imports: list (LinkedList*), entry (void*)               *
 92  * Exports: none                                            *
 93  * Assertion: Imports an element to the back of the list    *
 94  ***********************************************************/
 95 
 96 void insertLast(LinkedList* list, void* entry)
 97 {
 98     LinkedListNode* newNode = (LinkedListNode*)malloc(sizeof(LinkedListNode));
 99     LinkedListNode* curr;
100 
101     if (list -> head == NULL)
102     {
103         insertStart(list, entry);
104     }
105     else
106     {
107         newNode->data = entry;
108         newNode->next = NULL;
109 
110         curr = list->head;
111 
112         while (curr->next != NULL)
113         {
114             curr = curr->next;
115         }
116 
117         if (curr->next == NULL)
118         {
119             curr->next = newNode;
120             newNode->previous = curr;
121         }
122 
123         list->tail = newNode;
124         list->size++;
125     }
126 
127 }
128 
129 /*************************************************************************************
130  * Name: removeLast                                                                  *
131  * Imports: list (LinkedList*)                                                       *
132  * Exports: ptr (void*)                                                              *
133  * Assertion: Removes an element from the end, if empty will return null pointer     *
134  ************************************************************************************/
135 
136 void* removeLast(LinkedList* list)
137 {
138     LinkedListNode* curr = list -> head;
139     LinkedListNode* secondLast;
140 
141     void* ptr;
142 
143     if (isEmpty(list) == 0)
144     {
145         printf("List is empty");
146     }
147     else
148     {
149         while (curr->next != NULL)
150         {
151             secondLast = curr;
152             curr = curr->next;
153         }
154 
155         if (curr == list->head)
156         {
157             list -> head = NULL;
158         }
159 
160     }
161 
162     ptr = curr->data;
163     list->size--;
164     secondLast -> next = NULL;
165     list -> tail = secondLast;
166 
167     free(curr);
168     curr = NULL;
169 
170     return ptr;
171 }
201 /******************************************************
202  * Name: freeLinkedList                               *
203  * Imports: list (LinkedList*), funcPtr (listFunc)    *
204  * Exports: none                                      *
205  * Assertion: To free all elements within the list    *
206  *****************************************************/
207 
208 void freeLinkedList(LinkedList* list)
209 {
210     LinkedListNode* curr;
211     LinkedListNode* next;
212 
213     curr = list->head;
214 
215     while (curr != NULL)
216     {
217         next = curr->next;
218         free(curr);
219         curr = next;
220     }
221 
222     free(list);
223 }

根据 valgrind 的说法,我一直在失去记忆,我真的不知道是什么导致了这个问题。

无需深入研究您的程序(因为缺少 运行ning 场景(即缺少 main 函数)),

如果您查看 removeStart 函数:

void* removeStart(LinkedList* list)
{
     LinkedListNode* curr = (LinkedListNode*)malloc(sizeof(LinkedListNode));  
     void* ptr;
     curr = list->head;
     ...

你可以看到你使用 curr 指针分配内存(通过调用 malloc),

LinkedListNode* curr = (LinkedListNode*)malloc(sizeof(LinkedListNode));
然后你将它设置为 list->head (curr=list->head),这意味着你失去了对你刚刚分配的内存的引用。

我不知道你的程序是否有更多的内存泄漏,但是这个很明显。

我建议您首先将其更改为 LinkedListNode* curr = list->head 并且 运行 再次 valgrind 看看你是否还有泄漏。

如上面评论所述,您可以从 valgrind 获得完整的报告,包括代码中导致内存泄漏的行号。 要获得这样的完整报告,您需要使用调试信息编译源代码(将 -g 标志添加到 gcc),然后 运行 带有选项 --leak-check=full 的 valgrind。 valgrind 报告现在将包含导致内存泄漏的代码行。