提问人:cougarhound 提问时间:11/15/2023 最后编辑:cougarhound 更新时间:11/17/2023 访问量:106
内存泄漏问题,销毁函数没有释放由我的反向函数创建的链表节点
memory leak problem, destroy function is not freeing the linked list nodes created by my reverse function
问:
我的 list_sum 函数中的 destroy_list(pHead1_reversed) 和 destroy_list(pHead2_reversed) 函数似乎没有释放节点。我遇到了内存泄漏。我做错了什么?
int main(int argc, char* argv[])
{
//add up 189 + 11
Node* head1 = NULL;
Node* head2 = NULL;
Node* head_sum = NULL;
//create a list for the number 189
head_insert(&head1, 9);
head_insert(&head1, 8);
head_insert(&head1, 1);
//create a list for the number 11
head_insert(&head2, 1);
head_insert(&head2, 1);
head_sum = list_sum(head1, head2);
printf("The sum of ");
print_list(head1);
printf(" + ");
print_list(head2);
printf("\n");
printf(" = ");
print_list(head_sum);
printf("\n");
//clean up three lists
destroy_list(head1); head1 = NULL;
destroy_list(head2); head2 = NULL;
destroy_list(head_sum); head_sum = NULL;
return 0;
}
**********************************************************************
void head_insert(Node** hHead, int newItem)
{
Node* pNode = NULL;
pNode = (Node*)malloc(sizeof(Node));
if (pNode == NULL)
{
printf("malloc failed for node \n");
exit(1);
}
pNode->data = newItem;
pNode->next = *hHead;
*hHead = pNode;
}
void destroy_list(Node* hHead)
{
Node* current = hHead;
Node* next;
while (current != NULL) {
next = current->next;
free(current);
current = next;
}
}
Node* list_sum(Node* hHead1, Node* hHead2)
{
Node* pHead1_reversed=reverse(hHead1);
Node* pHead2_reversed=reverse(hHead2);
Node* result_reversed;
Node* resultHead = NULL;
int carry = 0;
while (pHead1_reversed != NULL || pHead2_reversed != NULL || carry != 0) {
int digit1 = (pHead1_reversed != NULL) ? pHead1_reversed->data : 0;
int digit2 = (pHead2_reversed != NULL) ? pHead2_reversed->data : 0;
int sum = digit1 + digit2 + carry;
carry = sum / 10;
Node* newNode = (Node*)malloc(sizeof(Node));
if (newNode == NULL) {
printf("malloc failed for result node \n");
exit(1);
}
newNode->data = sum % 10;
newNode->next = NULL;
if (resultHead == NULL) {
resultHead = newNode;
}
else {
Node* temp = resultHead;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = newNode;
}
if (pHead1_reversed != NULL) pHead1_reversed = pHead1_reversed->next;
if (pHead2_reversed != NULL) pHead2_reversed = pHead2_reversed->next;
}
destroy_list(pHead1_reversed);
destroy_list(pHead2_reversed);
result_reversed = reverse(resultHead);
destroy_list(resultHead);
return result_reversed;
}
void print_list(Node* hHead)
{
Node* pHead = (Node*)hHead;
printf("*******\n");
while (pHead != NULL)
{
printf("%d\n", pHead->data);
pHead = pHead->next;
}
printf("*******\n");
}
Node* reverse(Node* hHead)
{
Node* resultHead = NULL;
Node* next;
while (hHead != NULL) {
Node* newNode = (Node*)malloc(sizeof(Node));
if (newNode == NULL) {
printf("malloc failed for result node \n");
exit(1);
}
newNode->data = hHead->data;
newNode->next = resultHead;
resultHead = newNode;
hHead = hHead->next;
}
return resultHead;
}
尝试将pHead2_reversed设置为NULL,但不起作用。还尝试直接在反向函数中释放节点,而不是使用函数调用。顶部是我的主驱动程序文件,底部是函数实现文件。
答:
您在以下位置泄漏内存:list_sum
虽然你有:
destroy_list(pHead1_reversed);
destroy_list(pHead2_reversed);
...这些指针不指向这些反向列表的头部,因为您在前面的循环中将它们向前移动:
if (pHead1_reversed != NULL) pHead1_reversed = pHead1_reversed->next;
if (pHead2_reversed != NULL) pHead2_reversed = pHead2_reversed->next;
在循环之前,必须保留对这些头的引用,然后从这些头节点开始释放列表。
备注
通过为链表定义单独的类型(结构),可以更好地避免这种情况的发生,该类型将列表的头部作为成员。这样可以更容易地保证这个头确实是链表的头。释放链表的函数与释放单个节点的函数不同。
其次,如果每次都必须找到列表的末尾才能附加到结果列表中,然后在末尾反转该列表,则效率不高。更有效的是,通过在结果列表的前面插入总和数字,立即以正确的顺序创建结果。reverse
您也可以在构建总和的同时销毁反转列表:在同一循环中。这可能会导致非常优雅的代码。
最好只使用一个函数来分配节点。目前,此代码分布在三个位置。
建议的代码
下面是一些代码,显示了如何在考虑上述备注的情况下完成它:
#include <stdio.h>
#include <stdlib.h>
//////////////////////// Node /////////////////////////////////
typedef struct node {
int data;
struct node *next;
} Node;
Node* create_node(int data, Node *next_node) {
Node* node = malloc(sizeof(*node));
if (node== NULL) {
printf("malloc failed for creating node with data %d\n", data);
exit(1);
}
node->data = data;
node->next = next_node;
return node;
}
Node* destroy_node(Node* node) // Returns the successor
{
Node* next = node->next;
free(node);
return next;
}
//////////////////////// Linked List /////////////////////////////////
typedef struct linkedlist {
Node *head;
} LinkedList;
LinkedList* create_list() {
LinkedList* list = malloc(sizeof(*list));
if (list == NULL) {
printf("malloc failed for creating list\n");
exit(1);
}
list->head = NULL;
return list;
}
int list_is_empty(LinkedList *list) {
return list->head ? 0 : 1;
}
int list_pop_head(LinkedList *list, int defaultValue)
{
if (list_is_empty(list)) {
return defaultValue;
}
int data = list->head->data;
list->head = destroy_node(list->head);
return data;
}
void destroy_list(LinkedList *list)
{
while (!list_is_empty(list)) {
list_pop_head(list, 0);
}
}
void list_insert_head(LinkedList *list, int data)
{
list->head = create_node(data, list->head);
}
LinkedList* list_reverse(LinkedList* list)
{
LinkedList *result = create_list();
for (Node* node = list->head; node; node = node->next) {
list_insert_head(result, node->data);
}
return result;
}
LinkedList* list_sum(LinkedList* list1, LinkedList* list2)
{
LinkedList* reversed1 = list_reverse(list1);
LinkedList* reversed2 = list_reverse(list2);
LinkedList* result = create_list();
int carry = 0;
while (!list_is_empty(reversed1) || !list_is_empty(reversed2) || carry) {
int sum = list_pop_head(reversed1, 0) + list_pop_head(reversed2, 0) + carry;
carry = sum / 10;
list_insert_head(result, sum % 10);
}
return result;
}
void list_print(LinkedList* list)
{
for (Node* node = list->head; node; node = node->next) {
printf("%d -> ", node->data);
}
printf("NULL\n");
}
int main(int argc, char* argv[])
{
//add up 189 + 11
LinkedList* list1 = create_list();
LinkedList* list2 = create_list();
//populate a list for the number 189
list_insert_head(list1, 9);
list_insert_head(list1, 8);
list_insert_head(list1, 1);
//populate a list for the number 11
list_insert_head(list2, 1);
list_insert_head(list2, 1);
LinkedList *head_sum = list_sum(list1, list2);
printf("The sum of\n");
list_print(list1);
printf("+\n");
list_print(list2);
printf("=\n");
list_print(head_sum);
//clean up three lists
destroy_list(list1);
destroy_list(list2);
destroy_list(head_sum);
return 0;
}
评论
list_pop_head()
在空列表中返回 0 允许干净地实现,但具有重叠的值和错误域是一种错误修剪设计。如果 op 需要实现乘法,则恒等值不再是 0 而是 1,您需要检查并引入与 sum 相比的不对称性。现在可以进行设计,如果需要,将来可以更改设计。list_sum()
list_is_empty()
pop
pop
解决内存泄漏的另一种方法是就地反转列表。如果更改为 take a 并返回新分配的节点,则它将成为更通用的函数。然后,您可以重用 ,使用为您反转列表的事实,并合并两个重复的 NULL 检查。为了获得良好的度量值,请使用 Replace 和 Short 变量名称:list_sum()
head_insert()
Node *
head_insert()
list_sum()
head_insert()
signed char
int
Node *head_insert(Node *hHead, int newItem) {
Node* pNode = malloc(sizeof *pNode);
if (!pNode) {
printf("malloc failed for node \n");
exit(1);
}
pNode->data = newItem;
pNode->next = hHead;
return pNode;
}
Node* reverse(Node* hHead) {
if(!hHead)
return hHead;
Node *next = hHead->next;
hHead->next = NULL;
while(next) {
Node *prev = hHead;
hHead = next;
next = hHead->next;
hHead->next = prev;
}
return hHead;
}
Node *list_sum(Node* a, Node* b) {
a = reverse(a);
b = reverse(b);
Node* result = NULL;
signed char carry = 0;
for(Node *a2 = a, *b2 = b; a2 || b2 || carry; ) {
signed char a2_digit = 0;
if(a2) {
a2_digit = a2->data;
a2 = a2->next;
}
signed char b2_digit = 0;
if(b2) {
b2_digit = b2->data;
b2 = b2->next;
}
signed char sum = a2_digit + b2_digit + carry;
carry = sum / 10;
result = head_insert(result, sum % 10);
}
reverse(a);
reverse(b);
return result;
}
int main(void) {
//add up 189 + 11
Node* head1 = NULL;
Node* head2 = NULL;
Node* head_sum = NULL;
//create a list for the number 189
head1 = head_insert(head1, 9);
head1 = head_insert(head1, 8);
head1 = head_insert(head1, 1);
//create a list for the number 11
head2 = head_insert(head2, 1);
head2 = head_insert(head2, 1);
head_sum = list_sum(head1, head2);
printf("The sum of ");
print_list(head1);
printf(" + ");
print_list(head2);
printf(" = ");
print_list(head_sum);
printf("\n");
//clean up three lists
destroy_list(head1);
destroy_list(head2);
destroy_list(head_sum);
}
和示例运行方式(我删除了以使输出更紧凑):valgrind --leak-check=full
\n
print_list()
The sum of 189 + 11 = 200
[...]
==3546== HEAP SUMMARY:
==3546== in use at exit: 0 bytes in 0 blocks
==3546== total heap usage: 9 allocs, 9 frees, 1,152 bytes allocated
==3546==
==3546== All heap blocks were freed -- no leaks are possible
评论
head_insert()
评论
malloc()