malloc
malloc函数包含在头文件#include<stdlib.h>中,这个函数在编写代码过程中是经常用到的常与结构体一起用。我们知道malloc参数的单位为字节,并且他的返回值为void*,如果它申请内存失败,则会返回NULL。
当我们不知道某个变量需要多大的内存时,就可以使用malloc函数。
我们看下列代码
int *a=(int*)malloc(sizeof(int));//int*是将void*强制转换
*a = 6;
printf("%d\n",*a);
free(a);
打印结果我们都知道是6,但这个int型是通过申请动态内存而来的
值得注意的是,malloc函数所申请的内存,必须要通过free函数来释放掉,否则极容易出现内存泄露问题
realloc
这个函数,估计大家没见过几次。它的作用是把一曾经已经申请到的内存进行扩容。
语法:指针名=(数据类型*)realloc(要改变内存大小的指针名,新的大小)。值得注意的是,新的大小要大于原来的内存大小,否则可能会出现数据丢失的情况,我们看个简单的代码
int *a=(int*)malloc(sizeof(int));
a = (int*)realloc(a,sizeof(int)*4);
free(a);
这里原先a的大小为4个字节,使用realloc函数后就把a的大小扩容成了16字节。
calloc
这个函数与malloc函数基本上没有区别,值得注意的是他的格式为:
int* ptr = (int *)calloc(10,sizeof(int));其中,calloc(10,sizeof(int))相当于malloc(sizeof(int )*10)
int *a=(int*)malloc(sizeof(int));
int* b = (int*)calloc(10,sizeof(int));
free(a);
free(b);
上述代码中a,b的内存是一样大的,还有一点就是calloc申请到的内存空间被初始化为全0
上述三种申请的内存在 堆 这个内存上
如果一块大的内存空间,也需要频繁申请释放,使用内存池,先从堆上申请一大块内存,虽然现在可能只使用一小块,未来需要使用其他内存的时候,就可以直接从池中使用,避免向系统进行申请。
除此之外我们看一下下面这个代码
int a = 0;
int* b = &a;
free(b);
我们释放了一个没有通过动态内存申请的空间,这是错误的,相当于一个未定义行为。要知道free只能释放通过动态内存申请的内存。
int *a=(int*)malloc(sizeof(int));
free(a);
free(a);
申请的内存两次释放,这也是未定义行为,第二次的释放也相当于释放一个不是通过动态内存所申请的内存。有些人可能会觉得不会写两次释放,但是当你的代码量非常大的时候,通过动态内存申请的地方非常多,如果不小心释放了两次,则会对程序造成很大的错误,所以一定要避免这样的操作
柔性数组
这个知识点,大家可以了解了解
我们知道,一个数组的大小必须是要知道的,但是柔性数组可以不需要。首先要知道柔性数组必须要在结构体中才能使用,其次柔性数组成员前面必须有一个其他类型成员,最后必须是结构体最后一个成员
我们看如下代码
struct stu{
int a;
char b;
int num[];
}stu;
这样是正确的,相当于num就是一个长度可以动态变化的结构体成员,但是不能写成如下形式
struct stu{
int a;
char b;
int num[];
int c;
}stu;
引入柔性数组可以更好的对内存进行释放并且对其的访问速度有一定的提升,还可以防止内存碎片的发生