即使我在 C 中自由,也肯定丢失了记忆

Definitely lost memory even though I free in C

提问人:Jason 提问时间:10/27/2023 更新时间:10/27/2023 访问量:81

问:

我想创建一个函数,当给定一个结构体时,该结构体中有一个指向相同类型的另一个结构的指针,它会找到所有指针并释放它们。
结构为:

typedef struct example_ {
    uint16_t something;
    bool blabla;
    struct example_ *further_in; 
} example;

我创建的用于释放每个指针的函数是:

bool free_examples(example p) {
    bool isCounting = true;
    int16_t count = 0;
    example firstexample = p;
    while (isCounting) // counts how many examples there are
    {
        if (p.further_in == NULL)
        {
            isCounting = false; 
        }
        else if (p.further_in != NULL)
        {
            count++;
            p = *(p.further_in);
        }       
    }
    p = firstexample;
    example *n = malloc(sizeof(example));
    for (int i = 0; i < count; i++) // frees every pointer?
    {
        n = p.further_in;
        free(p.further_in);
        p = *(n);
    }
    free(n);    
    return true;
}

首先,我是编程和 C 的新手,所以我甚至不知道我的代码是否做了我想做的事情。
其次,我的问题是,当我通过 valgrind 运行它时,它返回的这一行肯定丢失了 16 个字节:

example *n = malloc(sizeof(example));

正如你所看到的,我释放了“n”,稍后。我不明白它怎么仍然泄露。

提前感谢您的任何帮助!

C 无内存泄漏

评论

0赞 Gerhardh 10/27/2023
n = p.further_in;这将丢弃您从 收到的值。你将永远无法释放你分配的东西。malloc
0赞 Gerhardh 10/27/2023
p = *(n);这将取消引用您之前刚刚释放的一行。复制指针不允许在释放内存后访问内存。p.further_in
0赞 n. m. could be an AI 10/27/2023
你可能想读这个
0赞 Gerhardh 10/27/2023
“正如你所看到的,我释放了”n“,稍后。我不明白它怎么还会泄露。变量的名称是否与分配内存时的名称相同并不重要。它与它所持有的地址值有关。
0赞 Jason 10/27/2023
谢谢 Gerhardh,您的回答消除了我的一些困惑!

答:

3赞 Vlad from Moscow 10/27/2023 #1

此代码片段:

p = firstexample;
example *n = malloc(sizeof(example));
for (int i = 0; i < count; i++) // frees every pointer?
{
    n = p.further_in;
    free(p.further_in);
    p = *(n);
}
free(n); 

至少会产生内存泄漏,并且具有未定义的行为。

在这一行中:

example *n = malloc(sizeof(example));

有分配的内存,其地址分配给指针。然后在下面的 for 循环中,指针被重新分配:nn

    n = p.further_in;

因此,分配的内存的地址将丢失。

还有这个声明

p = *(n);

访问已释放的内存,从而导致未定义的行为。

此外,也不清楚该类型的传递对象是否为:example

bool free_examples(example p) {
                          ^^^

是否存储在动态分配的内存中。如果它确实被放置在动态分配的内存中,那么它也应该被释放,并且至少应该声明该函数,如下所示:

void free_examples(example *p) {
                           ^^^

返回类型 bool 也没有意义。

请注意,相对于释放已分配内存的过程,计算非空指针的数量没有意义,并且效率低下且冗余。

如果你有一个单向链表,其中列表的所有节点都是动态分配的,那么该函数可以按以下方式显示:

void free_examples( example **p ) 
{
    while ( *p != NULL )
    {
        example *current = *p;
        *p = ( *p )->further_in;
        free( current );
    }
}

如果在调用方中,您有一个指向列表的第一个节点的指针,该节点是动态分配的,例如:

example *head = malloc( sizeof( example ) );

然后函数被调用如下:

free_examples( &head );

评论

0赞 Jason 10/27/2023
感谢您的详细回答!我现在更了解它了。
1赞 Vlad from Moscow 10/27/2023
@TedLyngmo谢谢。这是一个错别字。我已经更新了代码。
0赞 Vlad from Moscow 10/27/2023
@Jason完全没有。不客气:)
2赞 Ted Lyngmo 10/27/2023 #2

您当前正在访问内存之前释放内存。一个简单的解决方案是创建一个指针,如下所示:next

void free_examples(example **p) {
    if (p == NULL) return;
    for (example *curr = *p, *next; curr; curr = next) {
        next = curr->further_in; // get the pointer to the next `example` before ...
        free(curr);              // ... freeing what `curr` points at
    }
    *p = NULL;
}

然后,您需要通过获取指针的地址来调用它:example

free_examples(&n);