可能是重复问题:
为什么calloc需要两个参数,而malloc只需要一个参数?
有很多资源描述了malloc
和calloc
之间功能差异的区别,但我找不到一个能够描述这些函数签名差异背后历史的资源:
void *calloc(size_t nmemb, size_t size);
void *malloc(size_t size);
当然,前者中的是每个成员的大小。也许这个想法是,通过操作系统可以懒惰地实现对页面大小的倍数成员大小 ?这在C规范中使用的语言上有些开放性解释。
这里使用的语言似乎非常谨慎 - malloc在第7.20.3.3节中定义为:
malloc函数分配一个大小由size指定且值不确定的对象的空间。
早期,对象在第3.14节中被定义为:
执行环境中的数据存储区域,其内容可以表示值
另一方面,calloc在7.20.3.1中定义为:
calloc函数为nmemb个对象的数组分配空间,每个对象的大小为size。该空间初始化为所有位都为零。
这应该很明显了。calloc和malloc之间的区别在于calloc为n个概念对象的数组分配内存,尽管在实践中,这与调用malloc分配大小为(n * size)的1个概念对象的空间没有区别。
那么下一个问题是...为什么需要区分对象数组的空间和一个大对象的空间呢?
从程序员的角度来看,这两个函数调用只是在请求不同的东西。一个是请求分配一大块内存 - 我会处理它。另一个是说 - 我想要一个大小为n的这种类型的数组,给我一些可以用于此数组的内存,并将其清零 - 因为在大多数实现中,我可以对清零的内存做出良好的假设。#define malloc(x) (calloc(1, x))
有趣的是,如果我的NULL指针表示没有被清零,那么calloc不会返回一个由NULL指针组成的数组。更好的是,如果我设计了一个整数表示,在其中清零的内存不是((int)0),那么calloc不会返回一个由0组成的数组。
calloc
返回一个初始化对象的数组(尽管在所有实现中,全零比特并不保证是所有类型的有效对象,但这至少是一种合理的初始化尝试),而 malloc
返回一个对象或数组的未初始化原始内存? - Steve Jessopchar
和 signed/unsigned char
之外的每种类型的陷阱表示,从而使 calloc
几乎无用。作为推论,在严格符合规范的程序中,calloc
几乎无用,它的第二个参数在严格符合规范的程序中完全无用,因为它只对大小为1的类型有用。 - Steve Jessopmalloc(sizeof(double))
是否保证返回一个有效对齐的*double
?calloc(sizeof(double),1)
呢(与calloc(1,sizeof(double))
不同)?虽然我会对任何系统在内存分配时不能始终满足最长类型所需的要求感到惊讶,但我认为这样的系统可能并不一定被禁止。 - supercatmalloc()
和calloc()
都保证返回适合任何类型的指针对齐。请参阅N1570 7.22.3(N1570是2011年ISO C标准的最新草案)。 - Keith Thompson
calloc
的签名更可用,因为一个恰当的实现会在乘法溢出时检查,减轻调用者的责任。我怀疑有两种解释:(1)malloc
先出现了,只是一种兼容性问题,(2)calloc
预计会因为零清除而变慢,有人认为malloc
中的乘法和溢出检查应该被省略以提高速度。 - Steve Jessop