malloc和free函数使用注意事项,C语言malloc和free使用详解
在 C 语言中,程序中 malloc 等内存分配函数的使用次数一定要和 free 相等,并一一配对使用。绝对要避免“malloc 两次 free 一次”或者“malloc 一次 free 两次”等情况。这就像我们的婚姻制度,必须是“一夫一妻制”,不能够“多夫一妻”或者“一夫多妻”,这些都是不合法的,如下面的示例代码所示:
如下面的示例代码所示:
“free(p)”释放的是指针变量 p 所指向的内存,而不是指针变量 p 本身。指针变量 p 并没有被释放,仍然指向原来的存储空间。
其实,指针只是一个变量,只有程序结束时才被销毁。释放内存空间后,原来指向这块空间的指针还是存在的,只不过现在指针指向的这块内存是不合法的。因此,在释放内存后,必须把指针指向 NULL,以防止指针在后面不小心又被解引用了。
如下面的示例代码所示:
#define MAX_BUF_SIZE 100 int main(void) { /*内存释放标志*/ int flag = 0; char * p = (char *)malloc(MAX_BUF_SIZE); if (p == NULL) { /*...*/ } if (flag == 0) { free(p); } free(p); return 0; }在上面示例代码中,当条件“if(flag==0)”成立时,“free(p)”将被执行两次,从而导致内存的双重释放错误。因此,应该消除这种双重释放潜在的风险,保证动态内存只被释放一次,如下面的示例代码所示:
#define MAX_BUF_SIZE 100 int main(void) { /*内存释放标志*/ int flag = 0; char * p = (char *)malloc(MAX_BUF_SIZE); if (p == NULL) { /*...*/ } if (flag == 0) { /*...*/ } free(p); p=NULL; return 0; }当然,也可以采用下面的方式:
#define MAX_BUF_SIZE 100 int main(void) { /*内存释放标志*/ int flag = 0; char * p = (char *)malloc(MAX_BUF_SIZE); if (p == NULL) { /*...*/ } if (flag == 0) { free(p); p = NULL; } if (p != NULL) { free(p); p = NULL; } return 0; }除此之外,对于内存释放还必须保证只释放动态分配的内存,即不能用 free 来释放非 malloc、realloc、calloc 与 aligned_alloc 等内存分配函数分配的内存空间。与此同时,也不要将指针变量进行自增或者自减操作,使其指向动态分配的内存空间中间的某个位置,然后直接释放,这样也有可能引起未知的错误。
在 free 之后必须为指针赋一个新值
在使用指针进行动态内存分配操作时,在指针 p 被 free 释放之后,指针变量本身并没有被删除。如果这时候没有将指针 p 置为 NULL,会让人误以为 p 是个合法的指针而在以后的程序中错误使用它。如下面的示例代码所示:
#define MAX_BUF_SIZE 100 int main(void) { char * p = NULL; p=(char *)malloc(MAX_BUF_SIZE); if (p == NULL) { /*...*/ } /*内存初始化*/ memset(p, '\0', MAX_BUF_SIZE); strcpy(p, "hello"); /*释放内存*/ if (p != NULL) { free(p); } if (p != NULL) { /*发生错误*/ strcpy(p, "world"); } return 0; }在上面的示例代码中,第一个判断语句:
/*释放内存*/ if (p != NULL) { free(p); }虽然释放了指针变量 p,但这个时候指针变量 p 本身并没有被删除,其保存的地址并没有改变。但是,此时 p 虽不是 NULL 指针,但它却不指向合法的内存块,成为“野指针”或称为“悬垂指针”。接下来,在执行第二个判断语句时:
if (p != NULL) { /*发生错误*/ strcpy(p, "world"); }条件“if (p != NULL)”成立,“strcpy(p, "world");}”语句将被继续执行,导致程序出错。或许有人会问,“free(p)”到底释放了什么?
“free(p)”释放的是指针变量 p 所指向的内存,而不是指针变量 p 本身。指针变量 p 并没有被释放,仍然指向原来的存储空间。
其实,指针只是一个变量,只有程序结束时才被销毁。释放内存空间后,原来指向这块空间的指针还是存在的,只不过现在指针指向的这块内存是不合法的。因此,在释放内存后,必须把指针指向 NULL,以防止指针在后面不小心又被解引用了。
如下面的示例代码所示:
#define MAX_BUF_SIZE 100 int main(void) { char * p = NULL; /*内存申请*/ p = (char *)malloc(MAX_BUF_SIZE); if (p == NULL) { /*...*/ } /*内存初始化*/ memset(p, '\0', MAX_BUF_SIZE); strcpy(p, "hello"); /*释放内存*/ if (p != NULL) { free(p); /*在free之后给指针存储一个新值*/ p = NULL; } if (p != NULL) { /*发生错误*/ strcpy(p, "world"); } return 0; }现在,通过语句“p=NULL”给指针变量 p 赋予一个 NULL 值之后,第二个条件语句“if(p!=NULL)”将不成立,语句“strcpy(p,"world")”也将不会被执行。所以一定要记住一条:free(p) 完之后,一定要将指针变量 p 置为 NULL。
所有教程
- C语言入门
- C语言编译器
- C语言项目案例
- 数据结构
- C++
- STL
- C++11
- socket
- GCC
- GDB
- Makefile
- OpenCV
- Qt教程
- Unity 3D
- UE4
- 游戏引擎
- Python
- Python并发编程
- TensorFlow
- Django
- NumPy
- Linux
- Shell
- Java教程
- 设计模式
- Java Swing
- Servlet
- JSP教程
- Struts2
- Maven
- Spring
- Spring MVC
- Spring Boot
- Spring Cloud
- Hibernate
- Mybatis
- MySQL教程
- MySQL函数
- NoSQL
- Redis
- MongoDB
- HBase
- Go语言
- C#
- MATLAB
- JavaScript
- Bootstrap
- HTML
- CSS教程
- PHP
- 汇编语言
- TCP/IP
- vi命令
- Android教程
- 区块链
- Docker
- 大数据
- 云计算