C 语言内存分配函数

1、ANSI C 中的内存空间分配函数

ANSI C 中有 3 个分配内存的函数:malloc,calloc,realloc。

函数原型:

#include <stdlib.h>

void *malloc(size_t size);
void free(void *ptr);
void *calloc(size_t nmemb, size_t size);
void *realloc(void *ptr, size_t size);

简要说明:
1.malloc 分配长度为 size 个字节的空间,返回指向该空间的空类型指针,空间中的初始内容不确定。
2.calloc 分配长度为 nmemb*size 字节的空间,返回指向空间的指针,空间中的的位都被初始化为 0。
3.realloc 改变 ptr 指向的内存块的大小,将其调整为 size 个字节。其中的内容,从开始到 min(old size, new size) 的位置都保持不变(可能通过拷贝实现)。如果容量被扩大,新增加的空间不会初始化。
注意:malloc,calloc,realloc函数返回一个void型指针 ,指向重新分配大小的内存。如果请求失败,则返回 NULL。
4.free 释放之前调用 calloc、malloc 或 realloc 所分配的内存空间。free的参数必须要么是NULL,要么是从malloc、relloc、calloc返回的值。

例如:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main()
{
   char *str = NULL;
 
   /* 最初的内存分配 */
   str = (char *) malloc(15);
   strcpy(str, "runoob");
   printf("String = %s,  Address = %s\n", str, str);
 
   /* 重新分配内存 */
   str = (char *) realloc(str, 25);
   strcat(str, ".com");
   printf("String = %s,  Address = %s\n", str, str);
 
   /* 释放已分配的内存 */
   free(str);
   str = NULL;	//free之后,需要将str置为NULL,否则就会成为野指针
   				//避免多次free,否则要么程序崩溃,要么出现重大隐患
 
   return(0);
}

为了避免free之后,内存指针被再次free或使用,可定义如下宏:

#ifndef SAFE_FREE
#define SAFE_FREE(x) do { if ((x) != NULL) { free((x)); (x) = NULL;} } while(0) ///< 安全释放动态分配的内存
#endif

1.2、细说realloc函数

realloc函数尝试重新调整之前调用 malloc 或 calloc 所分配的 ptr 所指向的内存块的大小。

参数

  • ptr – 指针指向一个要重新分配内存的内存块,该内存块之前是通过调用 malloc、calloc 或 realloc 进行分配内存的。如果为空指针,则会分配一个新的内存块,且函数返回一个指向它的指针。
  • size – 内存块的新的大小,以字节为单位。如果大小为 0,且 ptr 指向一个已存在的内存块,则 ptr 所指向的内存块会被释放,并返回一个空指针。

返回值
该函数返回一个指针 ,指向重新分配大小的内存。如果请求失败,则返回 NULL。

注意:realloc函数用于修改一个原先已经分配的内存块的大小,可以使一块内存的扩大或缩小。当起始空间的地址为空,即ptr = NULL,则同malloc。当ptr非空:若nuw_size < size,即缩小ptr所指向的内存空间,该内存块尾部的部分内存被拿掉,剩余部分内存的原先内容依然保留;若nuw_size > size,即扩大ptr所指向的内存空间,如果原先的内存尾部有足够的扩大空间,则直接在原先的内存块尾部新增内存,如果原先的内存尾部空间不足,或原先的内存块无法改变大小,realloc将重新分配另一块nuw_size大小的内存,并把原先那块内存的内容复制到新的内存块上。因此,使用realloc后就应该改用realloc返回的新指针。

2、内存分配方式

  1. 从静态存储区域分配.
    内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.例如全局变量、static变量.
  2. 在栈上创建
    在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放.栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限.
  3. 从堆上分配,亦称动态内存分配.
    程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放

3、stdlib.h与malloc.h的区别

使用动态内存分配函数时,实际上,许多编译系统实现时,往往增加了一些其他函数。ANSI标准建议在“stdlib.h”头文件中包含有相关的信息,但大多数C编译系统要求用“mallco.h”而不是“stdlib.h"。一般来说stdlib.h包含malloc.h。

4、alloca函数

除了上面 3 个最常见的函数外,还有一个 alloca 函数值得一提。它与 malloc 功能上几乎一致,不同之处在于其在栈上分配空间,而不是在堆上分配空间。正因为如此,分配的空间在函数调用结束后会自动释放。另一方面,在某些系统中栈在函数调用期间可能无法改变大小,这样的系统中不能提供对 alloca 的支持。同时我认为,如果栈帧的大小可改变的范围受到严格限制,alloca 函数在分配较大空间时很容易引起栈溢出异常。

#include <alloca.h> 

void *alloca(size_t size);

alloca 是它在 Linux 中的名字,在 windows 中应该叫 _alloca,而且包含在头文件中,可以参考 MSDN 中的说明。

优缺点和使用可参考:https://blog.youkuaiyun.com/suoluotree/article/details/5649670

5、glibc 中的 memalign 函数

除了 ANSI C 中规定的内存分配函数,glibc 额外提供了地址对齐的内存空间的分配函数。主要有这么几个:posix_memalign, aligned_alloc, valloc, memalign, pvalloc。

函数原型:

#include <stdlib.h>

int posix_memalign(void **memptr, size_t alignment, size_t size); 
void *aligned_alloc(size_t alignment, size_t size); 
void *valloc(size_t size);

#include <malloc.h> 

void *memalign(size_t alignment, size_t size); 
void *pvalloc(size_t size);

简要说明

  1. posix_memalign 分配 size 字节的内存空间,将 *memptr 指向分配的空间,并且空间的地址是 alignment 的倍数。alignment 必须是 2 的乘幂,同时也要是 sizeof(void *) 的倍数。
  2. aligned_alloc 分配 size 字节的空间,返回指向该空间的指针。除了地址是 alignment 的倍数这一限制和 alignment 必须是 2 的乘幂的限制外,size 也必须是 alignment 的倍数。
  3. valloc 分配 size 字节的空间,返回指向该空间的指针,空间的地址是页大小的倍数。该函数可能已经过时,不提倡使用。
  4. memalign 分配 size 字节的空间,返回指向该空间的指针,空间的地址是 alignment 的倍数,alignment 必须是 2 的乘幂。该函数可能已经过时,不提倡使用。
  5. pvalloc 与 valloc 相似,不过将分配的空间大小扩展为页大小的倍数。该函数可能已经过时,不提倡使用。

上述对齐分配函数都不会把分配的空间置 0 ,需手动初始化。

在GNU系统中,malloc或realloc返回的内存块地址都是8的倍数(如果是64位系统,则为16的倍数)。如果你需要更大的粒度,请使用memalign或valloc。

6、性能测试

为了观察不同内存分配函数的性能,我在 Linux 系统上测试了几个函数。测试的环境为 3.13.0-35 版本内核,编译器 gcc 4.8.2,glibc 为 libc-2.19.so

测试详情见:http://lanhin.blog.163.com/blog/static/65775599201522924320490/


参考资料:
http://lanhin.blog.163.com/blog/static/65775599201522924320490/
http://www.runoob.com/cprogramming/c-standard-library-stdlib-h.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值