做什么之间有什么区别:
ptr = (char **) malloc (MAXELEMS * sizeof(char *));
或:
ptr = (char **) calloc (MAXELEMS, sizeof(char*));
什么时候使用calloc而不是malloc是一个好主意,反之亦然?
答案 0 :(得分:789)
calloc()
对缓冲区进行零初始化,而malloc()
使内存未初始化。
修改强>
将内存清零可能需要一些时间,因此如果性能有问题,您可能希望使用malloc()
。如果初始化内存更重要,请使用calloc()
。例如,calloc()
可能会为您保存对memset()
的调用。
答案 1 :(得分:348)
一个鲜为人知的区别是,在具有乐观内存分配的操作系统(如Linux)中,malloc
返回的指针在实际触摸它之前不会被实内存支持。
calloc
确实触及了内存(它在上面写了零),因此你可以确定操作系统正在用实际的RAM(或交换)来支持分配。这也是它比malloc慢的原因(它不仅要将它归零,操作系统还必须通过交换其他进程来找到合适的内存区域)
有关malloc
的行为的进一步讨论,请参阅this SO question答案 2 :(得分:104)
calloc
的一个经常被忽视的优点是(符合实现)它将有助于保护您免受整数溢出漏洞的影响。比较:
size_t count = get_int32(file);
struct foo *bar = malloc(count * sizeof *bar);
VS
size_t count = get_int32(file);
struct foo *bar = calloc(count, sizeof *bar);
如果count
大于SIZE_MAX/sizeof *bar
,前者可能导致微小的分配和随后的缓冲区溢出。在这种情况下,后者将自动失败,因为无法创建大的对象。
当然,您可能需要注意不符合要求的实现,这些实现只是忽略了溢出的可能性......如果这是您所针对的平台上的一个问题,那么无论如何您都必须手动测试溢出
答案 3 :(得分:32)
该文档使calloc看起来像malloc,它只是对内存进行零初始化;这不是主要的区别! calloc的想法是为内存分配禁止写时复制语义。使用calloc分配内存时,它都映射到初始化为零的同一物理页面。当分配的存储器的任何页面被写入物理页面时被分配。这通常用于制作HUGE哈希表,例如,因为哈希的部分是空的,不会被任何额外的内存(页面)支持;他们愉快地指向单个零初始化页面,甚至可以在进程之间共享。
对虚拟地址的任何写入都映射到页面,如果该页面为零页面,则分配另一个物理页面,在那里复制零页面并将控制流程返回给客户端进程。这与内存映射文件,虚拟内存等工作方式相同。它使用分页。
以下是关于该主题的一个优化故事: http://blogs.fau.de/hager/2007/05/08/benchmarking-fun-with-calloc-and-zero-pages/
答案 4 :(得分:26)
分配的内存块大小没有区别。 calloc
只用物理全零比特模式填充内存块。在实践中,通常假设位于分配有calloc
的内存块中的对象具有初始值,就好像它们是用文字0
初始化的那样,即整数应该具有值0
,浮动-point变量 - 0.0
的值,指针 - 适当的空指针值,依此类推。
从迂腐的角度来看,calloc
(以及memset(..., 0, ...)
)只能保证正确初始化(使用零)类型为unsigned char
的对象。其他所有内容都不能保证正确初始化,并且可能包含所谓的陷阱表示,这会导致未定义的行为。换句话说,对于除unsigned char
以外的任何类型,上述全零比特模式可能表示非法值,即陷阱表示。
后来,在C99标准的技术勘误之一中,为所有整数类型定义了行为(这是有意义的)。即形式上,在当前的C语言中,您只能使用calloc
(和memset(..., 0, ...)
)初始化整数类型。从C语言的角度来看,使用它来初始化其他任何一般情况都会导致未定义的行为。
在实践中,calloc
可以工作,我们都知道:),但是你是否想要使用它(考虑到上述情况)取决于你。我个人更喜欢完全避免它,而是使用malloc
来执行我自己的初始化。
最后,另一个重要细节是,通过将元素大小乘以元素数量,需要calloc
来计算最终块大小内部。这样做时,calloc
必须注意可能的算术溢出。如果无法正确计算所请求的块大小,则会导致分配失败(空指针)。同时,您的malloc
版本不会尝试查看溢出。如果发生溢出,它将分配一些“不可预测的”内存量。
答案 5 :(得分:20)
来自Benchmarking fun with calloc() and zero pages
上的文章Georg Hager's Blog使用calloc()分配内存时,请求的内存量不会立即分配。相反,属于内存块的所有页面都通过某些MMU魔法连接到包含全零的单个页面(下面的链接)。如果仅读取此类页面(对于基准测试的原始版本中的数组b,c和d都是如此),则数据从单个零页面提供,当然,该页面适合缓存。对于内存限制的循环内核来说非常重要。如果页面被写入(无论如何),则发生故障,映射“真实”页面并将零页面复制到存储器。这称为写时复制,这是一种众所周知的优化方法(我甚至已经在我的C ++讲座中多次教过)。在那之后,零读取技巧不再适用于该页面,这就是为什么在插入 - 假设冗余的 - init循环后性能会低得多。
答案 6 :(得分:11)
calloc
通常为malloc+memset
到0
明确地使用malloc+memset
通常会稍微好一些,特别是当您执行以下操作时:
ptr=malloc(sizeof(Item));
memset(ptr, 0, sizeof(Item));
这是更好的,因为在编译时编译器知道sizeof(Item)
,并且编译器在大多数情况下会用最好的指令替换它以使内存为零。另一方面,如果memset
中发生calloc
,则calloc
代码中的分配参数大小不会被编译,并且通常会调用实际memset
,这会通常包含用于逐字节填充直到长边界的代码,而不是循环以填充sizeof(long)
块中的内存,最后逐字节填充剩余空间。即使分配器足够聪明,可以调用一些aligned_memset
,它仍然是一个通用循环。
一个值得注意的例外是你正在做一个非常大的内存块(一些power_of_two千字节)的malloc / calloc,在这种情况下,可以直接从内核完成分配。由于操作系统内核通常会将出于安全原因而放弃的所有内存归零,因此足够聪明的calloc可能会将其返回并附加归零。再说一次 - 如果你只是分配你知道的东西很小,那么你可能会更好地使用malloc + memset性能。
答案 7 :(得分:8)
差异1: malloc()通常分配内存块,它是初始化的内存段。 calloc()分配内存块并将所有内存块初始化为0.
差异2: 如果考虑malloc()语法,则只需要1个参数。请考虑以下示例:
data_type ptr =(cast_type *)malloc(sizeof(data_type)* no_of_blocks);
例如:如果要为int类型分配10块内存,
int *ptr = (int *) malloc(sizeof(int) * 10 );
如果考虑calloc()语法,则需要2个参数。请考虑以下示例:
data_type ptr =(cast_type *)calloc(no_of_blocks,(sizeof(data_type)));
例如:如果你想为int类型分配10块内存并将所有内容初始化为ZERO,
int *ptr = (int *) calloc(10, (sizeof(int)));
相似度:
如果malloc()和calloc()没有类型化,它们将默认返回void *。
答案 8 :(得分:7)
有两点不同。
首先,是参数的数量。 malloc()
只需要一个参数(以字节为单位的内存),而calloc()
需要两个参数。
其次,malloc()
不初始化分配的内存,而calloc()
将分配的内存初始化为ZERO。
calloc()
分配一个内存区域,长度将是其参数的乘积。 calloc
用ZERO填充内存并返回指向第一个字节的指针。如果找不到足够的空间,则返回NULL
指针。语法:ptr_var=(cast_type *)calloc(no_of_blocks , size_of_each_block);
即ptr_var=(type *)calloc(n,s);
malloc()
分配REQUSTED SIZE的单个内存块并返回指向第一个字节的指针。如果无法找到需要的内存量,则返回空指针。语法:ptr_var=(cast_type *)malloc(Size_in_bytes);
malloc()
函数接受一个参数,即要分配的字节数,而calloc()
函数接受两个参数,一个是元素数,另一个是要分配的字节数每个元素。此外,calloc()
会将分配的空间初始化为零,而malloc()
则不会。
答案 9 :(得分:6)
calloc()
标头中声明的<stdlib.h>
函数比malloc()
函数提供了一些优势。
答案 10 :(得分:5)
尚未提及的差异:尺寸限制
void *malloc(size_t size)
最多只能分配SIZE_MAX
。
void *calloc(size_t nmemb, size_t size);
可以分配约SIZE_MAX*SIZE_MAX
。
这种能力通常不会在许多具有线性寻址的平台中使用。此类系统会将calloc()
限制为nmemb * size <= SIZE_MAX
。
考虑一种名为disk_sector
的512字节类型,代码想要使用 lot 扇区。在这里,代码最多只能使用SIZE_MAX/sizeof disk_sector
个扇区。
size_t count = SIZE_MAX/sizeof disk_sector;
disk_sector *p = malloc(count * sizeof *p);
考虑以下因素,可以进行更大的分配。
size_t count = something_in_the_range(SIZE_MAX/sizeof disk_sector + 1, SIZE_MAX)
disk_sector *p = calloc(count, sizeof *p);
现在,如果这样的系统可以提供如此大的分配是另一回事。今天大多数人不会。然而,当SIZE_MAX
为65535时,已发生多年。鉴于Moore's law,怀疑这将在2030年左右发生,某些内存模型的SIZE_MAX == 4294967295
和内存池的数量为100 GBytes。 / p>
答案 11 :(得分:4)
malloc()
和calloc()
是C标准库中的函数,它们允许动态内存分配,这意味着它们都允许在运行时分配内存。
他们的原型如下:
void *malloc( size_t n);
void *calloc( size_t n, size_t t)
两者之间主要有两个区别:
行为:malloc()
分配一个内存块而不初始化它,并且从该块中读取内容将导致垃圾值。另一方面,calloc()
分配一个内存块并将其初始化为零,显然读取该块的内容将导致零。
语法:malloc()
接受1个参数(要分配的大小),calloc()
接受两个参数(要分配的块数和每个块的大小)。
如果成功,两者的返回值都是指向分配的内存块的指针。否则,将返回 NULL ,指示内存分配失败。
示例:
int *arr;
// allocate memory for 10 integers with garbage values
arr = (int *)malloc(10 * sizeof(int));
// allocate memory for 10 integers and sets all of them to 0
arr = (int *)calloc(10, sizeof(int));
使用calloc()
和malloc()
可以实现与memset()
相同的功能:
// allocate memory for 10 integers with garbage values
arr= (int *)malloc(10 * sizeof(int));
// set all of them to 0
memset(arr, 0, 10 * sizeof(int));
请注意,malloc()
优于calloc()
,因为它更快。如果需要零初始化值,请改用calloc()
。
答案 12 :(得分:0)
块数:
malloc()分配所需内存的单个块,
calloc()分配所请求内存的多个块
初始化:
malloc()不会清除并初始化分配的内存。
calloc()将内存初始化为零。
速度:
malloc()速度很快。
calloc()的速度相对较慢。
语法:
void *malloc(size_t size); // syntex for malloc() function
void *calloc(size_t num, size_t size); // syntex for calloc() function
参数:
如果您考虑使用malloc()语法,则它将仅使用1个参数。
如果考虑calloc()语法,它将使用2个参数。
内存分配方式:
malloc()函数从可用堆中分配所需“大小”的内存。
calloc()函数分配的内存大小等于“ num * size”。
名称含义:
名称malloc表示归因于内存分配。
名称calloc表示连续分配。
答案 13 :(得分:0)
malloc
和calloc
都分配内存,但是calloc
会将所有位初始化为零,而malloc
则没有。
Calloc可以等效为malloc + memset
,其值为0(其中memset将内存的指定位设置为零)。
因此,如果不需要初始化为零,那么使用malloc可能会更快。