首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >calloc比malloc好吗?

calloc比malloc好吗?
EN

Stack Overflow用户
提问于 2016-12-21 13:04:21
回答 5查看 6K关注 0票数 17

前几天,我刚刚了解了C calloc()函数。在阅读了它的描述以及它与malloc (12)的不同之处后,我认为,作为一个非嵌入式程序员,我应该始终使用calloc()。但真的是这样吗?

我的一个保留是访问calloc()-ed内存的额外延迟,但我也不知道从malloc()切换到calloc()是否会以更严重的方式破坏程序。

在我看来,calloc()的零初始化方面是非常清楚的。我感兴趣的是calloc()malloc()之间的另一个区别-- calloc()提供的懒惰内存分配。如果您要将注意力完全集中在内存初始化方面,请不要发布答案。

EN

回答 5

Stack Overflow用户

发布于 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。

票数 11
EN

Stack Overflow用户

发布于 2016-12-21 13:09:09

malloccalloc的主要区别在于,calloc将对缓冲区进行零初始化,而malloc将保留未初始化的内存。

这就是常见的编程成语“不要为不使用的东西付费”。换句话说,如果你不一定需要(现在),为什么零初始化一些东西(这是有代价的)?

顺便提一句,因为您标记了C++:使用new/delete的手动内存使用在现代C++中是不受欢迎的(除了很少的内存池情况,等等)。malloc/free的使用更为罕见,应该非常谨慎地使用。

票数 3
EN

Stack Overflow用户

发布于 2016-12-22 07:58:36

使用calloc进行零填充分配,但只在真正需要零填充时才使用.

您应该始终使用calloc(count,size)而不是buff=malloc(total_size); memset(buff,0,total_size)

对零memset的调用是关键.malloccalloc都被转换成操作系统调用,这些调用可以进行大量的优化,尽可能地使用硬件技巧,等等。但是操作系统对memset所能做的事情很少。

另一方面,何时需要零填充分配的内存?唯一常用的是零结束的任意长度元素,如C-字符串.如果是这样的话,当然,和calloc一起去吧。

但是,如果您分配元素长度固定或携带任意大小元素的长度的结构(如C++字符串和向量),零填充根本没有帮助,如果您试图依赖它,就会导致棘手的错误。

假设您编写了自定义链接列表,并决定跳过指向下一个节点的指针的零化,方法是为具有calloc的节点分配内存。它工作很好,然后有人使用它与自定义安置新,这不是零填充。问题是,有时它会被零填充,并且能够通过所有通常的测试,投入生产,在那里它会崩溃,有时崩溃,可怕的不可重复的错误。

为了调试的目的,零填充通常也不是很好。0太常见了,您很少能够编写类似assert(size);的东西,因为它通常是一个有效值,您也可以用if(!size)来处理它,而不是使用断言。在调试器上,它也不会吸引你的眼球,通常你的记忆中到处都是零。最佳实践是避免长度的无符号类型(有符号长度对于运行时错误处理和一些最常见的溢出检查也很有用)。因此,虽然要避免使用buff=malloc(total_size); memset(buff,0,total_size),但以下内容是可以的:

代码语言:javascript
复制
const signed char UNINIT_MEM=MY_SENTINEL_VALUE;
buff=malloc(total_size);
#if DEBUG_MEMORY
memset(buff,UNINIT_MEM,total_size);
#endif

在调试模式下,运行时库甚至操作系统有时会为您执行此操作,例如检查这篇关于VC++特定前哨值的优秀文章

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41263448

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档