C语言动态内存开辟与销毁:包含在头文件<stdlib.h>中
(一)malloc:开辟一块内存
(1)原型:void*malloc(size_t size);void* 类型可以强制转换为任何其它类型的指针,但反过来就不行了
(2)开辟方式:
void*malloc(size_t size);//参数为开辟数据类型*开辟数量,返回值为所申请空间的首地
void*q = (int *)malloc(sizeof(int)* 4);//开辟4个int型大小的堆内存,即16个字节
(3)malloc函数申请的空间都是从堆中获取的,需要手动调用free函数释放
(4) 如果开辟成功,则返回一个执行开辟好空间的指针。
如果开辟失败,则返回一个 NULL 指针,因此 malloc 的返回值一定要做检查。
(二)calloc:也是用来动态分配,并初始化为0
原型: void *calloc(size_t num, size_t size)
功能:为num个大小为 size 的元素开辟一块空间,并把空间的每个字节初始化为0.
(三)realloc:修改原先已分配好的内存块大小
原型:void *realloc(void *ptr,size_t size)
使用:
- ptr是指针,指针指向需要修改的内存空间的首地址,ptr必须指向堆区空间
- size是最终内存的大小
- 修改ptr指向的内存空间的大小,并不会修改原来的内存空间的存储的值
- 修改后的空间的首地址不一定和之前的相等,假如原来的内存后面还有足够多剩余内存的话,realloc的内存=原来的内存+剩余内存,realloc还是返回原来内存的地址; 假如原来的内存后面没有足够多剩余内存的话,realloc将申请新的内存,然后把原来的内存数据拷贝到新内存里,原来的内存将被自动free掉,realloc返回新内存的地址。
- realloc传递的指针必须为malloc()、calloc()或者realloc()先前分配的指针
简单使用:realoc(arr,40);//arr为要扩充的内存的首地址,40为最终内存的大小
(四)内存销毁函数free
原型:void*free(void*)
使用:参数为所要释放内存的首地址,为指针类型
简单使用:
int *p = (int *)malloc(siozeof(int )* 4);
free(p);
(五)开辟与释放的具体使用:
malloc与calloc开辟与释放:
int main()
{
int i;
int *p = (int*)malloc(sizeof(int)*4); //开辟空间但是不做初始化
printf("malloc申请的空间值:\n");
for ( i=0 ; i < 4; i++)
{
printf("%d ", p[i]); //printf("%d\n",*p++)也可打印出随机值,但最后释放时程序崩溃,原因是:指针++改变了地址,free时要传入的是开辟内存的首地址
}
printf("\n\n");int *q = (int*)calloc(20,sizeof(int)); //开辟空间并做0初始化
printf("calloc申请的空间的值:\n");
for ( i=0 ; i < 20; i++)
{
printf("%d ", q[i]);
}
printf("\n");free(p); //参数为所开辟内存的首地址
p = NULL;
free(q);
q = NULL;return 0;
}
运行结果:
malloc与realloc的开辟与释放:
int main()
{
int *p = (int *)malloc(20*sizeof(int));
int *pp = (int *)realloc(p, 40*sizeof(int));int *q = (int *)realloc(p, 0);//当size为0时,相当于free。
printf("原来的p_Address:%x 扩容后的pp_Address:%x\n size为0的 q_Address:%dx\n", p, pp,q);
// free(p);
// p = NULL; 这两行代码错误,realloc底部实现,将原来内存的值拷贝到新内存中,并且将原来的内存free掉,因此不需要再次释放p.
free(pp);
pp = NULL;
return 0;
}
运行结果:
(六)TIPS:
(1)free释放内存:将内存小块拼成大块,然后释放
(2)调用free时并没有传入内存大小,那么free函数为什么知道释放了多少字节内存???
在函数内存块前加入了头信息,在内存块尾部加入了尾信息。
真正的内存管理如申请/释放等,并不是由malloc或者free等库函数来负责的,而是交由操作系统去完成,它们只是维护一个空闲的链表式的内存块。例如:要申请sizeof(int)*100大小的内存空间,虽然返回的是内存大小是400,但实际上,操作系统分配时候,会多出一块用于存储内存大小的类似链表head头节点的东西,这个节点存储的是空间的首地址及分配内存的大小。当调用free函数的时候,其实它也不知道要释放内存的大小,它只需改变head头结点里的内存的大小就可以了,具体内存空间的释放由操作系统去完成。
(3)free出现崩溃的原因:
- 越界(越界改掉尾部信息)
- 传参时漏掉了sizeof,例int *p = (int *)malloc(10*sizeof(int ));
- realloc的第二个参数写错
- 改变了指针的指向
int *p = (int *)malloc(10*sizeof(int ));
for(int i = 0;i < 10;i++)
{
*p = 0;
p++; //指针指向改变,没有指向所开辟内存的首地址
}
free(p); //出错
- 重复释放
- 释放不是动态申请的内存