区别是什么:

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

And:

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

什么时候使用calloc优于malloc或反之亦然?


当前回答

malloc和calloc都分配内存,但calloc将所有位初始化为0,而malloc则不这样做。

可以说,Calloc相当于malloc + memset + 0(其中memset将指定的内存位设置为0)。

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

其他回答

摘自Georg Hager的博客上的一篇文章,用calloc()进行有趣的基准测试

When allocating memory using calloc(), the amount of memory requested is not allocated right away. Instead, all pages that belong to the memory block are connected to a single page containing all zeroes by some MMU magic (links below). If such pages are only read (which was true for arrays b, c and d in the original version of the benchmark), the data is provided from the single zero page, which – of course – fits into cache. So much for memory-bound loop kernels. If a page gets written to (no matter how), a fault occurs, the “real” page is mapped and the zero page is copied to memory. This is called copy-on-write, a well-known optimization approach (that I even have taught multiple times in my C++ lectures). After that, the zero-read trick does not work any more for that page and this is why performance was so much lower after inserting the – supposedly redundant – init loop.

Calloc一般是malloc+memset为0

显式使用malloc+memset通常会稍微好一点,特别是当你在做以下事情时:

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

That is better because sizeof(Item) is know to the compiler at compile time and the compiler will in most cases replace it with the best possible instructions to zero memory. On the other hand if memset is happening in calloc, the parameter size of the allocation is not compiled in in the calloc code and real memset is often called, which would typically contain code to do byte-by-byte fill up until long boundary, than cycle to fill up memory in sizeof(long) chunks and finally byte-by-byte fill up of the remaining space. Even if the allocator is smart enough to call some aligned_memset it will still be a generic loop.

一个值得注意的例外是,当您对一个非常大的内存块(一些power__2kb)执行malloc/calloc时,在这种情况下,可以直接从内核进行分配。由于操作系统内核通常会出于安全原因将它们放弃的所有内存归零,足够聪明的calloc可能只返回内存,而不进行额外的归零。同样,如果你只是分配一些你知道很小的东西,那么在性能方面使用malloc+memset可能会更好。

还有一个没有提到的区别:大小限制

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。

一个不太为人所知的区别是,在具有乐观内存分配的操作系统(如Linux)中,由malloc返回的指针直到程序实际接触它时才得到实际内存的支持。

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

例如,请参阅这个SO问题以进一步讨论malloc的行为

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,前者可能导致少量分配和后续缓冲区溢出。在这种情况下,后者将自动失败,因为无法创建如此大的对象。

当然,您可能不得不注意不符合规范的实现,这些实现简单地忽略了溢出的可能性……如果在您的目标平台上存在这个问题,那么无论如何都必须对溢出进行手动测试。