Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Freeing pointers from inside other functions in C

Consider the c code:

void mycode() {
  MyType* p = malloc(sizeof(MyType));
  /* set the values for p and do some stuff with it */
  cleanup(p);
}


void cleanup(MyType* pointer) {
  free(pointer);
  pointer = NULL;
}

Am I wrong in thinking that after cleanup(p); is called, the contents of p should now be NULL? Will cleanup(MyType* pointer) properly free the memory allocation?

I am coding my college assignment and finding that the debugger is still showing the pointer to have a memory address instead of 0x0 (or NULL) as I expect.

I am finding the memory management in C to be very complicated (I hope that's not just me). can any shed some light onto what's happening?

like image 641
Ash Avatar asked May 19 '11 05:05

Ash


People also ask

Can you free a pointer in C?

The function free takes a pointer as parameter and deallocates the memory region pointed to by that pointer. The memory region passed to free must be previously allocated with calloc , malloc or realloc . If the pointer is NULL , no action is taken.

Can you use a pointer after freeing it?

Yes, when you use a free(px); call, it frees the memory that was malloc'd earlier and pointed to by px. The pointer itself, however, will continue to exist and will still have the same address. It will not automatically be changed to NULL or anything else.

Do function pointers need to be freed?

No. You must not because free(ptr) is used only when pointer ptr is previously returned by any of malloc family functions. Passing free a pointer to any other object (like a variable or array element) causes undefined behaviour.


4 Answers

This won't work as the pointer in cleanup() is local, and thus assigning it NULL is not seen by the calling function. There are two common ways of solving this.

  1. Instead of sending cleanup the pointer, send it a pointer to the pointer. Thus change cleanup() as follows:
void cleanup(MyType** pointer)
{
  free(*pointer);
  *pointer = NULL;
}

and then just call cleanup(&p).

  1. A second option which is quite common is to use a #define macro that frees the memory and cleans the pointer.

If you are using C++ then there is a third way by defining cleanup() as:

void cleanup(MyType& *pointer) { // your old code stays the same }

like image 174
Dov Grobgeld Avatar answered Oct 04 '22 07:10

Dov Grobgeld


Yes that will free the memory correctly.

pointer inside the cleanup function is a local variable; a copy of the value passed in stored locally for just that function.

This might add to your confusion, but you can adjust the value of the variable p (which is local to the mycode method) from inside the cleanup method like so:

void cleanup(MyType** pointer) {
  free(*pointer);
  *pointer = NULL;
}

In this case, pointer stores the address of the pointer. By dereferencing that, you can change the value stored at that address. And you would call the cleanup method like so:

cleanup(&p);

(That is, you want to pass the address of the pointer, not a copy of its value.)

I will note that it is usually good practice to deal with allocation and deallocation on the same logical 'level' of the software - i.e. don't make it the callers responsibility to allocate memory and then free it inside functions. Keep it consistent and on the same level.

like image 22
sje397 Avatar answered Oct 13 '22 12:10

sje397


cleanup will properly free p, but it won't change its value. C is a pass-by-value language, so you can't change the caller's variable from the called function. If you want to set p from cleanup, you'll need to do something like:

void cleanup(MyType **pointer) {
  free(*pointer);
  *pointer = NULL;
}

And call it like:

cleanup(&p);

Your code is a little bit un-idiomatic, can you explain a bit better why you want to write this cleanup function?

like image 13
Carl Norum Avatar answered Oct 13 '22 12:10

Carl Norum


Yes

Yes

Yes: There is a block of memory magically produced by malloc(3). You have assigned the address of this memory, but not the memory itself in any meaningful way, to the pointer p which is an auto variable in mycode().

Then, you pass p to cleanup(), by value, which will copy the pointer and, using the copy local to cleanup(), free the block. cleanup() then sets it's own instance of the pointer to NULL, but this is useless. Once the function is complete the parameter pointer ceases to exist.

Back in mycode(), you still have pointer p holding an address, but the block is now on the free list and not terribly useful for storage until allocated again.

You may notice that you can even still store to and read back from *p, but various amounts of downstream lossage will occur, as this block of memory now belongs to the library and you may corrupt its data structures or the data of a future owner of a malloc() block.

Carefully reading about C can give you an abstract idea of variable lifetime, but it's far easier to visualize the near-universal (for compiled languages, anyway) implementation of parameter passing and local variable allocation as stack operations. It helps to take an assembly course before the C course.

like image 6
DigitalRoss Avatar answered Oct 13 '22 10:10

DigitalRoss