Freeing malloced structure in a function

别等时光非礼了梦想. 提交于 2019-12-18 08:55:56

问题


I'm creating a source files containing buffer functionality that I want to use for my other library that I'm creating.

It is working correctly but I'm having trouble getting rid of the buffer structure that I'm creating in one of the functions. The following snippets should help illustrate my problem:

C header:

//dbuffer.h
...

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

C source:

//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);
    }
...

Main:

#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);
    }

Output:

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

RUN SUCCESSFUL (total time: 94ms)

Question:

Why am I still able to access struct contents using the line below after the pointer to the struct has been freed ?

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

回答1:


Once you've called free() on the allocated pointer, attempt to make use of the pointer invokes undefined behavior. You should not be doing that.

To quote C11 standard, chapter §7.22.3.4, free() function

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

It never say's anything about a cleanup, which you might be (wrongly) expecting.

Just to add clarity, calling free() does not always actually free up the allocated physical memory. It just enables that pointer (memory space) to be allocated again (returning the same pointer, for example) for successive calls to malloc() and family. After calling free(), that pointer is not supposed to be used from your program anymore but C standard does not guarantee of a cleanup of the allocated memory.




回答2:


If any attempt is made to read memory that has been freed can crash your program. Or they might not. As far as the language is concerned, its undefined behaviour.

Your compiler won't warn you about it(or stop you from accessing it). But clearly don't do this after calling free -

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

As a good practice you can set the freed pointer to NULL .




回答3:


free() call will just mark the memory in heap as available for use. So you still have the pointer pointing to this memory location but it's not available anymore for you. Thus, the next call to malloc() is likely to assign this memory to the new reservation.

To void this situations normally once you free() the memory allocated to a pointer you should set it to NULL. De-referencing NULL is UB also but at least when debugging you can see tha pointer should not be used because it's not pointing to a valid memory address.




回答4:


[too long for a comment]

To allow your "destructor" to set the pointer passed to NULL modify your code like this:

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

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

and call it like this:

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


来源:https://stackoverflow.com/questions/32884431/freeing-malloced-structure-in-a-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!