如果新块大小小于初始值,我应该强制执行realloc检查吗?

时间:2010-03-29 20:54:32

标签: c realloc

在这种情况下realloc会失败吗?

int *a = NULL;

a = calloc(100, sizeof(*a));
printf("1.ptr: %d\n", a);

a = realloc(a, 50 * sizeof(*a));
printf("2.ptr: %d\n", a);

if(a == NULL){
    printf("Is it possible?\n");
}

return (0);

}

我的输出是:

1.ptr: 4072560
2.ptr: 4072560

所以'a'指向相同的地址。 那么我应该强制执行realloc检查吗?

稍后修改

  • 在Windows XP下使用MinGW编译器。
  • 行为与Linux上的gcc类似吗?

稍后修改 2: 这样检查是否可以?

int *a = NULL, *b = NULL;

a = calloc(100, sizeof(*a));
b = realloc(a, 50 * sizeof(*a));

if(b == NULL){
    return a;
}
a = b;
return a;

6 个答案:

答案 0 :(得分:7)

是的,您应该始终对realloc或任何其他内存分配强制执行检查。

重用相同地址的当前行为是不应依赖的实现细节。这样做只是在库切换它的实现或移动到新平台时打开自己的bug。

这可能会失败吗?可能不是,如果你能找到一个案例,我会感到震惊。然而,这并不意味着它不会。在一个自动检查每个操作的函数中包装realloc很简单,没有理由不这样做。

void* xrealloc(void* ptr, size_t size) {
  ptr = realloc(ptr, size);
  if ( !ptr ) {
    exit(EXIT_FAILURE);
  }
  return ptr;
}

答案 1 :(得分:5)

如果realloc在传递小于原始分配的大小时失败,那将是令人惊讶的,但C标准(7.20.3.4)中没有任何内容保证它始终会成功:

  

realloc函数解除分配    ptr 指向的旧对象和   返回指向新对象的指针   具有 size 指定的大小。该   新对象的内容应为   与旧物体相同   在解除分配之前,直到   较小的新旧尺寸。任何   超出的新对象中的字节数   旧物体的大小有   不确定的价值观。

     

如果 ptr 是空指针, realloc   函数的行为类似于 malloc   指定大小的函数。   否则,如果 ptr 与a不匹配   早先返回的指针    calloc malloc realloc 功能,   或者如果空间已经解除分配   通过致电 free realloc   功能,行为未定义。   如果新对象的内存不能   分配,旧的对象不是   解除分配,其价值是   不变。

     

<强>返回

     

realloc 函数返回一个指针   到新对象(可能有   与旧指针相同的值   对象),或者如果是新的空指针   无法分配对象。

realloc的一个非常简单的符合性实现是这样的:

void *realloc(void *ptr, size_t size)
{
    void *new_ptr= malloc(size);
    if (new_ptr && ptr)
    {
        size_t original_size= _get_malloc_original_size(ptr);
        memcpy(new_ptr, ptr, min(original_size, size));
        free(ptr);
    }

    return new_ptr;
}

在内存不足的情况下(或malloc将返回NULL的任何条件),这将返回NULL

如果原始分配的大小大于或等于请求的大小,则返回相同的指针也是一种非常简单的优化。但是C标准中的任何内容都没有规定。

答案 2 :(得分:2)

最好在任何情况下检查realloc的返回值(规范并不表示如果缩小内存块比放大内存块更安全)。但是你应该注意不要丢失初始指针(在你的情况下你会这样做),因为你完全无法释放它。

答案 3 :(得分:1)

C99标准§7.20.3.4(realloc)说:

  

realloc函数释放ptr指向的旧对象并返回一个   指向具有size指定大小的新对象的指针。新内容   在解除分配之前,对象应与旧对象的对象相同,直到较小的对象   新旧尺寸。新对象中超出旧对象大小的任何字节都有   不确定的价值观。

     

如果ptr是空指针,则realloc函数的行为类似于malloc函数   指定大小。否则,如果ptr与之前返回的指针不匹配   calloc,malloc或realloc函数,或者如果空间已被调用释放   对于free或realloc函数,行为是未定义的。如果记忆为新的   无法分配对象,旧对象未被释放,其值不变。

     

返回

     

realloc函数返回一个指向新对象的指针(可能具有相同的指针)   value作为指向旧对象的指针),如果新对象不能,则返回空指针   分配

请注意,旧对象已取消分配;新对象可能碰巧指向与旧对象相同的位置。可能会有问题。这是不太可能的,但是使用规则“总是”比简单的例外要简单得多。

正常的反驳论据是“如果这不能失败,那就意味着我有一个我无法测试的错误路径”。到目前为止,这是事实。但是,可能存在一些内存的踩踏,因此分配不能成功 - 因为控制信息已被破坏。更有可能你只是获得核心转储,但也许代码足够强大,能够避免这种情况。 (我假设硬编码的100和50是为了提出问题的目的;当它知道它真正需要多少时,现实代码不会过度分配。)

对于'realloc()'的两个调用是相邻的,就像这里一样,没有什么地方可以出错。但是,实际工作代码会在两者之间进行一些操作 - 而且该代码可能导致第二个'realloc()'失败。

关于你的'编辑2'......

代码可能写得更好:

if (b != NULL)
    a = b;
return a;

但基本概念还可以。请注意,标准明确指出,如果无法创建新分配,则原始分配是安全的。

答案 4 :(得分:1)

与在realloc()中花费的时间相比,进行检查所花费的时间非常少,我甚至无法理解为什么它会成为一个问题。或者你想减少代码行数?

答案 5 :(得分:0)

realloc()可以轻松返回NULL缩小尺寸。

void *ptr = malloc(10);
ptr = realloc(ptr, 0);
if (ptr == NULL) {
  puts("Failure because return value is NULL? - not really");
}

realloc(any_pointer, 0)可以返回NULL或者某些not-NULL指针,它是实现定义的。

这就是realloc()/malloc()失败不应该是if (ptr == NULL)

的简单测试的原因
void *ptr = malloc(newsize); // or realloc(..., newsize)
if (ptr == NULL && newsize > 0) {
  exit(0); // Handle OOM;
}

由于这种歧义,如果代码想要制作realloc()包装器,建议如下:

void *xrealloc(void *ptr, size_t newsize, bool *falure) {
  *failure = 0;
  if (newsize > 0) {
    void *tmp = realloc(ptr, newsize);
    if (tmp == NULL) {
      *failure = 1;
      return ptr;  // old value
    }
    return tmp;  // new value
  } 
  free(ptr);
  return NULL; // new value
  }

因此NULL缩小realloc()并不是失败,所以这个答案只适用于此,但OP的问题是“...强制重新分配检查新的块大小是否小于初始块?“然后使用不太值得信赖的if (ptr == NULL)范例。