在函数中释放 malloc 结构

Freeing malloced structure in a function

我正在创建一个包含缓冲区功能的源文件,我想将其用于我正在创建的其他库。

它工作正常,但我无法摆脱我在其中一个函数中创建的缓冲区结构。以下片段应该有助于说明我的问题:

C header:

//dbuffer.h
...

typedef struct{
    char *pStorage;
    int *pPosition;
    int next_position;
    int number_of_strings;
    int total_size;
    }DBUFF; 
...

C 来源:

//dbuffer.c
...
DBUFF* dbuffer_init(char *init_pArray)
    {
    //Find out how many elements the array contains
    int size = sizeof_pArray(init_pArray);                         

    //Initialize buffer structure
    DBUFF *buffer = malloc(sizeof(DBUFF));                                       

    //Initialize the storage
    buffer->pStorage = malloc( (sizeof(char)) * (size) );

    strncpy( &(buffer->pStorage)[0] ,  &init_pArray[0] , size);
    buffer->number_of_strings = 1;

    buffer->total_size = size;
    buffer->next_position = size; //size is the next position because array allocates elements from 0 to (size-1)

    //Initialize the position tracker which keeps record of starting position for each string
    buffer->pPosition = malloc(sizeof(int) * buffer->number_of_strings );
    *(buffer->pPosition + (buffer->number_of_strings -1) ) = 0;

    return buffer;
    }

void dbuffer_destroy(DBUFF *buffer)
    {
    free(buffer->pStorage);
    free(buffer);
    }
...

主要:

#include <stdio.h>
#include <stdlib.h>
#include "dbuffer.h"


int main(int argc, char** argv)
    {
    DBUFF *buff; 

    buff = dbuffer_init("Bring the action");
    dbuffer_add(buff, "Bring the apostles");
    printf("BUFFER CONTENTS: ");
    dbuffer_print(buff); 

    dbuffer_destroy(buff);

    // Looks like it has been succesfully freed because output is garbage
    printf("%s\n", buff->pStorage);   

    //Why am I still able to access struct contents after the pointer has been freed ?
    printf("buff total size: %d\n", buff->total_size);

    return (EXIT_SUCCESS);
    }

输出:

BUFFER CONTENTS: Bring the action/0Bring the apostles/0
��/�
buff total size: 36

RUN SUCCESSFUL (total time: 94ms)

问题:

为什么在释放指向结构的指针后我仍然可以使用下面的行访问结构内容?

printf("buff total size: %d\n", buff->total_size);

在分配的指针上调用 free() 后,尝试使用指针调用 undefined behavior。你不应该那样做。

引用C11标准,章节§7.22.3.4,free()函数

The free() function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. [..]

它从不说任何关于 清理 的事情,这可能是您(错误地)期待的。

为了清楚起见,调用 free() 并不总是实际 释放 分配的物理内存。它只是使该指针(内存 space)能够再次分配(例如,返回相同的指针)以用于对 malloc() 和系列的连续调用。调用 free() 后,该指针不应再从您的程序中使用,但 C 标准不保证 清理 分配的内存。

如果尝试读取已经 freed 的内存,可能会使您的程序崩溃。或者他们可能不会。就语言而言,它的未定义的行为

您的编译器不会警告您(或阻止您访问它)。但是在调用 free -

之后显然不要这样做
printf("buff total size: %d\n", buff->total_size);

作为一种好的做法,您可以将 freed 指针设置为 NULL

free() 调用只会标记 堆中的内存可用。所以你仍然有指向这个内存位置的指针,但它不再对你可用。因此,下一次调用 malloc() 很可能会将此内存分配给新的预留空间。

要在 free() 分配给指针的内存后正常避免这种情况,您应该将其设置为 NULL。取消引用 NULL 也是 UB,但至少在调试时你可以看到不应该使用指针,因为它没有指向有效的内存地址。

[评论太长]

为了让您的 "destructor" 设置传递给 NULL 的指针,请像这样修改您的代码:

void dbuffer_destroy(DBUFF ** buffer)
{
  if ((NULL == buffer) || (NULL == *buffer))
  {
     return;
  }

  free((*buffer)->pPosition);
  free((*buffer)->pStorage);
  free(*buffer);
  *buffer = NULL;
}

并这样称呼它:

  ...
  dbuffer_destroy(&buff);
  ...