malloc和calloc有什么不同?

942

做以下两种操作有何区别:

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

并且:

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

何时使用callocmalloc更好,反之亦然?


48
在C语言中,你不需要给malloc系列函数的返回值进行类型转换。 - phuclv
9
在C语言中,你可以更加通用地写作:ptr = calloc(MAXELEMS, sizeof(*ptr));。其中,calloc用于动态分配内存,MAXELEMS表示需要分配的元素个数,sizeof(*ptr)表示每个元素所占内存的大小,ptr表示指向分配内存的指针。 - chqrlie
8
一篇有趣的帖子,讲述了calloc和malloc+memset之间的区别。https://vorpus.org/blog/why-does-calloc-exist/ - ddddavidee
2
@ddddavidee 我也是在对网络上那么多答案不满意之后才发现了那篇博客。Nathaniel J. Smith 对于他的分析应该获得100多个 Stack Overflow 积分。 - lifebalance
14个回答

7

malloc()calloc()是C标准库中的函数,允许动态内存分配,这意味着它们都允许在运行时进行内存分配。

它们的原型如下:

void *malloc( size_t n);
void *calloc( size_t n, size_t t)

这两者主要有两个不同之处:

  • 行为(Behavior):malloc() 分配一个内存块,但不初始化它,从该块读取内容将导致垃圾值。另一方面,calloc() 分配一个内存块并将其初始化为零,显然读取该块的内容将导致零。

  • 语法(Syntax):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));

使用 malloc()memset() 可以实现与 calloc() 相同的功能:
// 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()

7

calloc()函数在<stdlib.h>头文件中声明,相较于malloc()函数它有以下几个优点:

  1. 它以给定大小的元素数量来分配内存。
  2. 它初始化所分配的内存,使得所有位都是零。

6

一个还未提到的区别是:大小限制

void *malloc(size_t size) 只能分配最多 SIZE_MAX 大小的内存。

void *calloc(size_t nmemb, size_t size); 可以分配最多 SIZE_MAX*SIZE_MAX 大小的内存。

许多具有线性寻址的平台很少使用这种能力。这些系统通过 nmemb * size <= SIZE_MAX 来限制 calloc() 的使用。

考虑一种名为 disk_sector 的 512 字节类型,代码想要使用 大量 扇区。在这里,代码只能使用最多 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内存池。


2
通常,size_t 将能够保存程序可能处理的最大类型对象的大小。一个 size_t 为 32 位的系统不可能处理大于 4294967295 字节的分配,而能够处理这个大小的系统几乎肯定会使 size_t 大于 32 位。唯一的问题是,使用 calloc 并且乘积超过 SIZE_MAX 的值是否可靠地产生零,而不是返回指向较小分配的指针。 - supercat
1
C标准使得代码可以请求一个大小超过SIZE_MAX的分配。它当然不要求在任何情况下都必须成功分配这样的内存;我不确定强制要求不能处理这种分配的实现必须返回NULL是否有任何特定的好处(特别是考虑到一些实现通常会让malloc返回指向尚未提交的空间的指针,而当代码实际尝试使用它时可能无法使用)。 - supercat
@supercat "现实可能性不大,因为那将需要数十亿吉字节的存储容量" --> 超过4G的内存已经足够考虑使用返回指向SIZE_MAX (4G-1)以外内存指针的calloc()函数的架构。 - chux - Reinstate Monica
2
一个可以容纳超过4G的单个分配的实现,为什么不将size_t定义为uint64_t - supercat
让我们在聊天中继续这个讨论:http://chat.stackoverflow.com/rooms/120981/discussion-between-chux-and-supercat。 - chux - Reinstate Monica
显示剩余3条评论

0

malloccalloc 都用于分配内存,但是 calloc 会初始化所有位为零,而malloc 不会。

可以说 calloc 相当于使用 memset 设置为0 的 malloc(其中 memset 将指定的内存位设置为零)。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接