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