malloc和calloc之间的区别?

做什么有什么区别:

ptr = (char **) malloc (MAXELEMS * sizeof(char *)); 

要么:

 ptr = (char **) calloc (MAXELEMS, sizeof(char*)); 

什么时候使用calloc over malloc是一个好主意,反之亦然?

calloc()初始化缓冲区,而malloc()使内存未初始化。

编辑:

清零内存可能需要一点时间,所以如果性能是个问题,您可能需要使用malloc() 。 如果初始化内存更重要,请使用calloc() 。 例如, calloc()可能会保存您对memset()的调用。

一个鲜为人知的区别是,在内存分配比较乐观的操作系统中,像Linux一样, malloc返回的指针在程序实际触及它之前不会被真实存储器支持。

calloc的确会触及内存(它会写入零),因此您可以确定操作系统正在使用实际的内存(或交换)进行分配。 这也是为什么它比malloc慢(不仅需要将其清零,操作系统还必须找到一个合适的内存区域,可能会将其他进程替换掉)

关于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只是用物理的全零位模式填充内存块。 在实践中,通常假设位于分配有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看起来像malloc,它只是零初始化内存; 这不是主要的区别! calloc的思想是为存储器分配提供copy-on-write语义。 当你用calloc分配内存时,它全部映射到初始化为零的相同物理页面。 当分配的内存中的任何页面被写入物理页面时被分配。 这通常被用来制作巨大的散列表,例如,由于散列的散列部分不被任何额外的存储器(页面)支持; 他们高兴地指向单个零初始化页面,甚至可以在进程之间共享。

任何对虚拟地址的写入都被映射到一个页面,如果该页面是零页面,则分配另一个物理页面,在那里复制零页面,并将控制流程返回给客户端进程。 这工作方式相同的内存映射文件,虚拟内存等工作..它使用分页。

以下是关于该主题的一个优化故事: http : //blogs.fau.de/hager/2007/05/08/benchmarking-fun-with-calloc-and-zero-pages/

从一篇文章与 乔治·海格博客上的calloc()和零页面进行基准对比

当使用calloc()分配内存时,请求的内存量不会立即分配。 相反,属于内存块的所有页面通过一些MMU魔术(下面的链接)连接到包含全零的单个页面。 如果只读取这些页面(对于原始版本的基准测试中的数组b,c和d,则为真),数据是从单个零页面提供的,当然这些页面可以放入缓存中。 对于内存限制的循环内核来说非常重要。 如果页面被写入(无论如何),则发生错误,“真实”页面被映射,并且零页被复制到存储器。 这被称为copy-on-write,一个众所周知的优化方法(我甚至在我的C ++讲座中多次教过)。 之后,零读技巧不再适用于该页面,这就是为什么在插入 – 假定冗余 – 初始化循环后性能低得多。

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性能明智。

malloc()分配给定大小的内存块(以字节为单位),并返回一个指向块开始的指针。

 void *malloc(size_t size); 

malloc()不初始化分配的内存。

calloc()分配内存,并初始化分配内存到所有位零。

 void *calloc(size_t num, size_t size); 

有两个区别。
首先,是在论点的数量。 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()不初始化。

差异1:malloc()通常分配内存块,它是初始化的内存段。 calloc()分配内存块并将所有内存块初始化为0。

差异2:如果考虑malloc()语法,则只需要1个参数。 考虑下面的例子:

ptr data_type =(cast_type *)malloc(sizeof(data_type)* no_of_blocks);

例如:如果你想为int类型分配10块内存,

  int *ptr = (int *) malloc(sizeof(int) * 10 ); 

如果您考虑calloc()语法,则需要2个参数。 考虑下面的例子:

ptr data_type =(cast_type *)calloc(no_of_blocks,(sizeof(data_type)));

例如:如果要为int类型分配10个内存块,并将所有内存初始化为零,

  int *ptr = (int *) calloc(10, (sizeof(int))); 

相似:

如果malloc()和calloc()不是键入类型,则它们将默认返回void *。

<stdlib.h>头文件中声明的calloc()函数比malloc()函数提供了一些优点。

  1. 它将内存分配给一定数量的元素,并且
  2. 它初始化分配的内存,使所有的位都为零。

尚未提及的差异: 大小限制

void *malloc(size_t size)只能分配到SIZE_MAX

void *calloc(size_t nmemb, size_t size); 可以分配约SIZE_MAX*SIZE_MAX

线性寻址的许多平台并不经常使用这种功能。 这样的系统用nmemb * size <= SIZE_MAX限制calloc()

考虑一个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的内存池。

malloc():分配所请求的字节大小,并返回指针分配空间的第一个字节

calloc():为数组元素分配空间,初始化为零,然后返回一个指向内存的指针

malloc和calloc之间的主要区别是:

  1. malloc代表内存分配,而calloc代表连续分配
  2. malloc只接受一个参数 ,即块的大小,而calloc则需要两个参数 ,要分配的块的数量和每个块的大小。

    ptr =(cast-type *)malloc(byte-size)// malloc

    ptr =(cast-type *)calloc(块号,块大小); // calloc

  3. malloc不执行内存初始化,所有地址都存储垃圾值,而calloc执行内存初始化,地址初始化为零或空值

名称malloc和calloc()是动态分配内存的库函数。
这意味着内存是在运行时(程序的执行)从堆段分配的。

初始化:malloc()分配给定大小的内存块(以字节为单位),并返回一个指向块开始的指针。

 > malloc() doesn't initialize the allocated memory. If we try to access the content of memory block then we'll get garbage values. void * > malloc( size_t size ); > calloc() allocates the memory and also initializes the allocates memory block to zero. If we try to access the content of these blocks then we'll get 0. > void * calloc( size_t num, size_t size ); 

一些参数:与malloc()不同,calloc()有两个参数:1)要分配的块数。 2)每个块的大小。

最重要的 :

除非我们需要零初始化,因为malloc比calloc快,否则最好使用malloc over calloc。 所以如果我们只想复制一些东西或者做一些不需要用零填充的块,那么malloc就是一个更好的选择。

 char *ptr = (char *) malloc (n * sizeof(char)); 

只是分配n bytes的内存而没有任何初始化(即;那些内存字节将包含任何垃圾值)。

然而,除了malloc()函数以外,c中的calloc()方法对所有占用的内存字节进行初始化为0

malloc()接受一个参数,而calloc()接受两个参数。

其次,malloc()不初始化分配的内存,而calloc()将分配的内存初始化为ZERO。 malloc和calloc在C语言中用于动态内存分配,它们动态地获得内存块。