发布于 2016-12-21 13:09:39
这真的是一个取决于形势的决定。经验法则是
malloc()会更好(减少可能的开销)。
示例:考虑以下场景
char *指针= NULL;//分配strcpy(指针,源);
在这里,使用malloc()可以很好地进行分配。calloc(),因为它初始化内存。这样,您就可以避免调用未定义行为的统一内存读写场景的问题。
示例:
char *指针= NULL;//分配strcat(指针,源);
在这里,strcat()需要第一个参数已经是一个字符串,而使用malloc()分配不能保证这一点。当calloc()零初始化内存时,它将在这里起作用,因此,calloc()就是解决这个问题的方法。为了详细说明第二个场景,引用C11,第7.24.3.1节(我的重点)
strcat()函数将s2指向的字符串(包括终止空字符)的副本附加到s2指向的字符串的端。s2的初始字符覆盖s1末尾的空字符。……
因此,在这种情况下,目标指针应该是指向字符串的指针。通过calloc()分配保证使用malloc()分配不能保证,如我们所知,第7.22.3.4章
malloc函数为值不确定的size和指定的对象分配空间。
编辑:
一种可能的情况是,malloc()被推荐使用于calloc(),那就是编写用于单元/集成测试的测试存根。在这种情况下,使用calloc()可以隐藏与后一种情况类似的潜在bug。
发布于 2016-12-21 13:09:09
malloc和calloc的主要区别在于,calloc将对缓冲区进行零初始化,而malloc将保留未初始化的内存。
这就是常见的编程成语“不要为不使用的东西付费”。换句话说,如果你不一定需要(现在),为什么零初始化一些东西(这是有代价的)?
顺便提一句,因为您标记了C++:使用new/delete的手动内存使用在现代C++中是不受欢迎的(除了很少的内存池情况,等等)。malloc/free的使用更为罕见,应该非常谨慎地使用。
发布于 2016-12-22 07:58:36
使用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)来处理它,而不是使用断言。在调试器上,它也不会吸引你的眼球,通常你的记忆中到处都是零。最佳实践是避免长度的无符号类型(有符号长度对于运行时错误处理和一些最常见的溢出检查也很有用)。因此,虽然要避免使用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++特定前哨值的优秀文章。
https://stackoverflow.com/questions/41263448
复制相似问题