memset 将内存重新分配为 0 是常见的做法吗?

Is it common practice to memset reallocated memory to 0?

在一本 C 书中,我在一个实现动态调整数组大小的示例中找到了这段代码(简化):

void *contents = realloc(array->contents, array->max * sizeof(void *));
array->contents = contents;

memset(array->contents + old_max, 0, array->expand_rate + 1);

来源:Learn C The Hard Way – Chapter 34

我有点惊讶 memset 应该在这里实现什么,但后来我明白它是为了 "zero out" 重新分配的内存。

我用谷歌搜索以了解,如果这是我在 realloc 之后应该做的事情,并找到了关于此的 Whosebug 答案:

There is probably no need to do the memset […]

But, even if you wanted to "zero it out so everything is nice", or really need the new pointers to be NULL: the C standard doesn't guarantee that all-bits-zero is the null pointer constant (i.e., NULL), so memset() isn't the right solution anyway.

来源:How to zero out new memory after realloc

建议的解决方案而不是 memset 然后使用 for 循环来将内存设置为 NULL

所以我的问题是,因为 memset 并不一定意味着将值设置为 NULL 并且 for 循环解决方案似乎有点乏味 - 是否真的需要设置新的已分配内存?

So my question is, as memset does not necessarily mean setting values to NULL and the for loop solution seems a bit tedious – is it really needed to set the newly allocated memory?

realloc 不初始化新分配的内存段的值。

因此,如果您打算读取该(未初始化的)内存的值,则需要初始化内存。因为从未初始化的内存中读取值会触发未定义的行为。

顺便说一下,使用 realloc 的安全方法(因为它可能会失败)是:

  // Since using realloc with size of 0 is tricky and useless probably
  // we use below check (from discussion with @chux)
  if (new_size == 0) 
    dosmth();
  else 
  {
    new_p = realloc(p, new_size);
    if (new_p == NULL)
    {
      // ...handle error
    }else
    {
      p = new_p;
    }
  }

void * 设置为 0 是一个将与 NULL 进行比较的值。可能 memset(ptr, 0, size) 没问题 - 但需要查看更多代码才能确定。

OTOH:代码正确吗?也许应该

// memset(array->contents + old_max, 0, array->expand_rate + 1);
memset(array->contents + old_max, 0, sizeof(void *) * (array->expand_rate + 1) );

这是错误的:

But, even if you wanted to "zero it out so everything is nice", or really need the new pointers to be NULL: the C standard doesn't guarantee that all-bits-zero is the null pointer constant (i.e., NULL), so memset() isn't the right solution anyway.

C 标准实际上确实保证了这一点。

根据 C standard 的第 6.3.2.3 节:

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

Conversion of a null pointer to another pointer type yields a null pointer of that type. Any two null pointers shall compare equal.

注意,值为零的指针是a 空指针。这并不意味着 NULL 本身必须为零。但还要注意"any two null pointers shall compare equal"。所以任何 空指针 等于 NULL 值。

由于 memset() 将整数值作为其第二个参数,将零整数值传递给 memset() 将产生空指针。因为传递给 memset() 的值是“[a]n 值为 0 的整数常量表达式”,根据 6.3.2.3.