首页 > 编程笔记

malloc和free函数使用注意事项,C语言malloc和free使用详解

在 C 语言中,程序中 malloc 等内存分配函数的使用次数一定要和 free 相等,并一一配对使用。绝对要避免“malloc 两次 free 一次”或者“malloc 一次 free 两次”等情况。这就像我们的婚姻制度,必须是“一夫一妻制”,不能够“多夫一妻”或者“一夫多妻”,这些都是不合法的,如下面的示例代码所示:
#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。

推荐阅读