【问题标题】:malloc'ing and realloc'ing pointers causing memory leaks on returnmalloc'ing 和 realloc'ing 指针导致返回时内存泄漏
【发布时间】:2016-10-23 09:02:10
【问题描述】:

我被告知要编写一个包装器,该包装器采用位置的起始地址和数字“n”作为大小。稍后,用这个内存来存储一些东西。 我能够编写代码,但程序中存在内存泄漏。 这是程序:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int alloc_func(char *newptr, int size)
{
    newptr = (char *)realloc(newptr, size);
    printf("In func: %p\n", newptr);
    if(NULL == newptr)
        return 0;
    else
        return 1;
}

int main(int argc, char **argv)
{
    char *foo = "Computer";  //string to be copied to newly allocated memory

    char *ptr = (char *)malloc(1*sizeof(char));
    printf("Before return: %p\n", ptr);
    int size = 10, flag;

    flag = alloc_func(ptr, size);

    printf("After return: %p\n", ptr);

    if(flag == 0)
        return EXIT_FAILURE;
    else{
        strcpy(ptr, foo);
    }

    printf("The copied string is: %s\n", ptr);

    free(ptr);

    return 0;

}

在运行 valgrind 时,泄漏摘要显示 “肯定丢失:1 个块中的 10 个字节”

发生这种情况是因为我将 ptr(起始地址)作为指针值发送给函数,因此函数正在创建指针的副本,即程序中的 newptr。这个 newptr 正在重新分配到 10 个位置。由于我没有返回 newptr,一旦函数结束,我的“重新分配”位置将超出范围并丢失。

我的疑问是:

a) 即使创建了指针的副本,ptr 和 newptr 都会指向同一个内存位置,那为什么会泄漏呢?

b) malloc 的变量不是“全局”的吗?

c) 发生泄漏是因为我没有传递指针的地址以便不会创建副本吗? (我试过这个,但我想知道为什么)

d) 在我的主要内容中,什么是免费的(那么 ptr 在做什么)?只是清除 1 的 ptr malloc'ed?

e) 有什么方法可以检查这 10 个“大小”字节的分配是否成功?

【问题讨论】:

  • realloc 之后,ptr 不一定等于newptr,因为它是按值传递的,realloc 可能会返回不同的指针。瞧——你的ptr 指向错误的位置,周围有一些丢失的记忆。释放 ptr 导致 UB。
  • @EugeneSh。我在调用之前、调用之后和函数内部打印指针的地址。所有地址都相同,即 newptr 和 ptr 指向相同的地址。如何?如果我在函数调用后尝试在 main 中访问 ptr,由于 ptr 没有更新内存,它必须给出 seg 错误。但是,该程序如何正常运行?

标签: c pointers memory memory-leaks valgrind


【解决方案1】:

您正在更改alloc_funcnewptr 的值。但是,这只是局部变化。它不会改变调用函数中指针的值。因此,您有一个悬空指针和内存泄漏。

调用函数有一个悬空指针。
alloc_func 有内存泄漏。

您需要将新分配的指针从alloc_func 返回给调用函数。您可以通过返回值或将参数更改为指向指针的指针来做到这一点。

解决方案 1:返回指针

char* alloc_func(char *newptr, int size)
{
    newptr = (char *)realloc(newptr, size);
    printf("In func: %p\n", newptr);
    return newptr;
}

并将main中的调用更改为:

ptr = alloc_func(ptr, size); // not flag = ...

解决方案 2:更改参数类型

int alloc_func(char **newptr, int size)
{
    *newptr = (char *)realloc(*newptr, size);
    printf("In func: %p\n", *newptr);
    if(NULL == *newptr)
        return 0;
    else
        return 1;
}

并将main 中的调用更改为:

flag = alloc_func(&ptr, size); // Use &ptr, not ptr

【讨论】:

    【解决方案2】:

    你的 alloc_func() 方法应该是:

    int alloc_func(char **newptr, int size)
    {
        char *p = (char *)realloc(*newptr, size);
        printf("In func: %p\n", p);
        if(NULL == p) {
            return 0;
        } else {
            *newptr = p;
            return 1;
    }
    

    然后你用

    来调用它
    flag = alloc_func(&ptr, size);
    

    这样 ptr 就会改变。

    【讨论】:

    • 极端情况:代码调用 alloc_func(&amp;ptr, 0); 可能无法正确更新 ptr,因为 realloc(*newptr, 0) 可能会返回 NULL 而不是内存不足的情况。
    • @FredK。谢谢。 malloc 的变量不是全局的吗?我的意思是它们是在堆上分配的,所以它必须可以从任何地方访问。我说的对吗?
    • 这不是问题,信息搜索者。问题是您的函数版本按值访问第一个参数 (newptr)。 newptr 本身(在您的函数内部)的更改不会影响main()ptr 的值。 FredK 的解决方案纠正了这一点 - 这就是为什么他将参数从指针更改为指向指针的指针,并在函数内部分配给 *newptr 而不是 newptr
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-10
    相关资源
    最近更新 更多