malloc
作用区域 :堆区
对于申请后的内存的初始值:0xcdcdcdcd
函数返回值:
内存管理方式
使用场合
realloc
作用区域:堆区
函数原型:void *realloc( void *memblock, size_t size );
(1)返回的是一个void类型的指针:调用成功。(这就要求在你需要的时候进行强制类型转换)
(2)返回NULL:当需要扩展的大小(第二个参数)为0并且第一个参数不为NULL时。此时原内存变成“free(游离)”的了。
(3)返回NULL:当没有足够的空间可供扩展的时候。此时,原内存空间的大小维持不变。
内存管理方式:
"如果有足够空间用于扩大mem_address指向的内存块,则分配额外内存,并返回mem_address。这里说的是“扩大”,我们知道,
头文件:#include<stdlib.h> #include<malloc.h>
使用场合:调整已经申请的内存空间大小。当需要在内存的动态存储区中分配n个长度为size_t size字节的连续空间时。如果分配成功,函数返回一个指向分配起始地址的指针;如果分配不成功,返回NULL
calloc
作用区域:堆区
函数原型:void *calloc(size_t n, size_t size);
初始值:0
函数返回值:
在内存的动态存储区中分配n个长度为size的连续空间,函数返回一个指向分配起始地址的指针;如果分配不成功,返回NULL。。如果内存分配失败,或者请求的内存数量超过 _HEAP_MAXREQ,那么 calloc 设置 errno 为 ENOMEM 。
内存管理方式:
在malloc基础上,初始化了被申请的内存区域
使用场合:
动态分配内存。:当需要在已经被(malloc(), calloc(), 或realloc())分配的空间的基础上重新分配空间时。参数mem_address为原有的空间地址,newsize是重新申请的地址空间。(1)传递给realloc的指针必须是先前通过malloc(), calloc(), 或realloc()分配的。(2)如果realloc需要的内存小于原来的内存大小,会导致数据丢失;如果原来的内存后面还有足够多剩余内存的话,realloc的内存=原来的内存+剩余内存,realloc还是返回原来内存的地址; 如果原来的内存后面没有足够多剩余内存的话,realloc将申请新的内存,然后把原来的内存数据拷贝到新内存里,原来的内存将被free掉,realloc返回新内存的地址。(3)如果没有足够可用的内存用来完成重新分配(扩大原来的内存块或者分配新的内存块),则返回NULL。而原来的内存块保持不变。(4)如果newsize大小为0,那么释放mem_address指向的内存,并返回NULL(5)如果mem_address为NULL,则realloc()和malloc()类似。分配一个newsize的内存块,返回一个指向该内存块的指针
三者的释放方式:
void free(void *ptr);(与malloc()函数配对使用,释放malloc函数申请的动态内存。(另:对于free(p)这句语句,如果p 是NULL 指针,那么free 对p 无论操作多少次都不会出问题。如果p 不是NULL 指针,那么free 对p连续操作两次就会导致程序运行错误。))。如果对一个不是上面三个函数申请的内存free,结果是未定义的。
三者的最大分配:
如果内存分配失败,或者请求的内存数量超过 _HEAP_MAXREQ,那么 malloc 设置 errno 为 ENOMEM
补充:brk和mmap
在Linux中,对于heap区的操作提供的是brk()系统调用,C运行库又提供了sbrk()库函数。而对于与mmap区则提供的是mmap()和munmap()函数。在C中的malloc函数的底层主要就是使用了brk()和mmap()系统调用,它们的区别也从上面可以看出来,在<128K内存申请的时候,linux内核调用的是brk(),而>=128K的时候则是调用了mmap(). 两者申请的都是虚拟内存,并不是物理内存,只有当真正要访问的时候该内存的时候,就会产生缺页中断,然后陷入内核,操作系统根据资源情况分配物理内存,然后建立虚拟地址到物理地址的映射关系(写时)(《程序员的自我修养》 && https://blog.csdn.net/gamebot/article/details/79368323)。简略来说,申请大于128k的内存时,brk向上移动到申请的内存的地方。大于时,调用mmap映射内存,在mmap区(也就是heap堆和栈之间的一块区域区分配虚拟内存)申请了一块200K的内存。
参考资料:《程序员的自我修养》,《深入理解计算机系统·》