函数定义及原理
函数定义
extern void *malloc(unsigned int num_bytes);//函数原型
#include<stdlib.h>//头文件
void *malloc(size_t size);//函数声明
原理
malloc函数接收一个参数:所需的内存字节数。malloc会根据这个参数找到合适的空闲内存块,然后返回动态内存块的首字节地址。这个内存块是匿名的,malloc函数并不会为其赋名。因此我们需要将该地址赋值给一个指针变量,然后通过指针变量来访问这块内存。
如果内存分配成功,malloc函数会返回一个(void*)类型的指针,在C、C++中规定该指针可以被强制转换成任何类型的指针,因此malloc()函数可以用于返回指向数组的指针、指向结构的指针等而不用考虑类型匹配的问题。
如果内存分配失败,则会返回空指针(NULL)。利用这个特性,我们必须在每次使用malloc函数后检查内存是否分配成功。
使用malloc函数创建动态数组
double * ptd;
ptd = (double*)malloc(30 * sizeof(double));
这段代码中,malloc函数为30个double类型的值请求内存空间,然后使用强制类型转换将返回的指针转换成(double*)类型,然后赋值给ptd,即设置ptd指向所分配内存块的首元素。回忆数组的定义,数组名即为数组首元素的地址。我们将ptd指向内存块的首元素,便可以像使用数组名一样使用它。即用ptd[0]访问内存块的首元素,用ptd[1]访问内存块的第二个元素······
利用这个方法可以创建动态数组
double ptd[n];
通常我们执行程序时程序会报错(C99后可以使用),因此我们可以使用以下方法来创建动态数组:
double *ptd = ptd = (double*)malloc( n * sizeof(double));
free函数
内存泄漏
在C语言中,通常把变量分为静态存储变量和动态存储变量两类。静态存储变量是指在程序运行期间分配了固定存储空间的变量;动态存储变量是指在程序运行期间根据实际需要进行动态地分配存储空间的变量。在内存中供用户使用的内存空间分为三部分:
- 程序存储区
- 静态存储区
- 动态存储区
程序中使用的数据分别存放在静态存储区和动态存储区中,静态存储区数据在程序的开始就分配好内存区。也就是说静态内存的数量在编译时时固定的,在程序运行期间也不会改变,在程序结束时自动释放。但是动态内存的数量只会增加,除非使用free进行释放。我们来看一段程序:
...
int main()
{
double glad[2000];
int i;
...
for(int i=0;i<1000;i++)
gobble(glad,2000);
...
}
void gobble(double ar[],int n)
{
double * temp =(double*)malloc(n*sizeof(double));
}
在第一次调用gobble函数时,它创建了一个指针temp,并为其分配了8*2000=16000字节的内存,在函数结束时,作为自动变量的指针temp会消失,但是系统并不会为我们自动释放这16000字节的内存。因此这块内存区域依旧存在,但由于temp指针已经消失,因此无法访问这块内存空间,同时它也无法被重复使用。
主函数多次调用了gobble函数,当for循环执行结束,程序总共调用了1000次gobble函数,也就造成了16000000字节的内存被占用而无法使用,通常我们称这类问题为内存泄漏。为了避免这类问题,我们需要在函数末尾使用free函数来释放内存以避免这类问题的发生。
使用方法
free函数的参数是一个指针,即之前malloc函数返回的地址。使用时将其放在函数的末尾。例如上述代码添加free函数:
void gobble(double ar[],int n)
{
double * temp =(double*)malloc(n*sizeof(double));
free(temp);
}
free函数使用的指针变量可以与malloc函数的指针变量不同,但是两个指针变量必须储存相同的地址。另外,如果被调函数使用malloc函数分配内存空间并返回指针供主调函数使用,则可以在主调函数末尾使用free函数通过该指针释放被调函数创建的内存空间,也就是说内存块可以在一个函数中创建,在另一个函数中销毁。需要注意的是,不能释放同一内存块两次。
其他相关函数的使用
calloc函数
calloc函数功能与malloc函数类似,其典型用法如下:
double * temp = (double *)calloc(1000,sizeof(double))
calloc函数的参数是两个无符号整数,第一个参数是所需的存储单元数量,第二个参数是每个存储单元的大小。calloc函数有个特性,即在动态分配完内存后,自动初始化该内存空间为零,而malloc不初始化,里边数据是随机的垃圾数据。这是calloc与malloc最主要的区别。free函数也可以用于释放calloc分配的内存空间。
realloc函数
当我们动态分配的内存不够了或者过大,我们可以使用realloc函数来调整内存的大小。其基本语法为:
指
针
名
=
(
数
据
类
型
∗
)
r
e
a
l
l
o
c
(
要
改
变
内
存
大
小
的
指
针
名
,
新
的
大
小
)
指针名=(数据类型*)realloc(要改变内存大小的指针名,新的大小)
指针名=(数据类型∗)realloc(要改变内存大小的指针名,新的大小)
如果新的大小小于原内存大小,可能会导致数据的丢失;如果新的内存大小大于原内存大小,新分配的部分不会被初始化。
其原理时先判断当前指针是否有足够的连续内存空间,如果有则扩大当前地址,返回当前的指针;如果没有,则根据指定的内存大小重新寻找并分配内存空间,然后将原有数据全部拷贝至新的内存块,并自动释放原来的内存,然后返回新的内存块的首地址。
如果重新分配成功则返回指向被分配内存的指针,分配失败则返回空指针(NULL)。在函数结束时同样要使用free函数来释放内存空间。
参考资料
- 百度百科"realloc"
- 百度百科"malloc"
- 《C Primer Plus》(第6版)中文版