With the free function the coder can return memory when this memory is no longer needed. The prototype of the function is:
void free(void *ptr);
Free function should be used to deallocate memory that was allocated by a malloc type function. When using free function the memory is returned to the heap but the pointer may still point to the original region. So you should assume that the pointer points to garbage after using free function.
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int *ptr;
ptr = (int *) malloc(sizeof(int));
*ptr = 10;
printf("%d, %p", *ptr, ptr);
free(ptr);
return (0);
}
The image below illustrates what is happening when executing the code above, especially the situation before and after using the free function.
In the example below, I show the wrong use:
#include <stdlib.h>
int main(void)
{
int *ptr;
int number;
ptr = (int *) malloc(sizeof(int));
number = 10;
ptr = &number;
free(ptr);
return (0);
}
Terminal> gcc free.c
free.c: In function ‘main’:
free.c:11:9: warning: ‘free’ called on unallocated object ‘number’ [-Wfree-nonheap-object]
11 | free(ptr);
| ^~~~~~~~~
free.c:6:17: note: declared here
6 | int number;
| ^~~~~~
Assigning NULL to a freed pointer
When you dereference a freed pointer, its behavior is undefined. That’s why some coders assign NULL to a pointer to mark the pointer as invalid.
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int *ptr;
ptr = (int *) malloc(sizeof(int));
*ptr = 10;
printf("Before free\nValue: %d, adress %p\n\n", *ptr, ptr);
free(ptr);
printf("Address of ptr after free: %p\n", ptr);
ptr = NULL;
printf("Address of ptr after ptr = NULL, address of ptr: %p\n", ptr);
return (0);
}
Terminal> gcc free.c
Terminal> ./a.out
Before free
Value: 10, adress 0x55d23d96c2a0
Address of ptr after free: 0x55d23d96c2a0
Address of ptr after ptr = NULL, address of ptr: (nil)
This technique is useful for fighting against problems like dangling pointer. It is advised to invest time addressing the conditions which caused such problems. Remember that you cannot assign NULL to a constant pointer.
Double free
In the following example you can see what happens when you attempt to free a block of memory twice.
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int *ptr1;
int *ptr2;
ptr1 = (int *) malloc(sizeof(int));
ptr2 = (int *) malloc(sizeof(int));
*ptr1 = 10;
ptr2 = ptr1;
free(ptr1);
free(ptr2);
return (0);
}
Terminal> gcc doublefree.c
Terminal> ./a.out
free(): double free detected in tcache 2
fish: Job 1, './a.out' terminated by signal SIGABRT (Abort)
The execution of the second free results in runtime exception.
In the example below you can see what happens when we do only:
free(ptr1);
It is called “aliasing” when two pointers reference the same location. It is difficult for heap managers to determine when the two pointers reference to the same location and wheter this block of memory was deallocated. So if we free two times the same memory, normally it results in corrupt heap and program termination. In general there is no reason to free the same memory twice.
SOURCES:
[1] Understanding and Using C Pointers by Richard Reese (O’Reilly). Copyright 2013 Richard Reese, Ph.D. 978-1-449-34418-4