home

Love life, love sports, love to learn, & love...

Blog

Thought,  done  &  record.

订阅到QQ邮箱 google reader google reader

C 语言动态内存分配

基本信息

所谓动态内存分配就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不像数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。

详细释义

例如我们定义一个 float 型数组:

float score[100]; 

但是,在使用数组的时候,总有一个问题困扰着我们:数组应该有多大?在很多的情况下,你并不能确定要使用多大的数组,比如上例,你可能并不知道我们要定义的这个数组到底有多大,那么你就要把数组定义得足够大。这样,你的程序在运行时就申请了固定大小的你认为足够大的内存空间。即使你知道你想利用的空间大小,但是如果因为某种特殊原因空间利用的大小有增加或者减少,你又必须重新去修改程序,扩大数组的存储范围。这种分配固定大小的内存分配方法称之为静态内存分配。但是这种内存分配的方法存在比较严重的缺陷,特别是处理某些问题时:在大多数情况下会浪费大量的内存空间,在少数情况下,当你定义的数组不够大时,可能引起下标越界错误,甚至导致严重后果。

我们用动态内存分配就可以解决上面的问题. 所谓动态内存分配就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不象数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。

从以上动、静态内存分配比较可以知道动态内存分配相对于静态内存分配的特点:

  • 不需要预先分配存储空间;
  • 分配的空间可以根据程序的需要扩大或缩小。

要实现根据程序的需要动态分配存储空间,就涉及到 4 个函数,即 malloc()、calloc()、realloc()、free(),其原型分别为

void *malloc (unsigned int size);
void *calloc (unsigned n, unsigned size);
void *realloc (void *p, unsigned size);
void free (void *p); 

malloc()、calloc() 及 realloc() 函数都是内存分配函数,其相同点是都返回所分配的连续存储区的起始地址,如果可供分配的内存不够则返回 NULL,不同之处在于 malloc() 函数分配足够的内存来存储长度(用 sizeof 运算符计算)为 size 的数据对象,即分配 size 字节的存储区;calloc() 函数分配 n 个数据项的存储区,每个数据项的大小(用 sizeof 运算符计算)为 size 字节,并将该存储区的每个字节都初始化为 0;realloc() 函数在保留 p 所指向的已分配存储区的内容的同时改变其长度为 size,如果需要把内容复制到新的存储区,若 size 比原来分配的空间小则放弃旧区域末尾的一些内容,若 size 比旧长度大则所有旧内容保留并在末尾增加新的空间。如果 realloc() 函数返回的指针不同于 p,则说明重新分配了内存,要假设旧内存已释放不能再用。必须注意的是,当内存分配函数未能成功分配存储空间(如内存不足)时就会返回一个 NULL 指针,所以在调用该函数时应该检测返回值是否为 NULL 并执行相应的操作。

ANSI 标准中动态内存分配函数的返回值是 void *,其具有通用性,可指向任意类型的数据对象,在赋值时可进行隐式转换。但是在传统的 C 语言中,这些动态内存分配函数的返回类型为 char *,隐式转换可能会产生警告等信息。因此为了保证安全并保证 C++ 兼容性,需要用强制类型转换的方法把 void * 或者 char * 转换成所需的类型。

例如,假设 T 是某个要动态分配的对象类型,可能是结构、数组或字符,则:

T * NewObject (void)
{
    T *objptr = (T *)malloc (sizeof(T));
    if (objptr == NULL) printf ("NewObject: failed!\n");
    return objptr;
}

free() 函数为内存释放函数,当动态分配的存储空间使用完毕后一定得释放,否则会造成内存泄漏。

回顶部