当声明数组时,你必须用一个编译时常量指定数组的长度。但是,数组的长度常常在运行时才知道,这是由于它所需要的内存空间取决于输入数据。这时应该使用动态内存分配。
C函数库提供了两个函数,malloc和free,分别用于执行动态内存分配和释放,这些函数维护一个可用的内存池。**动态分配的内存没有以任何方式进行初始化。如果对这块内存进行初始化非常重要,要么手动对它进行初始化,要么使用calloc函数进行初始化。**两个函数的原型为:
void *malloc(size_t size);
void free(void *pointer);
malloc所分配的是一块连续的内存。如果操作系统无法向malloc提供更多的内存,malloc就返回一个NULL指针。因此,对每个从malloc返回的指针都进行检查,确保它并非NULL是非常重要的。
free的参数必须要么是NULL,要么是一个先前从malloc,calloc或realloc返回的值。向free传递一个NULL参数不会产生任何效果。
calloc和realloc是另外两个内存分配函数。两个函数的原型为:
void *calloc(size_t num_elements, size_t element_size);
void realloc(void *ptr, size_t new_size);
malloc和calloc之间的主要区别是后者在返回指向内存的指针之前把它初始化为0,这个初始化常常能带来方便。其另外一个较小的区别是它们请求内存数量的方式不同。
realloc函数用于修改一个原先已经分配的内存块的大小。使用这个函数,你可以使一块内存扩大或缩小。如果原先的内存块无法改变大小,realloc将分配另一块正确大小的内存,并把原先那块内存的内容复制到新的块上。因此,在使用realloc之后,你就不能再使用指向旧内存的指针,而是应该改用realloc所返回的新指针。
如果你的目标是获得存储25个整数的内存,则代码为:
int *pi;
pi = malloc(25 * sizeof(int));
if (pi == NULL)
{
printf("Out of memory!\n");
exit(1);
}
动态内存分配最常见的错误就是忘记检查所请求的内存是否成功分配。动态内存分配d额第二大错误来源是操作内存时超出了分配内存的边界。
一种很少引起错误的内存分配器的程序如下,其分为3个文件实现:
// alloc.h 定义一个不易发生错误的内存分配器
#include <stdlib.h>
#define malloc 不要直接调用malloc
#define MALLOC(num, type) (type*)alloc((num) * sizeof(type))
extern void *alloc(size_t size);
// alloc.c 不易发生错误的内存分配器的实现
#include <stdio.h>
#include "alloc.h"
#undef malloc
void *alloc(size_t size)
{
void *new_mem;
// 请求所需的内存 并检查是否分配成功
new_mem = malloc(size);
if (new_mem == NULL)
{
printf("Out of memory!\n");
exit(1);
}
return new_mem;
}
// a_client.c 一个使用很少引起错误的内存分配器的程序
#include "alloc.h"
void function()
{
int *new_memory;
new_memory = MALLOC(25, int);
// ...
}
**释放一块内存的一部分是不允许的,动态分配的内存必须整块一起释放。**不要访问已经被free函数释放了的内存。这种情况多发生在对动态分配的内存的指针进行复制的情况中。