为什么需要动态内存?
2 动态内存分配函数
在C语言中, 有几个内存分配函数可以用来管理动态内存,虽然具体可用的函数取决于系统,但是大部分系统的stdlib.h文件中都有如下函数:
malloc //从堆上分配内存 realloc //在之前分配的内存块的基础上,将内存重新分配为更大或是更小的部分 calloc //从堆上分配内存并清零分配的内存 free //释放分配的内存
在C语言中动态内存分配的基本步骤:
1. 使用malloc函数分配内存
2. 使用这些内存
3. 使用函数free释放内存 -- 每次调用malloc或是类似函数(calloc,realloc),程序结束时必须有对应的free函数调用,以免造成内存泄漏
在c++中,有类似功能的是new和delete,new和delete在后续讨论。
malloc函数的声明:
void *malloc(size_t size);
free函数的声明:
void free(void *ptr);
如果我们想在一块内存上分配20字节大小的内存,可以这样写:
malloc(20);
因为malloc函数的返回值是一个 void * 类型的指针,所以,我们需要根据实际的需要将其显示的转换成我们所需要的数据类型,如整型,如字符型,
那么我们就可以这样写(因为void *可以赋给任意类型,所以一般没有必要显示转换,不过显示转换是个好习惯):
(int *)malloc(20); (char *)malloc(20);
malloc函数返回的是指向分配的这块内存的地址,因此,我们可以把这个地址赋值给一个指针变量,例如:
int *ptr = (int *)malloc(4);
但是如果我们不幸写成了如下的代码:
int *ptr; *ptr = (int *)malloc(4);
这样编译器就会报错,因为我们把一个指针赋值给了一个int类型的变量。
举例来说:
例1:不规范的初始版本
int i; int *pi = (int *)malloc(5*sizeof(int)); for (i=0; i<5; i++) { pi[i] = i*i; printf("pi[%d] = %d, &pi[%d] = %p\n", i, pi[i], i, &pi[i]); } free(pi);
这段代码在作者的机器上的输出是:
那么,要如何来使用malloc函数呢?
以下面这段代码为例说明:
void *malloc(size_t size);
int *ptr = (int *)malloc(sizeof(int));
在执行malloc函数时,会进行如下的操作:
1. 从堆上分配内存
2. 这段内存中原有的数据不会被清空或是修改 -- 这表示这段内存中存在垃圾数据
3. 返回分配的这段内存的首字节的地址
因此,我们在使用malloc函数时,就可能会遇到如下问题:
1. 堆上的内存空间不足(传入的参数过大,超过了堆得内存空间),那么malloc函数会返回NULL --- 因此在使用malloc函数时,对返回值进行检查是必不可少的操作
2. 传入的参数是负数,在某些系统中,它会返回NULL
3. 传入的参数是0,那么malloc可能会返回NULL, 也看会返回一个指向分配了0字节区域的指针