malloc和calloc之间的区别?

做的有什么区别:

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

要么:

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

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


#1楼

有两点不同。
首先,是参数的数量。 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()则不会。


#2楼

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

编辑:

将内存清零可能需要一些时间,因此如果性能问题,您可能希望使用malloc() 。 如果初始化内存更重要,请使用calloc() 。 例如, calloc()可能会保存对memset()的调用。


#3楼

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

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

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


#4楼

分配的内存块大小没有区别。 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版本不会尝试监视溢出。 如果发生溢出,它将分配一些“不可预测的”内存量。


#5楼

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

  1. 它将内存分配给给定大小的多个元素,并且
  2. 它初始化分配的内存,以便所有位都为零。

#6楼

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

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

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


#7楼

来自一篇文章使用calloc()和 Georg Hager博客的 零页面进行基准测试

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


#8楼

calloc一般是malloc+memset为0

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

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

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

一个值得注意的例外是当你正在做一个非常大的内存块(一些power_of_two千字节)的malloc / calloc时,在这种情况下,可以直接从内核完成分配。 由于操作系统内核通常会将出于安全原因而放弃的所有内存归零,因此足够聪明的calloc可能会将其返回并附加归零。 再说一遍 - 如果你只是分配你知道的东西很小,那么你可能会更好地使用malloc + memset。


#9楼

差异1:

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

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

差异2:

如果考虑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块内存并将所有内容初始化为ZERO,

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

相似:

如果malloc()calloc()没有类型化,它们将默认返回void *。


#10楼

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

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


#11楼

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

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


#12楼

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

使用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()


#13楼

没有块:
malloc()分配单个需求内存块,
calloc()分配所请求内存的多个块

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

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

西尔文特克斯:

void *malloc(size_t size);                   // syntex for malloc() function
void *calloc(size_t num, size_t size);       // syntex for calloc() function

参数:
如果考虑malloc()语法,则只需要1个参数。
如果考虑calloc()语法,则需要2个参数。

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

名称含义:
名称malloc意味着归因于内存分配。
calloc这个名字意味着连续分配。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值