【问题标题】:Freeing memory before calling realloc()在调用 realloc() 之前释放内存
【发布时间】:2017-05-01 05:52:49
【问题描述】:

下面的代码有些混乱。

我使用 malloc() 分配内存,释放它,然后使用与参数相同的指针 ptr 调用 realloc(),但不要使用 realloc 的返回地址。

此代码编译并运行良好的打印预期字符串。我没想到它会因为 ptr 之前被释放。

但是,如果我将 realloc() 的返回地址分配给 ptr,而将其注释掉,那么当然会出现预期的运行时错误,因为 ptr 将为 NULL。

如果我只是将先前释放的 ptr 作为参数传递,为什么它会起作用。它显然再次分配内存?提前致谢。

注意:故意编写此代码只是为了尝试了解后台发生的情况。当然不建议取消引用悬空指针等。

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

int main()
{
    char* ptr;
    ptr = (char*)malloc(20);

    strcpy(ptr, "Hello");

    printf("Address before free : %d\n", ptr);
    printf("%s\n", ptr);

    free (ptr);

    printf("Address after free  : %d\n", ptr);
    printf("%s\n", ptr);

    realloc(ptr, 30);

    //ptr = realloc(ptr, 30); // causes runtime problem as expected

    strcpy(ptr, "Hello");

    printf("Address after realloc  : %d\n", ptr);
    printf("%s\n", ptr);

    return 0;
}

【问题讨论】:

  • 您在使用 ptr 调用 free 后取消引用它,这会导致 未定义的行为。您还使用错误的格式来打印 also 导致未定义行为的指针(您应该使用 "%p" 打印 void* 指针(并且您确实需要将指针转换为 @ 987654326@ 有效))。整个程序只是未定义行为的一个大展示。它所做的任何事情都不能真正被相信是正确的。
  • 逻辑上也想一想。如果realloc函数需要实际分配新内存并将数据复制到其中,那么它将返回指向新分配内存的指针。如果您不使用它,那么ptr 仍将指向旧内存。
  • 如果你在ptr 被释放后调用realloc(ptr, 30);,你会得到未定义的行为
  • 顺便说一句,您可以进行一个简单更改以使realloc 调用再次有效:使ptr 成为空指针。然后realloc 的行为就像malloc
  • 铸造malloc和朋友在C语言中是没用的。

标签: c pointers free dynamic-memory-allocation realloc


【解决方案1】:

ptr = realloc(ptr, 30);

这很糟糕。如果 realloc 失败怎么办,例如没有足够的内存并返回零,然后你失去了原来的指针,你就有了内存泄漏

【讨论】:

    【解决方案2】:

    你的程序的正确和示范版本:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main()
    {
        char* ptr;
        ptr = malloc(20);
    
        strcpy(ptr, "Hello");
    
        printf("Address : %p\n", (void*)ptr);
        printf("%s\n", ptr);
    
        ptr = realloc(ptr, 30);   // expand the memory pointed by ptr
                                  // from 20 to 30 bytes.
    
        printf("Address after realloc  : %p\n", (void*)ptr);  // address most likely different
        printf("%s\n", ptr);                           // displays still "Hello"
                                                       // as realloc preserves memory content
    
        free(ptr);     // eventually free what has been allocated previously
        return 0;
    }
    

    示例输出:

    Address : 00767BC8
    Hello
    Address after realloc  : 00768C38
    Hello
    

    顺便说一句:realloc 之前和之后的地址可能相同,具体取决于实现。

    尝试重新分配更少的内存(例如 18),地址很可能是相同的,但这仍然取决于实现。

    【讨论】:

    • 最好将realloc retun 值存储到临时指针中以测试realloc 是否失败。否则ptr 内存泄漏。
    • %d 对 64 位环境中的指针尤其不利,因为 8 字节的指针大小很可能大于 int,后者通常为 4 字节。
    • @alk 完成,我实际上将错误的代码复制/粘贴到答案中。
    【解决方案3】:

    调用realloc() 的函数将重新分配内存区域,前提是它先前已使用malloc() calloc()realloc 分配并且尚未通过调用@ 释放 987654325@。如果在realloc() 之前在一块内存上调用free() 将导致未定义的行为。不要将realloc() 用于已释放的内存。

    最好的问候!

    【讨论】:

    • 谢谢。我知道 realloc() 不应该用于释放的内存。我只是在测试它,看看在这种情况下它是否会导致运行时错误
    • @Engineer999,您不能假设当您的程序表现出未定义的行为时会发生运行时错误(就像它使用无效指针调用 realloc() 时一样)。你也不能假设没有运行时错误就意味着你的程序工作正常。
    【解决方案4】:

    对于realloc(),特别是引用C11 标准,第 7.22.3.5 章

    如果ptr 是空指针,则realloc 函数的行为类似于malloc 函数 规定的大小。否则,如果ptr 与内存先前返回的指针不匹配 管理功能,或者如果空间已通过调用freerealloc 函数,行为未定义。 [....]

    也就是说,在这种情况下,您调用了 undefined behavior 在此之前,通过说

    printf("Address after free  : %d\n", ptr);
    printf("%s\n", ptr);
    

    错误在哪里

    • %p 是指针所需的格式说明符,参数转换为 void *,而不是 %d
    • 尝试使用free()-d 内存

    其中,单独和单独足以调用 UB。


    底线:在将指针传递给realloc()之前不要尝试free(),它会自己处理。

    【讨论】:

      猜你喜欢
      • 2018-03-09
      • 2021-11-25
      • 2014-03-07
      • 2012-02-28
      • 2012-07-17
      • 2018-03-26
      • 2016-11-16
      • 1970-01-01
      • 2017-06-11
      相关资源
      最近更新 更多