【问题标题】:Proper usage of realloc()正确使用 realloc()
【发布时间】:2014-01-27 04:56:54
【问题描述】:

来自 man realloc:realloc() 函数返回一个指向新分配内存的指针,该指针针对任何类型的变量进行适当对齐,并且可能不同于 ptr,如果请求失败,则为 NULL .

所以在这段代码中sn-p:

ptr = (int *) malloc(sizeof(int));
ptr1 = (int *) realloc(ptr, count * sizeof(int));
if(ptr1 == NULL){           //reallocated pointer ptr1
    printf("Exiting!!\n");
    free(ptr);
    exit(0);
}else{
    free(ptr);          //to deallocate the previous memory block pointed by ptr so as not to leave orphaned blocks of memory when ptr=ptr1 executes and ptr moves on to another block
    ptr = ptr1;         //deallocation using free has been done assuming that ptr and ptr1 do not point to the same address                     
}

仅仅假设重新分配的指针指向不同的内存块而不是同一个块就足够了。因为如果假设变为错误并且realloc返回ptr指向的原始内存块的地址然后释放(ptr) 执行(由于 cmets 中给出的原因)然后内存块将被擦除并且程序会发疯。 我应该输入另一个条件来比较 ptr 和 ptr1 的相等性并排除 free(ptr) 语句的执行吗?

【问题讨论】:

  • PS-我没有足够的代表点来在关于 SO 的另一个类似问题中提出这个问题,所以我不得不提出一个新问题..

标签: c memory-leaks dynamic-memory-allocation realloc calloc


【解决方案1】:

只是不要在快乐路径中的原始 ptr 上调用 free()。基本上realloc() 已经为你做到了。

ptr = malloc(sizeof(int));
ptr1 = realloc(ptr, count * sizeof(int));
if (ptr1 == NULL) // reallocated pointer ptr1
{       
    printf("\nExiting!!");
    free(ptr);
    exit(0);
}
else
{
    ptr = ptr1;           // the reallocation succeeded, we can overwrite our original pointer now
}

【讨论】:

  • 在 realloc 的手册页中,我找不到它本身会调用 free()...thnx 的信息
  • @user3163420 真的吗?在我的 Mac man realloc 上:“...如果没有足够的空间来扩大 ptr 指向的内存分配,realloc() 会创建一个新分配,复制 ptr 指向的尽可能多的旧数据以适应新分配,释放旧分配,并返回一个指向已分配内存的指针。..."
  • heh... 类型转换不仅令人眼花缭乱,而且可能会在某些晦涩的系统上引起问题并且毫无用处...但是您保留它们以保持代码的原始性。现在引入了空间以使其不那么碍眼,它也没有任何功能用途,但不会破坏任何东西(与类型转换不同,它会)。我的观点是,如果您允许添加空格以使代码在风格上吸引人,您是否还允许删除不必要的类型转换以使代码更便携 风格上吸引人?我不打算编辑,但如果我这样做了,你会回复吗?
  • /me 喊“叔叔!”。演员表已移除。
【解决方案2】:

根据以下优秀的 cmets 将修复应用为编辑。

阅读this comp.lang.c question,发现3个案例:

  1. “当它能够做到时,它只是将你交给它的指针返回给你。”
  2. “但如果它必须去内存的其他部分找到足够的连续空间,它将返回一个不同的指针(并且之前的指针值将变得不可用)。”
  3. “如果realloc 根本找不到足够的空间,它会返回一个空指针,并保留之前分配的区域。”

这可以直接翻译成代码:

int* ptr = (int*)malloc(sizeof(int));
int* tmp = (int*)realloc(ptr, count * sizeof(int));
if(tmp == NULL)
{
    // Case 3, clean up then terminate.
    free(ptr);
    exit(0);
}
else if(tmp == ptr)
{
    // Case 1: They point to the same place, so technically we can get away with
    // doing nothing.
    // Just to be safe, I'll assign NULL to tmp to avoid a dangling pointer.
    tmp = NULL;
}
else
{
    // Case 2: Now tmp is a different chunk of memory.
    ptr = tmp;
    tmp = NULL;
}

所以,如果您考虑一下,您发布的代码(几乎)没问题。上面的代码简化为:

int* ptr = (int*)malloc(sizeof(int));
int* tmp = (int*)realloc(ptr, count * sizeof(int));
if(tmp == NULL)
{
    // Case 3.
    free(ptr);
    exit(0);
}
else if(ptr != tmp)
{
    ptr = tmp;
}
// Eliminate dangling pointer.
tmp = NULL;

请注意额外的else if(ptr != tmp),它不包括案例 1,您不想调用 free(ptr),因为 ptrtmp 指的是同一个位置。另外,为了安全起见,我确保将NULL 分配给tmp 以避免在tmp 在范围内时出现任何悬空指针问题。

【讨论】:

  • 您没有遵守“并且先前的指针值将变得无法使用”部分。在ptr != tmp 的情况下,free(ptr) 是错误的。
  • 同意@glglgl,这个答案很危险,因为你不能在情况2中调用free(ptr)。
  • 好电话,作为编辑应用,并为你们俩点赞。
  • @Keeler +1 用于将 tmp 指针设置为 NULL。当我将函数中的重新分配指针更改为静态时,我被严重咬伤了。这导致了随后的 realloc 调用(内存在函数调用之间被释放)的后续段错误,因为现在指针保留了它的旧(悬空)值。花了我一段时间才弄清楚...我有一个习惯,经常使用 realloc 而不是 malloc,但是必须保持警惕,以确保第一个 realloc 调用(没有先前的 malloc)确实得到一个 NULL 指针。
【解决方案3】:

OP: ... 可能与 ptr 不同,如果请求失败,则为 NULL。
答:并非总是如此。如果count 为0,NULL 可能会被合法返回(不是失败)。

OP:假设重新分配的指针指向不同的内存块而不是同一个块是否足够。
答:没有

OP:我是否应该输入另一个条件来比较 ptr 和 ptr1 的相等性并排除 free(ptr) 语句的执行?
答:没有。

如果realloc() 返回NULL(并且count 不为0),则ptr 的值仍然有效,指向未调整大小的数据。 free(ptr) 与否取决于您的目标。

如果realloc() 不返回NULL,也不返回free(ptr),则一切就绪。

示例:https://codereview.stackexchange.com/questions/36662/critique-of-realloc-wrapper

#include <assert.h>
#include <stdlib.h>

int ReallocAndTest(char **Buf, size_t NewSize) {
  assert(Buf);
  void *NewBuf = realloc(*Buf, NewSize);
  if ((NewBuf == NULL) && (NewSize > 0)) {
    return 1;  // return failure
  }
  *Buf = NewBuf;
  return 0;
}

【讨论】:

    【解决方案4】:

    如果realloc 有足够的空间来扩展ptr 指向的实际内存块,realloc 将返回相同的地址给ptr。否则,它将数据移动到新块并释放旧块。你不能指望ptr1ptr 不同。您的程序行为未定义。

    如果realloc 返回另一个地址,它会首先释放旧地址,这样您就不必自己动手了。

    顺便说一句,永远不要返回malloc/realloc :)。你的代码应该是这样的:

    ptr=malloc(sizeof(int));
    ptr=realloc(ptr,count*sizeof(int));
    if(ptr==NULL)
    {   
        // error!    
        printf("\nExiting!!");
        // no need to free, the process is exiting :)
        exit(0);
    }
    

    【讨论】:

    • 这里有一个问题:如果ptr为NULL,free(ptr)没有意义。
    • 嗯,这实际上是有道理的。此外,程序即将退出,所以不释放它没问题:)修复它:)
    • 这是一个实现细节,一般不正确:“如果 realloc 有足够的空间来扩展 ptr 指向的实际内存块,它将返回相同的地址给 ptr。”按大小分离分配的实现(例如 OpenBSD 的 omalloc)不太可能返回原始指针,除非原始大小和新大小匹配。
    • 用于添加关于 malloc() 等的强制转换返回的注释。+1
    • ptr=realloc(ptr,count*sizeof(int)); 坏了;当realloc 返回NULL(不是地址,因为它不指向对象)时,您会泄漏旧对象的内存。 The OpenGroup manual 声明:“如果空间无法分配,则对象应保持不变。” The C standard 声明:“如果无法分配新对象的内存,则旧对象为未解除分配,其值不变。”
    【解决方案5】:

    如果realloc 移动您的数据,它将在幕后为您释放旧指针。我没有 C11 标准的副本,但它在 C99 标准中得到保证。

    【讨论】:

    • C11 标准草案是 n1570.pdf,您可以通过谷歌搜索找到。我发现使用链接引用很有帮助(例如,clicking this link 将带您到 n1570.html 的 realloc 部分,该部分是从 n1570.pdf 转换而来的)。
    【解决方案6】:

    如果realloc 成功,您应该 free 您的原始指针。如果realloc 失败,您是否free 那个指针取决于您的特定应用程序的需要;如果您在没有额外内存的情况下绝对无法继续,那么这将是一个致命错误,您将取消分配任何持有的存储并退出。如果,OTOH,您仍然可以继续(也许执行不同的操作并希望内存稍后可用),您可能希望保留该内存并稍后尝试另一个 realloc

    Chapter and verse:

    7.22.3.5 realloc 函数

    概要

    1
         #include <stdlib.h>
         void *realloc(void *ptr, size_t size);

    说明

    2 realloc 函数释放ptr 指向的旧对象 并返回一个 指向具有size 指定大小的新对象的指针。新的内容 对象应与释放前的旧对象相同,直至两者中的较小者 新旧尺寸。新对象中超出旧对象大小的任何字节都有 不确定的值。

    3 如果ptr 是空指针,则realloc 函数的行为类似于malloc 函数 指定尺寸。否则,如果ptr 与内存先前返回的指针不匹配 管理功能,或者如果空间已通过调用 freerealloc 函数,行为未定义。 如果新对象的内存不能 已分配,旧对象不会被释放,其值不变。

    返回

    4 realloc 函数返回一个指向新对象的指针(可能具有相同的 值作为指向旧对象的指针),或者如果新对象不能是空指针 已分配。

    添加了重点。注意第 4 条;返回的指针可能与您的原始指针相同。

    【讨论】:

      猜你喜欢
      • 2017-12-01
      • 2014-02-08
      • 1970-01-01
      • 1970-01-01
      • 2018-11-24
      • 2016-02-06
      • 2014-09-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多