1

Say I had the following simple example

#include <stdlib.h>
#include <stdio.h>
struct x {
    int* p;
};

typedef struct y {
    x* foo;
}real;

void doSomething();

int main() {
    doSomething();
    getchar();
    return 0;
}

void doSomething() {
   real* tmp = (real*)malloc(sizeof(real));
   tmp->foo = (x*)malloc(sizeof(x));
   free(tmp->foo);
   free(tmp);
}

Is it necessary to free the pointer I allocated inside before I free the "outer" allocated memory?

would the second line take care of the first allocated memory...my assumption is no(it will still remain on the heap I assume and I would need to keep it this way).

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
Yusuf Jama
  • 123
  • 13
  • 2
    Note that in `struct y`, you refer to a type `x` but, in C, that is not the type specified by `struct x`. Only C++ defines the type `x` after you define `struct x`; C leaves the type `x` undefined until you use `typedef struct x x;`. That means your code should not compile with a C compiler — but maybe you're using a C++ compiler to compile the code after all, despite the C tag. (Maybe the compiler is the MS Visual Studio compiler, at that.) – Jonathan Leffler Sep 21 '16 at 05:28
  • 1
    you are correct....it's a c++ compiler in VS – Yusuf Jama Sep 21 '16 at 05:29
  • @JonathanLeffler C++ tag removed by Yu Hao. – BLUEPIXY Sep 21 '16 at 05:29
  • 2
    The answers are 'yes' and 'no'; you need to free the inner allocated memory before freeing the outer (because you can't refer to the inner pointer via the outer after you've freed the outer). – Jonathan Leffler Sep 21 '16 at 05:29
  • 1
    It gets tricky deciding what to do. If it is C++ code, you shouldn't be using `malloc()` and `free()` — you use `new` and `delete` if you aren't using types that take care of memory allocation automatically. If it is not C++ code, it doesn't compile. If it is C++ code, the casts on the results from `malloc()` are necessary (assuming you use `malloc()` at all); if it is C, you don't need the casts, though they don't do much harm if you're careful. Waaah! – Jonathan Leffler Sep 21 '16 at 05:33
  • `x* foo;`...this compiles? – Sourav Ghosh Sep 21 '16 at 06:46
  • 1
    [Please see this discussion on why not to cast the return value of `malloc()` and family in `C`.](http://stackoverflow.com/q/605845/2173917). – Sourav Ghosh Sep 21 '16 at 06:46

3 Answers3

1

Just adding my two cents to elaborate on the why part.

Let's state two concepts first.

  1. You need to free()each memory allocated by memory allocator function to avoid memory leak.

  2. You need to pass the exact pointer returned by malloc() or family to free(). They do not have any hierarchical information stored into them (Like, "member of the structure" kind, each allocation is individual).

So, to reach the inner pointer member foo, you must access (dereference) the outer pointer tmp.

Now, if you free() the outer pointer tmp first, afterwards, accessing that free-d memory is invalid invokes undefined behavior. So, you have no way to reach the inner pointer to call free() on it. It remains allocated and contributes to memory leak.

That is why, you have to start freeing the memory from inside out.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
0

The first malloc will just allocate space for holding the members of y. Deleting it only deletes that allocated space. It has nothing to do with what you allocate afterwards. So yes, your assumption is correct.

nishantsingh
  • 4,537
  • 5
  • 25
  • 51
  • i was maybe thinking that free was smart enough to see if any of its members had more allocated memory...thank you – Yusuf Jama Sep 21 '16 at 05:21
0

You can follow this simple rule, every malloc call should have a corresponding free call, else consider the memory is not freed. The argument to free must be the value returned by corresponding malloc. Additionally, it is better to do a NULL check before passing the pointer to free.

In your example, struct real has struct x as it's member and struct x in turn has int *p as it's member. In your real code, you will also have to allocate memory for p and also free the memory when your usage is done.

Jay
  • 24,173
  • 25
  • 93
  • 141
  • Additionally, If there is a possibility that a given `p` can remain unallocated in your collection of `real` and `x`'s, you may want to protect your `free` with a check to insure `p` is not `NULL` (e.g. `if (p) free (p);`). (Jay, I know you know, this is for the questioner) – David C. Rankin Sep 21 '16 at 06:02
  • This answer does seem to imply that anything with regards to a needed `free` would be different if using C++ - It isn't. – tofro Sep 21 '16 at 06:50
  • @DavidC.Rankin & tofro, Hope I have addressed your comments in my recent edit. Thanks for your comments. : ) – Jay Sep 21 '16 at 16:56