1

I have something like this:-

struct Pos {
    float x, y;
};
struct Rect {
    struct Pos* pos;
    int width, height;
};

I have created a pointer of Rect, so when I will free this pointer using free(), then will it also free pos?

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
Priyanshu
  • 23
  • 4
  • 1
    What do you mean by `Entity`? – Govind Parmar Jan 26 '23 at 15:40
  • 7
    No. ___________ – interjay Jan 26 '23 at 15:40
  • 1
    Quick answer: no. In C nothing gets freed automatically, it's up to you to free anything that has been allocated via `malloc` and similar functions. – Jabberwocky Jan 26 '23 at 15:40
  • @GovindParmar sorry there was some mistake, but I have corrected it now. – Priyanshu Jan 26 '23 at 15:47
  • @Priyanshu Provide a minimal complete program that shows how pointers were created and assigned. – Vlad from Moscow Jan 26 '23 at 15:50
  • No, and you must `free` the `pos` member (if it was allocated) *before* the struct itself. – Weather Vane Jan 26 '23 at 15:53
  • 1
    Memory that is dynamically allocated by a program will also be freed by the OS upon program end. Although a fact, it is not a recommended method. – ryyker Jan 26 '23 at 15:59
  • 1
    With C++, you have constructors to control the allocation and destructors to do the deallocation. C is not C++, though. There is nothing that will automatically release the data associated with an embedded pointer — if only because there's no guarantee that a pointer in a structure points to deallocatable memory. – Jonathan Leffler Jan 26 '23 at 16:02
  • 3
    In C never assume *anything* happens without your explicit programming doing it. There are very few things that are "automatic". They don't call it "fancy assembly" for nothing. – tadman Jan 26 '23 at 16:02
  • In C everything that is manually allocated must be manually deallocated. Beware that of you free the pointer to your struct before freeing it content, you'll end up with a an invalid pointer and you wont be able to free the "pos" pointer. – Elzaidir Jan 26 '23 at 16:02
  • 1
    _"I have created a pointer of Rect,..."_. It would be an improvement to your question for you to include the one, or two lines to show this in your post. – ryyker Jan 26 '23 at 16:03
  • If you want (somewhat) automatic deallocation, GCC and CLANG have the handy "cleanup" attribute. See https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-cleanup-variable-attribute. It is not portable, and if you are learning C you need to understand how memory management work, so I don't recommend you using it – Elzaidir Jan 26 '23 at 16:04

4 Answers4

2

I have created a pointer of Rect, so when I will free this pointer using free(), then will it also free pos?


Assuming the pointer to struct Rect was allocated on the heap with one of the memory allocation function (so that it can be freed legitimately), then free() will only release the memory for the structure that was pointed at, not the nested pointers.

You must free() the pointer pos before free()ing the pointer to the struct, else you'll lose access to the memory allocated through pos, and leak it.

Every object you malloc(), must later be released with free(). It doesn't happen for you automatically.

See also: When you exit a C application, is the malloc-ed memory automatically freed?

Harith
  • 4,663
  • 1
  • 5
  • 20
  • @Priyanshu Better to add some code relevant to the question. There's no point in hamstringing us. :-) – Harith Jan 26 '23 at 16:17
2

No; everything you manually allocate, you manually deallocate. This makes dynamic 2D (and more) arrays somewhat tedious to code, requiring:

 int **array = malloc(NUM_ROWS * sizeof(int *));
 if(NULL == array)
 {
     // Handle out of memory error
 }
 for(int i = 0; i < NUM_ROWS; i++)
 {
     array[i] = malloc(NUM_COLS * sizeof(int));
     if(NULL == array[i])
     {
         // Handle out of memory error
     }
 }

To allocate, then:

for(int i = 0; i < NUM_ROWS; i++)
{
    free(array[i]);
    array[i] = NULL;
}
free(array);
array = NULL;

To deallocate. If you manually allocate pos, you manually deallocate pos before you deallocate its parent struct Rect if that's what it's in:

free(someRect.pos);
someRect.pos = NULL;
free(someRect);
someRect = NULL;

I always set pointers to NULL(ptr) after freeing or deleteing (C++) them.

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85
  • 1
    And cleaning up if there's a memory allocation failure part way through the allocating `for` loop is fiddly (but necessary to avoid leaks). – Jonathan Leffler Jan 26 '23 at 16:00
  • @JonathanLeffler Indeed - assuming you do anything other than exit with an error message about the user's system being seriously low on memory, which is, if you ask me, the best thing to do for all but the most heavy-duty of allocations – Govind Parmar Jan 26 '23 at 16:09
  • @GovindParmar It is evident that the question is unclear. It is unclear how the pointer pos was assigned. For example it can point to a local or global variable The author of the question must provide a minimal complete program that demonstrates the meaning of the question. But such as you are hurry to answer even to bad questions. – Vlad from Moscow Jan 26 '23 at 16:40
  • @VladfromMoscow That is the same assumption every single other answer on this question makes – Govind Parmar Jan 26 '23 at 16:44
  • @GovindParmar Even this phrase in the question "I have created a pointer of Rect" does not make sense. – Vlad from Moscow Jan 26 '23 at 16:49
2

Assuming you do something like

struct Rect *r = malloc( sizeof *r );
r->pos = malloc( sizeof *r->pos );
...
free( r );

then no, this will not free the memory that r->pos points to. You must make sure to deallocate r->pos before deallocating r:

free( r->pos );
free( r );

It's usually a good idea to abstract out the allocation and deallocation for types that require multiple allocation and free operations:

struct Rect *newRect( void )
{
  struct Rect *r = malloc( sizeof *r );
  if ( r )
  {
    r->pos = malloc( sizeof *r->pos );
    /**
     * If we can't successfully allocate r->pos, 
     * deallocate anything we've allocated
     * so far and return NULL.
     */
    if ( !r->pos )
    {
      free( r );
      r = NULL;
      fputs( "Failed to allocate internal member\n", stderr );
    }
  }
  return r;
}

void freeRect( struct Rect *r )
{
  free( r->pos );
  free( r );
}
John Bode
  • 119,563
  • 19
  • 122
  • 198
1

Note, this is an aside, as it does not address your primary question.
But given your description

"I have created a pointer of Rect"

I wanted to point out that it is possible to use this pointer variable without having to free its memory. Just point it to a location created on the stack. So given your definitions, here is how that would work:

struct Pos {
    float x, y;
};
struct Rect {
    struct Pos* pos;
    int width, height;
};

int main(void) {
   
    struct Rect rect = {0};//create instance of struct on stack
    struct Rect *pRect = &rect;//point pointer to location created on the stack
    pRect->pos = malloc(10*sizeof(struct Pos));// allocate only pointer
                                               // member of struct Pos
    if(pRect->pos)
    {
        //do something with rect.pos
        for(int i=0;i<10;i++)
        {
            pRect->pos[i].x = (i+1.0)*1.0; 
            pRect->pos[i].y = pRect->pos[i].x * pRect->pos[i].x;
        }
        //free rect.pos when finished
        free(pRect->pos);//only need to free the pointer member of struct Pos
        //no need to free pRect as it points to memory created on stack
    }
    return 0;
}
ryyker
  • 22,849
  • 3
  • 43
  • 87