函数 malloc、calloc、realloc
内存泄漏
之前变量也好数组也好,初始化空间大小后空间固定那么大,如数组不能多放元素;而定义的空间大,但是只放少量元素会显得其他空间有些浪费
那么存不存在一种方式,初始化空间大小后,之后还能继续改变空间大小
有,当然有(无所谓 ,Vs 会出手)
函数 malloc、calloc、realloc
函数且不说,首先先把这种空间初始化后还能调整的空间称为动态内存
并且记住动态内存是在堆区分配内存 (不像变量和数组再栈区分配内存)
malloc
void*malloc(size_tsize);
格式:(例) int* p = (int*)malloc(5*sizeof(int));
头文件:
参数size:表示要开辟空间大小,以字节为单位(注意是以字节为单位)
返回值:
开辟成功返回开辟的那块空间的首地址(注意是 void* 类型,记得类型转换)
开辟失败返回 NULL
用法:(一借一还)
借:
(1)使用malloc借用空间;
使用 malloc 来开辟空间,可以理解为向内存空间借了一块空间
(2)检验是否借‘款’成功
而你得知道堆区人家不是大银行,当你索要的空间有点大的时候,可能会借‘款’失败
所以就需要验证:可以用 perror 、strerror,或者说 assert
还(两步:free,置空)
free 释放借来的空间 & 将原指针置空
格式:
free(p); //假设p为动态内存空间的首地址
p = NULL;
这两步才称为 还 。而一开始会想 free(p); 不是已经把借的内存释放掉了吗。 p=NULL; 这一步是什么?有必要吗?
那就先看到 free(p); 是把借来的内存还回去了,但是要注意,p 这个指针好像还是指向刚刚开始借内存的地方(p里面还存着这个地址),但是现在已经把它指向的空间释放掉了,p现在如果不赋有用的地址,还是指向没开辟的内存空间,已经没有什么实际意义;更糟糕的是如果不小心解引用 p (*p)会出现访问错误(这时相当于变成野指针)
所以用完没什么事我们最好把 p 置空即:p=NULL;
注:
(1)free对象是在堆区开辟动态内存空间的首地址,一定要是首地址,
所以定义一个动态空间,给的首地址 p 一般不要让其改动(自增自减),不然就改动前把它存起来
(2)还得注意不要二次 free ,没事不要二次放p,p没置空会出错
(3)注意free释放的是堆区的空间,不能杀疯了把栈区的空间释放(普通指针变量),会报错的
calloc
void*calloc(size_tnum,size_tsize);
格式:(例) int* p = (int*)calloc(5, sizeof(int));
头文件:<stdlib.h>
参数num:元素个数
参数size:每个元素的大小,以字节为单位(注意是以字节为单位)
返回值:
开辟成功返回开辟的那块空间的首地址(注意是 void* 类型,记得类型转换)
开辟失败返回 NULL
用法也是一借一还
借:
(1)使用malloc借用空间;
(2)检验是否借‘款’成功
还:(两步:free,置空)
free 释放借来的空间 & 将原指针置空
可以发现 malloc 和 calloc 除了参数还是挺像的,他们之间有什么区别呢
malloc 和 calloc的区别:
malloc申请的空间不会初始化 ,同时效率会高点
calloc申请好空间会把空间初始化为 0 , 不过效率相比 malloc 会低一点点
realloc
malloc 和 calloc 只是开辟初始的内存空间,如要改变、调整空间大小,还是得看 realloc
先了解realloc的基本原理是重新定义借来空间的大小
void*realloc(void*memblock,size_tsize);
格式:(例)int* ptr = (int*)realloc(p, 10*sizeof(int));
memblock:表示要调整的动态内存的首地址(原来接收malloc或calloc返回值的指针)
size:要新定义空间的大小,以字节为单位(注意是以字节为单位)
返回值:
情况一:若申请的内存比较小,新开辟的空间不会太大说影响到堆区已开辟的空间(不会大到影响他后面已定义了的空间)
这时返回原来的首地址(p)
情况二:若申请的内存比较大,新开辟的空间太大而影响到堆区已开辟的空间(太大影响到他后面定义了的空间)
这时会有相关操作:既然这个地方太小,那我走
会到另一个空间足够的地方(还在堆区),开辟大小符合要求的空间,返回这个新空间的首地址
内存泄漏
如果说开辟了动态空间用完没有释放 没有还,那么之前开辟的动态空间就会一直占着(堆区)内存空间,可能影响其他程序运行(占着茅坑不拉屎)
所以说借了一定得还,不然伤的是电脑(心疼的嘞)
重要的话说三遍:
创建了动态内存空间,就一定要记得释放!
创建了动态内存空间,就一定要记得释放!
创建了动态内存空间,就一定要记得释放!
常见错误:
忘记验证是否开辟动态内存空间成功(忘记验证是否借成功)
忘记还的第一步:释放动态内存
忘记还的第二步:指针忘记置空
所以既然要用动态内存空间
我们就应该做到:有借有还
借完记得验证,还完记得置空