870

做有什么区别:

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

或者:

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

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

4

14 回答 14

936

calloc()为您提供一个零初始化的缓冲区,malloc()而使内存未初始化。

对于大分配,calloc主流操作系统下的大多数实现将从操作系统(例如通过 POSIXmmap(MAP_ANONYMOUS)或 Windows VirtualAlloc)获得已知零页面,因此不需要在用户空间中编写它们。这也是正常malloc从操作系统获取更多页面的方式;calloc只是利用操作系统的保证。

这意味着calloc内存仍然可以是“干净的”和延迟分配的,并且写入时复制映射到系统范围的共享零物理页。(假设系统具有虚拟内存。)

一些编译器甚至可以为您优化 malloc + memset(0) 为 calloc,但如果您希望内存读取为0.

如果您在写入之前不打算读取内存,请使用malloc它以便(可能)从其内部空闲列表中为您提供脏内存,而不是从操作系统获取新页面。(或者不是将空闲列表上的一块内存归零以进行少量分配)。


如果没有操作系统,嵌入式实现calloc可能会将其自身保持为零内存,或者它不是一个花哨的多用户操作系统,它会将页面归零以阻止进程之间的信息泄漏。calloc

在嵌入式 Linux 上, malloc 可以mmap(MAP_UNINITIALIZED|MAP_ANONYMOUS),它仅对某些嵌入式内核启用,因为它在多用户系统上不安全。

于 2009-10-08T15:05:25.260 回答
377

一个鲜为人知的区别是,在具有乐观内存分配的操作系统中,如 Linux,malloc在程序实际接触到它之前,返回的指针不会由实际内存支持。

calloc确实会触及内存(它会在上面写零),因此您可以确定操作系统正在使用实际 RAM(或交换)支持分配。这也是它比 malloc 慢的原因(不仅必须将它归零,操作系统还必须通过可能换出其他进程来找到合适的内存区域)

有关malloc 行为的进一步讨论,请参见例如这个 SO question

于 2009-10-18T20:44:56.330 回答
115

一个经常被忽视的优点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. 在这种情况下,后者将自动失败,因为无法创建这么大的对象。

当然,您可能必须注意不符合要求的实现,这些实现只是忽略了溢出的可能性......如果这是您所针对的平台上的一个问题,那么无论如何您都必须手动测试溢出。

于 2010-08-13T16:53:30.150 回答
40

文档calloc看起来像malloc,它只是对内存进行零初始化;这不是主要区别!的想法calloc是为内存分配抽象写时复制语义。当您使用它分配内存时,calloc它们都映射到初始化为零的相同物理页面。当已分配内存的任何页被写入物理页时,就会被分配。这通常用于制作巨大的哈希表,例如因为空的哈希部分没有任何额外的内存(页面)支持;他们高兴地指向单个零初始化页面,甚至可以在进程之间共享。

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

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

于 2013-08-15T11:16:29.420 回答
27

分配的内存块的大小没有区别。calloc只是用物理全零位模式填充内存块。在实践中,通常假设位于分配的内存块中的对象calloc具有初始值,就好像它们是用字面量初始化的一样0,即整数应该具有值0,浮点变量 - 值0.0,指针 - 适当的空指针值, 等等。

但是,从迂腐的角度来看,calloc(以及memset(..., 0, ...))只能保证正确初始化(用零)类型的对象unsigned char。其他所有内容都不能保证正确初始化,并且可能包含所谓的陷阱表示,这会导致未定义的行为。换句话说,对于除unsigned char上述全零位模式之外的任何类型,都可能表示非法值,陷阱表示。

后来,在 C99 标准的技术勘误之一中,为所有整数类型定义了行为(这是有道理的)。即,正式地,在当前的 C 语言中,您只能用calloc(and memset(..., 0, ...)) 初始化整数类型。从 C 语言的角度来看,在一般情况下使用它来初始化其他任何东西都会导致未定义的行为。

在实践中,calloc我们都知道 :) 是可行的,但是您是否要使用它(考虑到上述情况)取决于您。我个人更喜欢完全避免它,malloc而是使用并执行我自己的初始化。

最后,另一个重要的细节是内部calloc计算最终块大小所需的,方法是将元素大小乘以元素数量。这样做时,必须注意可能的算术溢出。如果无法正确计算请求的块大小,将导致分配不成功(空指针)。同时,您的版本不会尝试监视溢出。如果发生溢出,它将分配一些“不可预测的”内存量。callocmalloc

于 2009-10-18T20:59:32.893 回答
21

来自Georg Hager 博客上的文章Benchmarking fun with calloc() 和零页

使用 calloc() 分配内存时,请求的内存量不会立即分配。相反,属于内存块的所有页面都通过某种 MMU 魔法连接到包含全零的单个页面(下面的链接)。如果仅读取此类页面(在基准测试的原始版本中对数组 b、c 和 d 是正确的),则数据是从单个零页面提供的,这 - 当然 - 适合缓存。内存绑定的循环内核就这么多。如果一个页面被写入(无论如何),就会发生错误,映射“真实”页面并将零页面复制到内存中。这被称为写时复制,这是一种众所周知的优化方法(我什至在我的 C++ 讲座中多次教授过这种方法)。之后,

于 2013-08-28T05:51:19.627 回答
14

calloc一般malloc+memset为0

显式使用通常会稍微好一些malloc+memset,尤其是当您执行以下操作时:

ptr=malloc(sizeof(Item));
memset(ptr, 0, sizeof(Item));

这更好,因为sizeof(Item)编译器在编译时就知道了,并且在大多数情况下,编译器会用最好的指令替换它以使内存为零。另一方面,如果memset发生在 中calloc,则分配的参数大小未在calloc代码中编译,并且经常调用 real memset,这通常包含执行逐字节填充直到长边界的代码,而不是循环填充以块的形式增加内存,sizeof(long)最后逐字节填充剩余空间。即使分配器足够聪明,可以调用一些aligned_memset,它仍然是一个通用循环。

一个值得注意的例外是,当您对非常大的内存块(一些 power_of_two 千字节)执行 malloc/calloc 时,可以直接从内核进行分配。由于操作系统内核出于安全原因通常会将它们放弃的所有内存归零,因此足够聪明的 calloc 可能会在没有额外归零的情况下将其返回。再说一次 - 如果你只是分配你知道很小的东西,你可能会更好地使用 malloc+memset 性能。

于 2014-08-16T21:46:10.063 回答
10

有两个区别。
首先,是论据的数量。malloc()接受一个参数(需要以字节为单位的内存),而calloc()需要两个参数。
其次,malloc()不初始化分配的内存,而calloc()将分配的内存初始化为零。

  • calloc()分配一个内存区域,长度将是其参数的乘积。calloc用零填充内存并返回指向第一个字节的指针。如果它未能找到足够的空间,它会返回一个NULL指针。

语法:ptr_var = calloc(no_of_blocks, size_of_each_block); ptr_var = calloc(n, s);

  • malloc()分配 REQUSTED SIZE 的单个内存块并返回指向第一个字节的指针。如果它未能找到请求的内存量,它会返回一个空指针。

语法:ptr_var = malloc(Size_in_bytes);malloc()函数有一个参数,即要分配的字节数,而该calloc()函数有两个参数,一个是元素数,另一个是要为每个元素分配的字节数。此外,calloc()将分配的空间初始化为零,而malloc()不会。

于 2012-09-14T09:58:04.030 回答
10

块数:
malloc()分配单个请求的内存
calloc()块,分配多个请求的内存块

初始化:
malloc() - 不清除和初始化分配的内存。
calloc()- 将分配的内存初始化为零。

速度:
malloc()快。
calloc()比 malloc() 慢。

参数和语法:
malloc()接受 1 个参数:

  1. 字节

    • 要分配的字节数

calloc()接受 2 个参数:

  1. 长度

    • 要分配的内存块数
  2. 字节

    • 在每个内存块上分配的字节数
void *malloc(size_t bytes);         
void *calloc(size_t length, size_t bytes);      

内存分配方式:
malloc函数从可用堆中分配所需“大小”的内存。
calloc函数分配的内存大小等于“num *size”。

名字含义:
名字的malloc意思是“内存分配”。
该名称的calloc意思是“连续分配”。

于 2019-06-22T10:26:27.670 回答
9

区别一:

malloc()通常分配内存块,它是初始化的内存段。

calloc()分配内存块并将所有内存块初始化为0。

区别二:

如果你考虑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 个内存块并将所有这些内存块初始化为零,

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

相似:

如果它们不是类型转换的,则默认情况下两者都malloc()calloc()返回 void* 。!

于 2015-01-12T07:52:58.747 回答
7

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

  1. 它将内存分配为给定大小的多个元素,并且
  2. 它初始化分配的内存,使所有位都为零。
于 2013-07-30T16:18:06.693 回答
7

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));

使用andcalloc()可以实现相同的功能: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()改用。

于 2018-06-19T12:29:24.233 回答
6

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

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 GB。

于 2015-08-29T22:12:45.033 回答
0

两者都malloc分配calloc内存,但calloc将所有位初始化为零,而malloc没有。

Calloc 可以说等同于 malloc + memsetwith 0(其中 memset 将指定的内存位设置为零)。

因此,如果不需要初始化为零,那么使用 malloc 可能会更快。

于 2020-07-31T07:00:33.270 回答