malloc,calloc,realloc函数用法,原理及不同解析

https://blog.csdn.net/lixungogogo/article/details/50887028

 

一、malloc 
malloc在MSDN中原型为: 
void *malloc( size_t size ); 
介绍为: 
malloc returns a void pointer to the allocated space, or NULL if there is insufficient memory available. To return a pointer to a type other than void, use a type cast on the return value. The storage space pointed to by the return value is guaranteed to be suitably aligned for storage of any type of object. If size is 0, malloc allocates a zero-length item in the heap and returns a valid pointer to that item. Always check the return from malloc, even if the amount of memory requested is small.

大概意思为: 
malloc返回一个指针,如果没有成功分配内存或内存不够大导致分配失败,会返回NULL指针。否则返回分配内容的首地址。

在这里我要注意的是:如果给malloc中size写入0,会给变量写入0字节的大小。 
这里就有歧义了。 
如果我给程序写入这样一行代码:

int * p;
p = (int *)malloc(0);
  • 1
  • 2

p的值是不是NULL呢? 
经VS2013检验,不是NULL,这是为什么呢? 
在MSDN中有这么一段话: 
The malloc function allocates a memory block of at least size bytes. The block may be larger than size bytes because of space required for alignment and maintenance information.

意思是,malloc生成的空间大小是要比你写入的空间大小要大的。 
解释如下: 
首先: 
在标准的malloc实现中,并不检查输入值的大小,而是将输入值做对齐操作后直接从堆上分配空间。 
其次: 
不论输入值的大小为多少,在malloc的内部最小的内存分配大小是一个定值(一般是8B),因为malloc需要用这部分空间来维护堆上的内存块链表。所以当用户申请一块0B的空间时,malloc实际分配的空间是8B,如果用户申请的空间是X,则malloc实际分配的空间是(对齐(X) + 8)。这也是为什么malloc分配的空间千万不能越界使用的原因:堆的内部链表结构将被破坏。 
实际上,在内存中是这样的:

那么,free是怎么知道要释放多少内存的呢?
看图~
malloc自动记录了此次分配的内存大小。
  • 1
  • 2
  • 3
  • 4

二、calloc 
那calloc是用来干嘛的呢? 
calloc在MSDN中描述如下: 
calloc 
Allocates an array in memory with elements initialized to 0.

void *calloc( size_t num, size_t size );

Routine Required Header Compatibility 
calloc

int *p = (int*)calloc(0,2*sizeof(int)); //相当于 int *p=(int *)malloc(2*sizeof(int)); memset(p,0,2*sizeof(int));
  • 1
  • 2
  • 3
  • 4

那为什么日常中我们看到用malloc的多于calloc呢,是因为calloc虽然对内存空间进行了初始化,但是同时也降低了程序的效率。 
而在一些情况下是不需要对内存空间进行初始化的~

三、realloc 
ANSI C说明了三个用于存储空间动态分配的函数 
(1) malloc 分配指定字节数的存储区。此存储区中的初始值不确定 
(2) calloc 为指定长度的对象,分配能容纳其指定个数的存储空间。该空间中的每一位(bit)都初始化为0 
(3) realloc 更改以前分配区的长度(增加或减少)。当增加长度时,可能需将以前分配区的内容移到另一个足够大的区域,而新增区域内的初始值则不确定 
这是以上三个函数的区别

realloc分配失败时,返回NULL
realloc分配失败时,原来的内存空间不改变,不释放也不会移动
如果size=0,realloc = free,只对指针指向内存进行释放
对于二级指针来说,realloc(**p,0),只会释放一维指针,不会释放内存,所以要注意内存泄露
传递给realloc的指针必须是经过malloc,calloc,realloc申请的
当ptr为NULL,realloc(ptr,10) = malloc(ptr,10)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

realloc使我们可以增、减以前分配区的长度(最常见的用法是增加该区)。 
PS:在动态顺序表中就是用的realloc进行增容

如果先分配一个可容纳长度为512的数组的空间,并在运行时填充它,但又发现空间不够,则可调用realloc扩充该存储空间。

1.如果在该存储区后有足够的空间可供扩充,则可在原存储区位置上向高地址方向扩充,并返回传送给它的同样的指针值。

2.如果在原存储区后没有足够的空间,则realloc分配另一个足够大的存储区,将现存的5 1 2个元素数组的内容复制到新分配的存储区。

因为这种存储区可能会移动位置,所以不应当使用任何指针指在该区中。

注意, 
realloc的最后一个参数是存储区的newsize(新长度),不是新、旧长度之差。 
作为一个特例,若ptr是一个空指针,则realloc的功能与malloc相同,用于分配一个指定长度newsize的存储区。

四、alloca 
alloca函数 
还有一个函数也值得一提,这就是alloca。其调用序列与malloc相同,但是它是在当前函数的栈帧上分配存储空间,而不是在堆中。 
其优点是:当 函数返回时,自动释放它所使用的栈帧,所以不必再为释放空间而费心。其缺点是:某些系统在函数已被调用后不能增加栈帧长度,于是也就不能支持alloca 函数。尽管如此,很多软件包还是使用alloca函数,也有很多系统支持它。 
_alloca 
Allocates memory on the stack.

void *_alloca( size_t size );

Routine Required Header Compatibility 
_alloca

 

=======================================================

 

https://blog.csdn.net/u014170207/article/details/53126340

 

对于这个说烂的问题 ,做一点感悟笔记。三者都是分配内存,都是stdlib.h库里的函数,但是也存在一些细微的差异。

 

首先,对于malloc函数。其原型void *malloc(unsigned int num_bytes)

num_byte为要申请的空间大小,需要我们手动的去计算,如int *p = (int *)malloc(20*sizeof(int)),如果编译器默认int为4字节存储的话,那么计算结果是80Byte,一次申请一

个80Byte的连续空间,并将空间基地址强制转换为int类型,赋值给指针p,此时申请的内存值是不确定的。

 

而对于calloc函数,其原型void *calloc(size_t n, size_t size);

从直观的看,其比malloc函数多一个参数,并不需要人为的计算空间的大小,比如如果他要申请20个int类型空间,会int *p = (int *)calloc(20, sizeof(int)),这样就省去了人为空

间计算的麻烦。但这并不是他们之间最重要的区别,malloc申请后空间的值是随机的,并没有进行初始化,而calloc却在申请后,对空间逐一进行初始化,并设置值为0;

如下

 

[cpp]  view plain  copy
 
  1. int *p = (int *)malloc(20*sizeof(int));  
  2. int *pp = (int *)calloc(20, sizeof(int));  
  3. int i;  
  4.   
  5. printf("malloc申请的空间值:\n\n");  
  6. for ( i=0 ; i < 20; i++)  
  7. {  
  8.     printf("%d ", *p++);  
  9. }  
  10. printf("\n\n");  
  11. printf("calloc申请的空间的值:\n\n");  
  12. for ( i=0 ; i < 20; i++)  
  13. {  
  14.     printf("%d ", *pp++);  
  15. }  
  16. printf("\n");  



 

 

结果为

很多人会疑问:既然calloc不需要计算空间并且可以直接初始化内存避免错误,那为什么不直接使用calloc函数,那要malloc要什么用呢?

实际上,任何事物都有两面性,有好的一面,必然存在不好的地方。这就是效率。calloc函数由于给每一个空间都要初始化值,那必然效率较malloc要低,并且现实世界,很多情况的空间申请是不需要初始值的,这也就是为什么许多初学者更多的接触malloc函数的原因。

说完了malloc和calloc,接下来谈realloc函数。

realloc函数和上面两个有本质的区别,

其原型void realloc(void *ptr, size_t new_Size) 用于对动态内存进行扩容(及已申请的动态空间不够使用,需要进行空间扩容操作)

ptr为指向原来空间基址的指针, new_size为接下来需要扩充容量的大小

 

 

[cpp]  view plain  copy
 
  1. int main(void)  
  2. {  
  3.     const int size = 2000;  
  4.     int *p = (int *)malloc(20*sizeof(int));  
  5.     int *pp = (int *)realloc(p, size*sizeof(int));  
  6.       
  7.     printf("原来的p_Address:%x   扩容后的pp_Address:%x \n\n", p, pp);  
  8.       
  9.     return 0;  
  10. }  



 

 

结果为:

可从图看出,扩容后地址和原先地址是不一样的,但是这仅仅取决于扩容的内存大小。

实际上:

        如果size较小,原来申请的动态内存后面还有空余内存,系统将直接在原内存空间后面扩容,并返回原动态空间基地址;

        如果size较大,原来申请的空间后面没有足够大的空间扩容,系统将重新申请一块(20+size)*sizeof(int)的内存,并把原来空间的内容拷贝过去,原来空间free;

        如果size非常大,系统内存申请失败,返回NULL,原来的内存不会释放。

注意:如果扩容后的内存空间较原空间小,将会出现数据丢失,如果直接realloc(p, 0);相当于free(p)

 

=======================================================

三个函数的申明分别是: 
void* realloc(void* ptr, unsigned newsize); 
void* malloc(unsigned size); 
void* calloc(size_t numElements, size_t sizeOfElement); 
都在stdlib.h函数库内

它们的返回值都是请求系统分配的地址,如果请求失败就返回NULL 

malloc用于申请一段新的地址,参数size为需要内存空间的长度,如: 
char* p; 
p=(char*)malloc(20);

calloc与malloc相似,参数sizeOfElement为申请地址的单位元素长度,numElements为元素个数,如: 
char* p; 
p=(char*)calloc(20,sizeof(char)); 
这个例子与上一个效果相同

realloc是给一个已经分配了地址的指针重新分配空间,参数ptr为原有的空间地址,newsize是重新申请的地址长度 
如: 
char* p; 
p=(char*)malloc(sizeof(char)*20); 
p=(char*)realloc(p,sizeof(char)*40);

注意,这里的空间长度都是以字节为单位。 


C语言的标准内存分配函数:malloc,calloc,realloc,free等。 
malloc与calloc的区别为1块与n块的区别: 
malloc调用形式为(类型*)malloc(size):在内存的动态存储区中分配一块长度为“size”字节的连续区域,返回该区域的首地址。 
calloc调用形式为(类型*)calloc(n,size):在内存的动态存储区中分配n块长度为“size”字节的连续区域,返回首地址。 
realloc调用形式为(类型*)realloc(*ptr,size):将ptr内存大小增大到size。 


free的调用形式为free(void*ptr):释放ptr所指向的一块内存空间。 
C++中为new/delete函数。

 
 
1,int *p1=(int*)malloc(0) //ok,p1!=NULL

2,int *p2=(int*)realloc(p1,newsize*sizeof(int));
//newsize很小且realloc操作成功时,p2==p1
//newsize较大且realloc操作成功时,p2!=p1 && p2!=NULL
//newsize很大,realloc操作失败时,p2==NULL

3,int *p3=(int*)realloc(NULL,10*sizeof(int));//ok,p3!=NULL

转载于:https://www.cnblogs.com/kungfupanda/p/9006049.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值