0

I know that realloc will free memory when necessary, and I know the third rule of C - "for every malloc there must be an equal and opposite free"... but how do these two work together?

The situation is best described in code:

int main()
{
    myStruct **myStructArray;
    int      i, num_elements;

    num_elements = getnumber(); // gets value for num_elements

    myStructArray = (myStruct **) malloc(num_elements * sizeof(myStruct*));
    for (i=0; i<num_elements; i++)
        myStructArray[i] = (myStruct *) malloc(sizeof(myStruct));

    // so far so good...

    num_elements = getnumber(); // gets new, LOWER value

    myStructArray = realloc(myStructArrary, num_elements * sizeof(myStruct*));

    // rest_of_code, and necessary free loop for myStructArray etc...
}

Obviously the above is nothing more than a snippet, but a snippet paints a thousand words.

Would this create a memory leak? I know the call to realloc will free the pointers' memory, but I can see arguments for and against the possibility that there is still going to be a bunch of memory forgotten about.

A leak can be circumvented by incorporating int number_elements_new into the code and loop free-ing the surplus myStructs before calling realloc to free the (now NULL) pointers.

If realloc does the donkeywork and frees up ALL the associated memory that's great, otherwise I've got to trawl through to make sure nothing has been missed - myStruct itself contains allocated memory and so on.

Thank you for your recommendations...

  • I don't see what you mean here. Are you asking if `realloc()` will free the pointers that the array you `malloc()`ed too, and not just its argument? Because then no, it doesn't. –  Jan 25 '13 at 14:25
  • How do you imagine that it wouldn't leak memory? You still need to free the elements you allocated regardless of if they are in an array or not. – Art Jan 25 '13 at 14:25
  • 2
    Please don't [cast the return value of `malloc()` and `realloc()` in C](http://stackoverflow.com/a/605858/28169). – unwind Jan 25 '13 at 14:28
  • `realloc` doesn't count in the rule, since it takes an existing `malloc`-ed pointer and returns a new one, while freeing up any memory in the event of a reallocation. – Kerrek SB Jan 25 '13 at 14:32
  • @unwind: force of habit from too much c++, my mistake! – CharlieHanson Jan 25 '13 at 15:05

3 Answers3

6

malloc, realloc and free have no idea about what the memory is being used for. If you're using the memory to store pointers to other dynamically-allocated memory, then that's for you to tidy up!


Also, note that the way you're using realloc in your code snippet is potentially unsafe. If realloc fails, it leaves the original memory un-freed, and returns NULL. Best practice is to assign the return value to a temporary pointer, and then check. See e.g. http://www.c-faq.com/malloc/realloc.html.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • Suggestion: moreover, no type of malloc allocation tracks pointers stored in that memory; they *always* have to be freed. – Dariusz Jan 25 '13 at 14:27
0

If the number is lower than the existing number of elements, you will introduce a memory leak as the reallocated block is not related to the content and you are losing your reference to the blocks allocated in the for-loop.

Therefore you'll have to loop through your array and free all elements that will be subject to removed.

If the number is higher than the existing number, it won't create a memory leak as realloc copies the existing data if a new memory block has been allocated. Therefore your other dynamically allocated blocks (malloc in the for loop) are still referenced by the resized array. The only gotcha here is, that the newly allocated array spaces are uninitialized and can therefore contain invalid pointers.

junix
  • 3,161
  • 13
  • 27
0

If you're shrinking the size of your array, you would first need to free each myStructArray[i] where i >= num_elements, otherwise you will have a memory leak.

Put another way, shrinking the size of the pointer array does not affect the memory that each array element was pointing to.

Also, in the realloc call, you will want to assign the result to a temporary pointer; if realloc cannot extend or shrink the buffer, it will return NULL, and you'll lose your reference to that block, which will also introduce a leak:

myStruct **tmp = realloc(myStructArray, ...);
if (tmp)
{
  myStructArray = tmp;
  ...
}
John Bode
  • 119,563
  • 19
  • 122
  • 198