通常的做法是将重新分配的内存设置为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。