9

在这种情况下 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;
4

6 回答 6

7

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

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

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

void* xrealloc(void* ptr, size_t size) {
  ptr = realloc(ptr, size);
  if ( !ptr ) {
    exit(EXIT_FAILURE);
  }
  return ptr;
}
于 2010-03-29T20:57:12.307 回答
6

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

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

如果ptr是空指针,则realloc 函数的行为类似于malloc 指定大小的函数。否则,如果ptr不匹配先前由 、 或 函数返回的指针 callocmalloc或者realloc如果空间已通过调用freeorrealloc 函数被释放,则行为未定义。如果无法为新对象分配内存,则不会释放旧对象并且其值不变。

退货

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 标准中没有任何规定。

于 2010-03-29T21:22:24.723 回答
2

在任何情况下检查返回值都是一个好习惯realloc(规范并没有说缩小内存块比扩展它更安全)。但是您应该小心不要丢失初始指针(在您的情况下您会丢失),因为您将完全无法释放它。

于 2010-03-29T20:59:06.547 回答
2

C99 标准 §7.20.3.4 (realloc) 说:

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

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

退货

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

请注意,旧对象已被释放;新对象可能碰巧指向与旧对象相同的位置。而且可能会出现问题。这不太可能,但遵循“总是”的规则要比有奇怪的例外要简单得多。

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

在两个对“realloc()”的调用相邻的地方,就像这里一样,几乎没有任何出错的余地。然而,现实生活中的工作代码会在两者之间进行一些操作——并且该代码可能会导致第二个“realloc()”失败。

关于您的“编辑 2”...

代码可能更好地写成:

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

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

于 2010-03-29T21:21:15.143 回答
1

与 realloc() 中花费的时间相比,检查所需的时间是如此之少,以至于我什至不明白为什么会出现问题。还是想减少代码行数?

于 2010-03-29T21:28:54.913 回答
1

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)范例。

于 2014-09-13T03:45:26.480 回答