这是一个非常情况依赖的决定。经验法则是:
如果您是第一次写入分配的内存,那么使用malloc()
更好(可能会有较少的开销)。
例如:考虑以下情况
char * pointer = NULL;
//allocation
strcpy(pointer, source);
在这里,可以使用malloc()
非常好地进行内存分配。
如果在分配的内存中存在读写顺序错误的可能性,请使用calloc()
,因为它会初始化内存。这样,您就可以避免未初始化内存读写顺序错误的问题,从而避免调用未定义行为。
例如:
char * pointer = NULL;
//allocation
strcat(pointer, source);
在这里,strcat()
需要第一个参数已经是一个字符串,并且使用malloc()
进行分配不能保证这一点。由于calloc()
会对内存进行零初始化,因此它将在这里起到作用,因此calloc()
是应该选择的方法。
为了阐述第二种情况,引用自C11
,第§7.24.3.1章节(我的重点)
strcat()
函数将s2
指向的字符串(包括终止空字符)的副本附加到s1
指向的字符串的末尾
。s2
的初始字符覆盖s1
末尾的空字符。[....]
因此,在这种情况下,目标指针应该是指向字符串的指针。通过calloc()
进行分配可以保证这一点,而使用malloc()
进行分配不能保证,正如我们所知道的,来自第§7.22.3.4章节
malloc
函数分配大小由size
指定并且值不确定的对象的空间。
编辑:
建议在编写用于单元/集成测试的测试桩时使用malloc()
而不是calloc()
的一个可能情况是,calloc()
的使用可以隐藏与后者类似的潜在错误。
calloc()
提供的惰性内存分配又是怎样的呢? - Violet Giraffemalloc()
和/或calloc()
同样适用。你能详细说明一下吗? - Sourav Ghoshchar
数组的第一个字符设置为'\0'
,那就直接这么做。对于这样简单的初始化,使用calloc
会过度杀伤。 - Pete Beckermalloc
和 calloc
的主要区别在于 calloc
会将缓冲区初始化为零,而 malloc
则不会对内存进行初始化。new/delete
来分配内存是不被推荐的(除非是在内存池等少数情况下)。使用 malloc/free
更加罕见,应该非常谨慎地使用。对于需要清零的分配,使用calloc
,但仅当真正需要清零时才使用。
您应始终使用calloc(count,size)
而不是buff=malloc(total_size); memset(buff,0,total_size)
。
对memset
的调用是关键。 malloc
和calloc
都被转换为执行许多优化、尽可能使用硬件技巧等操作系统调用。 但是,操作系统在memset
方面可以做的很少。
另一方面,何时需要填充分配的内存?唯一常见的用途是用于以零结尾的任意长度元素,例如C字符串。 如果是这种情况,请使用calloc
。
但是,如果您分配的结构中的元素具有固定长度或携带带有它们的任意大小元素的长度(例如C ++字符串和向量),则填充零不起作用,如果您尝试依赖它,则可能会导致棘手的错误。
假设您编写了自定义链接列表,并决定跳过指向下一个节点的指针的清零,方法是使用calloc
为节点分配内存。 它起作用,然后有人使用自定义放置新对象,它不会填充零。问题在于,有时它将被填充为零,并且可以通过所有通常的测试,进入生产环境,然后会崩溃,有时会崩溃,这是可怕的无法重复的错误。
出于调试目的,填充零通常不是那么好的选择。 0太常见了,您很少能写出像assert(size);
这样的东西,因为它通常也是有效值,您需要使用if(!size)
而不是asserts处理它。 在调试器中,它也不会引起注意,您的内存中通常到处都是零。 最佳实践是避免用于长度的无符号类型(对于运行时错误处理和一些常见的溢出检查,有符号长度也可能很有用)。 因此,应避免使用buff=malloc(total_size); memset(buff,0,total_size)
,而以下操作则没有问题:
const signed char UNINIT_MEM=MY_SENTINEL_VALUE;
buff=malloc(total_size);
#if DEBUG_MEMORY
memset(buff,UNINIT_MEM,total_size);
#endif
在调试模式下,运行时库甚至操作系统有时会为您执行此操作,例如检查VC++特定哨兵值的这篇优秀文章。
这完全取决于您想用内存做什么。malloc
返回未初始化的(可能甚至还不存在的)内存。calloc
返回真实的、零值的内存。如果您需要它被清零,那么是的,calloc
是您最好的选择。如果不需要,为什么要在不需要时付出延迟成本来清零呢?
calloc()
提供的惰性分配。 - Violet Giraffemalloc
。在Linux上,malloc
返回的指针甚至不指向实际内存。只有当程序第一次访问该内存时,内存才会变得真实。 - Paul Evans在C代码中,malloc()比calloc()更为常见。
搜索"malloc"文本会忽略掉对calloc()的调用。
替换库通常会有mymalloc()、myrealloc()和myfree(),但没有mycalloc()。
指针和实数的零初始化并不能保证有预期的效果,尽管在每个主要平台上,所有位都为零对于指针而言是NULL,对于实数而言是0.0。
calloc()往往会隐藏错误。调试malloc通常会设置一个填充模式,如DEADBEEF,它被计算为一个很大的负数,看起来不像真实数据。因此程序很快就会崩溃,并且使用调试器可以找出错误。
calloc()
函数? - Sourav Ghoshstd::unique_ptr<T[]>
。这样你就有了内置的内存管理。 - NathanOliverstd::unique_ptr
仅将该删除绑定到指针范围,因此您无需记住它。具有默认删除器的std::unique_ptr
应与自己完成同样有效,而且不会出现错误的好处。 - NathanOliverdelete[]
,那么它甚至不会使指针的大小变大。在gcc中,sizeof(std::unique_ptr<int[]>)
为8
,与单个指针(64位)的大小相同。 - NathanOliver