通常的做法是将重新分配的内存设置为0吗?

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

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

资料来源: 学习C艰难之路 – 第34章

我对memset在这里应该实现的内容感到有些惊讶,但后来我才知道它是为了“重新分配”重新分配的内存而使用的。

我用Google搜索,以便找出,如果这是我应该在realloc之后做的事情,并找到了关于此的stackoverflow答案:

可能没有必要做memset […]

但是,即使你想“将其归零所以一切都很好”,或者真的需要新的指针为NULL :C标准并不保证all-bits-zero是空指针常量(即NULL ) ,所以memset()无论如何都不是正确的解决方案。

来源: 如何在realloc之后将新内存清零

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

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

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

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) ); 

这是错的:

但是,即使你想“将其归零所以一切都很好”,或者真的需要新的指针为NULL:C标准并不保证all-bits-zero是空指针常量(即NULL) ,所以memset()无论如何都不是正确的解决方案。

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

根据C标准的 6.3.2.3节:

值为0的整型常量表达式或类型为void *的表达式称为空指针常量 。 如果将空指针常量转换为指针类型,则保证将结果指针(称为空指针)与指向任何对象或函数的指针进行比较。

将空指针转换为另一种指针类型会产生该类型的空指针。 任何两个空指针都应该相等。

请注意,值为零 指针空指针 。 这并不意味着NULL本身必须为零。 但是请注意“任何两个空指针都应该相等” 。 所以任何空指针都等于NULL值。

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