前言 :我们知道内存分为 栈 堆 其实在计算机中是不存在差别的,只是程序员手动分类 方便处理
C语言内存分配:
1. 栈区(stack)
windows下,栈内存分配2M(确定的常数),超出了限制,提示stack overflow错误
自动分配,释放
2. 堆区(heap)
程序员手动分配释放,操作系统80%内存
3. 全局区或静态区
4. 字符常量区
5. 程序代码区
案例1 我们直接创建一个在栈区的40m大小数组
void main(){
int aaasd[1024 * 1024 * 10];
}
结果:栈溢出
案例2 在堆区创建一个40m的数组
#include <stdlib.h>
void main(){
int * a = malloc(sizeof(int)* 1024 * 1024 * 10);
getchar();
}
malloc函数分配堆内存并返回对应指针 头文件stdlib.h
sizeof 返回对应变量所占字节数
结果:正常
案例3 多次动态分配堆内存 不释放
void main(){
int * a = malloc(sizeof(int)* 1024 * 1024 * 10);
//休眠程序10秒 头文件#include <Windows.h>
Sleep(10000);
a = malloc(sizeof(int)* 1024 * 1024 * 10);
getchar();
}
在执行睡眠的时候我们看看程序所占内存大小40mb
睡眠结束后 程序内存变为80mb
我们申请了两次内存分别为40mb,发现再第二次申请的时候内存所占变为80 可见第一次申请的内存并没有释放
案例4 手动释放内存
void main(){
int * a = malloc(sizeof(int)* 1024 * 1024 * 10);
//释放 a所指向的内存
free(a);
//休眠程序10秒 头文件#include <Windows.h>
Sleep(10000);
a = malloc(sizeof(int)* 1024 * 1024 * 10);
getchar();
}
上面的代码运行预期结果应该是:手动释放了第一次申请的40mb 内存 ,然后有申请了一次40mb 所以程序运行结束休眠后应该还是40mb
结果:和预期一致
案例5 申请内存另一个api
void main(){
//第一个参数申请数量, 每个申请数量的大小 那么这里还是申请40mb
int * a = calloc(1024*1024*10,sizeof(int));
getchar();
}
案例6 DEMO
void main(){
//第一个参数申请数量, 每个申请数量的大小 那么这里还是申请40mb
int * a = calloc(1024*1024*10,sizeof(int));
//内存申请成功
if (a!=NULL)
{
//xXXXX之后释放内存
free(a);
a = NULL;
}else{
//内存申请失败
}
getchar();
}
realloc
内存重新分配,当你动态内存申请40mb的数组此时你不够用怎么办?便可以重新调用realoc来重新分配内存
void main(){
//第一个参数申请数量, 每个申请数量的大小 那么这里还是申请40mb
int * a = calloc(1024 * 1024 * 10, sizeof(int)* 2);
//重新申请80mb 第一次申请的内存区域如果和新申请的区域不再同一段 那么 赋值数据到新内存段,并释放久指针内存区域
int * b=realloc(a, 1024 * 1024 * 10 * sizeof(int)* 2);
getchar();
}
注意新申请的内存 可能会在原来内存地址上基础上扩展/缩小,也有可能在某个新的内存地址段 申请一块 并且拷贝旧数据到新内存,同时释放旧内存
百度百科 :
realloc分配一个newsize的内存块,返回一个指向该内存块的指针。
如果newsize大小为0,那么释放mem_address指向的内存,并返回NULL。
如果没有足够可用的内存用来完成重新分配(扩大原来的内存块或者分配新的内存块),则返回NULL。而原来的内存块保持不变。
现存的数据然后就被拷贝至新的位置,而老块则放回到堆上.重要的信息就是数据可能被移动
总结:
- realloc失败的时候,返回NULL
- realloc失败的时候,原来的内存不改变,不会释放也不会移动
- 假如原来的内存后面还有足够多剩余内存的话,realloc的内存=原来的内存+剩余内存,realloc还是返回原来内存的地址; 假如原来的内存后面没有足够多剩余内存的话,realloc将申请新的内存,然后把原来的内存数据拷贝到新内存里,原来的内存将被free掉,realloc返回新内存的地址
- 如果size为0,效果等同于free()。这里需要注意的是只对指针本身进行释放,例如对二维指针**a,对a调用realloc时只会释放一维,使用时谨防内存泄露。
- 传递给realloc的指针必须是先前通过malloc(), calloc(), 或realloc()分配的
6.传递给realloc的指针可以为空,等同于malloc。