个人主页:修修修也
所属专栏:C语言
⚙️操作环境:Visual Studio 2022
目录
一.free()函数简介
1.函数功能
2.函数参数
void * ptr
3.函数返回值
4.函数头文件
二.free()函数的具体使用
1.使用free()函数完成malloc()开辟空间的释放
2.使用free()函数完成calloc()开辟空间的释放
3.使用free()函数完成realloc()开辟空间的释放
三.free()函数常见使用误区
1.对非动态开辟内存使用free释放
2.使用free释放一块动态内存的一部分
3.对同一块动态内存多次释放
4.动态开辟内存后忘记释放
结语
一.free()函数简介
我们先来看一下cplusplus.com – The C++ Resources Network网站上free()函数的基本信息:
1.函数功能
可以看到,free()函数的功能是:释放以前由malloc(),calloc(),realloc()函数动态开辟的内存空间.使其可以重新被分配.
2.函数参数
该函数有1个参数,是:
void free (void* ptr);
void * ptr
该参数的类型是无类型指针(void*),它指向先前由malloc(),calloc(),realloc()动态分配的内存块,它的作用是告诉函数要释放的内存块的起始位置.
3.函数返回值
函数的返回值类型是空(void),它表示函数在运行结束后不需要返回值.
4.函数头文件
该函数包含在头文件中.
二.free()函数的具体使用
free()函数的使用场景是:当我们先前使用了malloc(),calloc(),realloc()函数开辟了动态内存空间,我们在不再使用这块空间时就应该及时使用free()函数将它释放掉,以免造成内存泄漏.
内存泄漏:如果动态开辟的内存没有被释放,那么这些内存就会一直占用系统资源,从而导致内存泄漏。内存泄漏会导致程序运行速度变慢,甚至崩溃。
1.使用free()函数完成malloc()开辟空间的释放
如下,我们使用free()函数将malloc()开辟空间的释放掉:
给free()函数传入:malloc()函数动态开辟的指针(即p).
int main(){int* p = (int*)malloc(sizeof(int)*10);//开辟10个整型大小空间if (p == NULL) //如果开辟失败,则打印错误原因{//打印错误原因的一个方式printf("%s\n", strerror(errno));}else{int i = 0;for (i = 0; i < 10; i++)//遍历赋值并打印这10个整型空间{*(p + i) = i;printf("%d ", *(p + i));}//可以正常使用p指针来操作这片空间了}free(p);//释放p的内存空间p = NULL; //将指针p置为NULL,防止其变成野指针return 0;}
在vs编译器中运行查看结果:
虽然这里free()将malloc()动态开辟的内存释放后好像也没有发生什么变化,但如果我们因此不释放之前malloc()动态开辟的空间,那么这块空间就会一直占用着内存,既没有用,也没法让其他人使用.
还有一点需要注意的是,我们在free()完p指向的空间后,最好将p的内容置为NULL,否则这块空间已经被释放掉了,但你还保存着这块空间的地址,后续如果不小心再访问p的话,就会造成非法访问.
2.使用free()函数完成calloc()开辟空间的释放
如下,我们使用free()函数将calloc()开辟空间的释放掉:
给free()函数传入:calloc()动态开辟的内存指针(即p).
int main(){int* p = (int*)calloc(10,sizeof(int));//开辟10个整型大小空间if (p == NULL) //如果开辟失败,则打印错误原因{//打印错误原因的一个方式printf("%s\n", strerror(errno));}else{int i = 0;for (i = 0; i < 10; i++)//遍历并打印这10个整型空间{printf("%d ", *(p + i));//因为calloc()开辟的空间会自动初始化,所以我们可以不初始化这块空间,直接打印}//可以正常使用p指针来操作这片空间了}free(p);//释放p的内存空间p = NULL; //将指针p置为NULL,防止其变成野指针return 0;}
在vs编译器中运行查看结果:
释放calloc()开辟的空间和malloc()一样,看不出来必要性,但却是非常有必要的.
3.使用free()函数完成realloc()开辟空间的释放
如下,我们使用free()函数将realloc()开辟空间的释放掉:
分别给free()函数传入:realloc()扩容后的内存块指针(即p).
int main(){int* p = (int*)calloc(10,sizeof(int));//开辟10个整型大小空间if (p == NULL) //如果开辟失败,则打印错误原因{//打印错误原因的一个方式printf("%s\n", strerror(errno));}else{int i = 0;for (i = 0; i < 10; i++)//遍历并打印这10个整型空间{printf("%d ", *(p + i));//因为calloc()开辟的空间会自动初始化,所以我们可以不初始化这块空间,直接打印}//可以正常使用p指针来操作这片空间了}printf("\n");p = (int*)realloc(p, 15 * sizeof(int));//将这块空间扩容到15个整型if (p == NULL){printf("%s\n", strerror(errno));}else{int i = 0;for (i = 0; i < 15; i++)//遍历并打印这15个整型空间{printf("%d ", *(p + i));}}free(p);//释放p的内存空间p = NULL; //将指针p置为NULL,防止其变成野指针return 0;}
在vs编译器中运行查看结果:
由realloc()扩容的内存块,扩容前的数据会保留,但新扩容的空间不会初始化,因此后面五个元素打印出的值是随机值.
三.free()函数常见使用误区
1.对非动态开辟内存使用free释放
因为p是由编译器分配到栈区的,不属于堆区,因此不能使用free释放.
void test(){int a = 10;int *p = &a;free(p);//p不是动态开辟的,不能释放}
使用vs2022测试一下:
可以看到,该错误导致了程序出错.
而图中的报错”已执行断点指令”则是因为代码执行过程中出现了未定义的非法行为.
2.使用free释放一块动态内存的一部分
如下代码:
void test(){int *p = (int *)malloc(100);p++;free(p);//p不再指向动态内存的起始位置}
在vs2022中测试一下:
可以看到,该错误导致了程序异常终止.
3.对同一块动态内存多次释放
如下代码:
void test(){int *p = (int *)malloc(100);free(p);free(p); //重复释放}
在vs2022中进行测试:
可以看到,该错误导致了程序出错.
这里列出了两个防止重复释放的小技巧:
- 在设计时尽量遵从:谁开辟,谁回收的原则
- 在free完后立刻将原动态开辟的指针置为NULL.
4.动态开辟内存后忘记释放
如下代码:
void test(){int *p = (int *)malloc(100);if(NULL != p){*p = 20;}//没有释放!}int main(){test();}
如果动态开辟的内存忘记释放,程序不会报错,但会造成内存泄漏!
忘记释放不再使用的动态开辟的空间会造成内存泄漏.
内存泄漏:如果动态开辟的内存没有被释放,那么这些内存就会一直占用系统资源,从而导致内存泄漏。内存泄漏会导致程序运行速度变慢,甚至崩溃。
因此:
动态开辟的空间一定要释放,并且正确释放!
动态开辟的空间一定要释放,并且正确释放!
动态开辟的空间一定要释放,并且正确释放!
结语
希望这篇free()函数详解能对大家有所帮助,欢迎大佬们留言或私信与我交流.
有关更多动态开辟相关知识可以移步:
【C语言】内存的动态分配与释放https://blog.csdn.net/weixin_72357342/article/details/134099965?spm=1001.2014.3001.5502
学海漫浩浩,我亦苦作舟!关注我,大家一起学习,一起进步!
相关文章推荐
【C语言】malloc()函数详解(动态内存开辟函数)
【C语言】realloc()函数详解(动态内存开辟函数)
【C语言】calloc()函数详解(动态内存开辟函数)
【C语言】free()函数详解(动态内存释放函数)
【C语言】memcpy()函数
【数据结构实战项目】C语言实现数据结构顺序表万字详解(附完整运行代码)
【实用编程技巧】不想改bug?初学者必须学会使用的报错函数assert!(断言函数详解)
C语言动态内存开辟相关库函数思维导图: