动态内存
用户无法确定空间大小,或者空间太大,栈上无法分配时,会采用动态内存分配,存放于堆(heap)区,不能通过变量名或数组名引用,只能通过指针引用.
1、在Windows操作系统中,堆中最大连续内存大概1.3G。
2、最大问题:内存泄漏(软件开发设计考虑的主要方面,每次泄露少量,久而久之很多,导致程序运行速度减慢甚至导致系统崩溃。)
3、内存不足时返回空指针。
4、返回类型是void*类型,表示未确定类型的指针,void*可以强转为任何其他类型指针。
5、主要函数 malloc(), calloc(), realloc(), free().头文件:#include<stdlib.h>
malloc
用于申请一块连续的指定大小的内存块区域
函数原型:void *malloc (unsign int size)
参数:size
int *p = (int*)malloc(n*sizeof(int)); //int [p]
返回值:如果分配成功则返回指向被分配内存的指针(此存储区中的初始值不确定),否则返回空指针NULL。当内存不再使用时,应使用free()函数将内存块释放。函数返回的指针一定要适当对齐,使其可以用于任何数据对象。
sizeof(int)尽量不使用具体数据类型数值
原因:自定义数据类型不容易得到数值
不同平台数值可能不同。(跨平台问题)
calloc
calloc用于将所有元素赋值初始值为0
函数原型:void *calloc(unsigned num,unsigned size)
参数:num(元素的数目),size(申请地址的单位元素长度)
int *p = (int*)calloc(100,sizeof(int));
malloc和calloc之间的主要区别:calloc在返回指向内存的指针之前把它初始化为0。
没有malloc常用
realloc
调整动态内存,主要用于扩大内存
函数原型: void*realloc(void *p,unsigned int size)
参数:p(要改变内存大小的指针名),size(新的内存大小)
p = (int*)realloc(p,20*sizeof(int));
使用总结
1. realloc失败的时候,返回NULL
2. realloc失败的时候,原来的内存不改变,不会释放也不会移动
3. 如果是扩大内存,先进行判断,如果当前指针有足够的连续空间,不用重新申请内存,直接在后面附加;如果空间不够,按照新的内存大小重新在堆中申请内存,将原有数据拷贝到新内存区域,并且释放原有指针空间(注意:是自动释放,不需要使用free),同时返回新分配的内存区域首地址。
如果它用于缩小一个内存块,原空间不变,服务器不会对此作出改变。
4. 如果size为0,效果等同于free()。这里需要注意的是只对指针本身进行释放,例如对二维指针**a,对a调用realloc时只会释放一维,使用时谨防内存泄露。
5. 传递给realloc的指针必须是先前通过malloc(), calloc(), 或realloc()分配的
6.传递给realloc的指针可以为空,等同于malloc。
free
执行动态内存释放,防止内存泄漏内存
对于不再使用的动态分配的内存空间,可以通过内存释放free函数将其返还给堆供后续分配函数使用
函数原型:void free(void *p)
参数:p
free(p);
通过以上的存储方式结构图可以看出有头信息和尾信息,每一段中间有空白区域,所以free 不需要长度信息。
free崩溃的原因:
1、越界,漏写sizeof(),或者realloc()第二个参数错误。
int main()
{
int *p1 = (int *)malloc(20);
for(int i=0;i<20;i++)
{
p1[i] = 0;
}
free(p1);
return 0;
}
2、指针移动,找不到头(修改了指针的值)
int main()
{
int *p = (int *)malloc(10*sizeof(int));
for(int i=0;i<10;i++)
{
*p = 0;
p++; //不free不崩溃
}
free(p); //崩溃
return 0;
}
3、重复释放内存
int main()
{
int *p = (int *)malloc(10*sizeof(int));
int *q = p;
free(p);
free(q);
return 0;
}
4、释放不是动态创建的内存(非动态内存)
int main()
{
int a = 10;
free(&a);
return 0;
}