升起时奋斗,日落时自省
目录
一、常见的动态内存错误
1.对NULL指针的解引用操作
#include<stdio.h>
#include<stdlib.h>
int main() //错误 没有检测p是否开辟成功
{
int* p = (int*)malloc(40);
*p = 20;
return 0;
}
int main() //正确
{
int* p = (int*)malloc(40);
if (p == NULL)
{
perror(p);
}
*p = 20;
free(p);
p = NULL;
return 0;
}
动态开辟内存,需判断是否为NULL,代码运行更可靠,动态开辟易产生内存泄漏,该情况也存在内存泄漏,没有在程序结束时,free掉原来开辟的内存。
2、对动态开辟之间的越界访问
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p = (int*)malloc(40);
if (p == NULL)
{
perror(p);
return 1;
}
int i = 0;
for (i = 0; i <= 10; i++)//越界访问
{
p[i] = i;
}
free(p);
p = NULL;
return 0;
}
当前开辟内存只有40个字节,但是在i在这里为11个int,相当于44个字节,越界访问
3、对非动态开辟内存使用free释放
void test()
{
int a = 10;
int* p = &a;
free(p);
p = NULL;
return 0;
}
非动态开辟free会直接报错
4、使用free释放一块动态开辟内存的一部分
int main()
{
int i = 0;
int* p = (int*)malloc(10*sizeof(int));
if (p == NULL)
{
perror(p);
return 1;
}
for (i = 0; i < 10; i++)
{
*p = i;
p++; //这里改变了p的位置
}
free(p); //不能释放部分p内存
p = NULL;
return 0;
}
当前p的变化如上图,free是p以后的内存,这是不能的,在上面的错误代码中p直接走到了最后当前如果free要进行的话,又什么都free不了。
更改:p++改为*(p+i);
5、对同一块动态内存多次释放
int main()
{
int* p = (int*)malloc(40);
//...
free(p);
//...
free(p);
}
当前p内存以及释放一次,在次释放,系统也不知道做什么,就会报错,在每次free之后记得将其置空p=NULL,再次释放也不会有太大的影响
6、动态开辟内存忘记释放(内存泄漏)
#include<stdio.h>
#include<stdlib.h>
void test()
{
int* p = (int*)malloc(10 * sizeof(int));
int flag = 0;
//...
scanf("%d", &flag);
if (flag == 5) //如果当前执行了,那就没有机会free
return;
//...
free(p);
p = NULL;
}
int main()
{
test();
return 0;
}
int *test()
{
int* p = (int*)malloc(10 * sizeof(int));
if(p=NULL)
{
return p;
}
return p;
}
int main()
{
int *ret=test();
return 0;
}
第一种,在代码中途以及return返回了,不能执行free释放空间,导致内存泄漏
第二种,是忘记了,在调用函数中申请的内存,返回时忘记了在主函数中释放内存
内存泄漏:是当前开辟内存,你用完后,又不释放掉,那就相当于没有人再去使用这块内存,就是内存泄漏
二、内存开辟
堆区(Heap) :运行时分配、手动开辟、释放内存
栈区 (Stack):局部变量、运行时分配、系统自动管理