C语言链表实现中Valgrind显示malloc次数比实际多1次的原因
双向链表Valgrind显示分配次数比实际多1次的原因
我用C实现双向链表,只在push_int_list函数里调用malloc,代码中调用了5次这个函数,但Valgrind显示执行了6次分配与释放。调整push_int_list的调用次数后,分配次数始终比实际多1次。排除了栈上的Int结构体被计数的可能,请问这是为什么?
代码实现
#include <stdio.h> #include <stdlib.h> #include <inttypes.h> // -------------------------------------------------------------------------------- // Linked list Struct to containt data typedef struct int_list { int data; struct int_list *next; struct int_list *previous; } int_list; // -------------------------------------------------------------------------------- // Struct to track linked list data typedef struct { size_t active_length; struct int_list *head; struct int_list *tail; } Int; // -------------------------------------------------------------------------------- // Basic initialization of data tracking struct void init_int_list(Int *list) { list->active_length = 0; list->head = NULL; list->tail = NULL; } // -------------------------------------------------------------------------------- // Function that allows user to push a struct to any indice int push_int_list(Int *list, int data, size_t index) { if (index < 0 || index > list->active_length) { fprintf(stderr, "INdex out of range\n"); return -1; } struct int_list *dat = malloc(sizeof(int_list)); if (!dat) { fprintf(stderr, "malloc failed in file %s at line %d\n", __FILE__, __LINE__); return -1; } if (list->active_length == 0) { // populate struct dat->data = data; dat->previous = NULL; dat->next = NULL; // Update linked list tracking struct list->head = dat; list->tail = dat; list->active_length += 1; } else if (index == 0 && list->active_length > 0) { // populate struct dat->previous = NULL; dat->next = list->head; dat->data = data; // Update data in the struct occupying hte next index (list->head)->previous = dat; // Update linked list tracking struct list->head = dat; list->active_length += 1; } else if (list->active_length > 0 && index == list->active_length) { // populate struct dat->data = data; dat->next = NULL; dat->previous = list->tail; // Update struct occupying previous index (list->tail)->next = dat; // Update linked list tracking struct list->tail = dat; list->active_length += 1; } // The next two if statements are mean to reduce the iteration time by half // if the index to be inserted is between 0 and active_length else if (index < list->active_length / 2) { struct int_list *current = list->head; struct int_list *previous = NULL; for (size_t i = 0; i < index; i++) { previous = current; current = current->next; } // populate struct dat->data = data; dat->next = current; dat->previous = previous; // Update previous and next struct previous->next = dat; current->previous = dat; // Update linked list tracking struct list->active_length += 1; } else { struct int_list *current = list->tail; struct int_list *next = NULL; for (size_t i = list->active_length; i > index; i--) { next = current; current = current->previous; } // Update struct dat->data = data; dat->next = next; dat->previous = current; // Update previous and next struct next->previous = dat; current->next = dat; // Update linked list tracking struct list->active_length += 1; } return 1; } void free_int_list(Int *list) { if (list->active_length > 0) { struct int_list *tmp = NULL; struct int_list *head = list->head; while (head->next != NULL) { tmp = head; head = tmp->next; free(tmp); } free(head); } } // Begin code int main() { Int list; init_int_list(&list); push_int_list(&list, 1, 0); push_int_list(&list, 2, 1); push_int_list(&list, 3, 2); push_int_list(&list, 4, 3); push_int_list(&list, 8, 0); // Print linked list struct int_list *current = list.head; for (size_t i = 0; i < list.active_length; i++) { printf("%d\n", current->data); current = current->next; } free_int_list(&list); return 0; }
Valgrind检测信息
==10074== Memcheck, a memory error detector ==10074== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al. ==10074== Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info ==10074== Command: ./test ==10074== 8 1 2 3 4 ==10074== ==10074== HEAP SUMMARY: ==10074== in use at exit: 0 bytes in 0 blocks ==10074== total heap usage: 6 allocs, 6 frees, 1,144 bytes allocated ==10074== ==10074== All heap blocks were freed -- no leaks are possible ==10074== ==10074== For lists of detected and suppressed errors, rerun with: -s ==10074== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
原因分析
多出来的那次分配并非你的代码导致,而是C标准库内部的内存分配操作。比如你代码中调用的printf函数,在首次执行时,stdio库会分配一个内部缓冲区(用于行缓冲或全缓冲),这个分配会被Valgrind统计进去。
你可以做验证:把代码中的printf输出部分注释掉,重新用Valgrind运行,此时分配次数就会和你调用push_int_list的次数完全一致(5次)。
另外Valgrind已经明确显示All heap blocks were freed -- no leaks are possible,说明所有分配的内存都被正确释放了,你的链表实现没有内存泄漏问题。
内容的提问来源于stack exchange,提问作者Jon
相关产品推荐
相关产品推荐

