这可能是一个非常简单的问题,但是我在互联网上找不到答案。我正在用C语言实现一个链表,并且正在用valgrind检查内存使用和释放。我创建了下面的实现,它工作正常。malloc
唯一被调用的地方是在push_int_list
函数中。它允许用户创建一个结构体并将其插入到链表中的任何索引中。是的,我知道它不像数组那样是真正的索引,但我使用同样的行话来描述数据点的位置。此外,push_int_list
函数将从链表的头部或尾部开始迭代,这取决于结构体将被插入的位置。
下面显示的实现工作正常;但是,当我用valgrind检查内存分配和释放时,显示我执行了6个allocs和6个frees。正如您所看到的,我只调用了push_int_list
函数5次,因此应该只执行5个allocs和5个frees。如果我更改push语句的数量,在valgrind中分配和释放的数量总是比我实际执行的多一个。为什么valgrind总是比我实际执行的多一个malloc。
#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)
我想知道它是否将Int
结构的示例化作为malloc进行跟踪,但这是在堆栈内存中作为静态分配创建的,所以我不明白为什么这会作为valgrind中的malloc进行跟踪!
1条答案
按热度按时间toe950271#
你想太多了。如果Valgrind说“不可能有泄密”,那么你应该相信它。
内存是为您调用printf而分配的。由于此内存是以“singleton”方式分配的,因此glibc在Valgrind外部运行时不会释放此内存。您应该能够通过使用gdb并在
malloc
和free
上设置断点来确认这一点。glibc中的其他几个函数分配singleton缓冲区。Valgrind包含了一个释放内存的方法。当guest启动时,它会添加一个重定向到
exit()
以调用__libc_freeres()
,然后退出()。freeres函数通常不会被调用,只存在于像Valgrind这样的工具中。如果您使用
--run-libc-freeres=no
运行Valgrind,则memcheck将不再调用__libc_freeres
,因此将此分配“检测”为“可达”泄漏。