Open Source Your Knowledge, Become a Contributor
Technology knowledge has to be shared and made accessible for free. Join the movement.
When a variable is declared compiler automatically allocates memory for it. This is known as compile time memory allocation or static memory allocation. Memory can be allocated for data variables after the program begins execution. This mechanism is known as runtime memory allocation or dynamic memory allocation.
The memory allocated at compile time is deallocated (i.e., the memory is released so that the same memory can be reused by other data) automatically at the end of the scope of the variable. In the example below the memory allocated for the variable i
will be deallocated when the closing brace (}
) of the statement block is encountered (considering no compiler optimization).
{
int i = 0;
}
C provides several functions in stdlib
library for dynamic memory allocation. It's easy to both use and misuse these functions. One should write a program following best coding practices when dynamic memory allocation library functions are used.
Memory Allocation With calloc
Given a number of objects to be allocated and size of each object calloc
allocates memory. calloc
returns a pointer to the first element of the allocated elements. If memory cannot be allocated, calloc
returns NULL
. If the allocation is successful, calloc
initializes all bits to 0.
#define NUMBER_OF_ELEMENTS 100
int32_t *parr = calloc(NUMBER_OF_ELEMENTS, sizeof(int32_t));
if (parr == NULL) /* Memory allocation fails */
{
printf("Couldn't allocate memory");
}
else /* Memory allocation successful */
{
printf("Memory allocation successful");
}
In the example above memory allocation of NUMBER_OF_ELEMENTS
32 bit integers is requested by calloc
. If the memory allocation is successful then parr
will point to the first element of the allocated memory. Using parr
the allocated memory can be used as array. All integers in the array pointed to by parr
is initialized to 0.
Memory Allocation With malloc
malloc
tries to allocate a given number of bytes and returns a pointer to the first address of the allocated region. If malloc
fails then a NULL
pointer is returned. malloc
doesn't initialize the allocated memory and reading them without initialization invokes undefined behaviour.
The above example of calloc
can be implemented as below with malloc
:
#define NUMBER_OF_ELEMENTS 100
int32_t *parr = malloc(NUMBER_OF_ELEMENTS * sizeof(int32_t));
if (parr == NULL) /* Memory allocation fails */
{
printf("Couldn't allocate memory");
}
else /* Memory allocation successful */
{
memset(parr, 0, NUMBER_OF_ELEMENTS * sizeof(parr[0]));
printf("Memory allocation successful");
}
To use the function memset
header file <string.h>
must be included. Given a pointer and number of bytes, memset
initializes all bytes to zero.
Memory Reallocation With realloc
Given a pointer to a previously allocated region and a size, realloc
deallocates previous region, allocates memory having the new size and copies old content into the new region upto the lesser of old and new sizes. realloc
returns a pointer to the first element of the allocated memory. If new memory allocation fails, old content isn't deallocated, the value of the old content is unchanged and realloc
return NULL
.
#define NUMBER_OF_ELEMENTS 100
int32_t *parr = calloc(NUMBER_OF_ELEMENTS, sizeof(int32_t));
if (parr == NULL) /* Memory allocation fails */
{
printf("Couldn't allocate memory");
}
else /* Memory allocation successful */
{
printf("Memory allocation successful\n");
parr = realloc(parr, (NUMBER_OF_ELEMENTS / 2) * sizeof(int32_t));
if (parr == NULL) /* Memory reallocation fails */
{
printf("Memory reallocation fails");
}
else /* Memory reallocation successful */
{
printf("Memory reallocation successful");
}
}
In the above example, realloc
is used to reduce the dynamic array size to half.
If the first parameter to realloc
is NULL
, then realloc
behaves like malloc
.
Deallocation Of Allocated Memory With free
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.
Warning: If the pointer passed to free
doesn't match to a memory region previously allocated by memory management function or is already passed to free
or realloc
to deallocate, then the behaviour is undefined.
It's a good practice to set the pointer value to NULL
once it is passed to free
to avoid accidentally triggered undefined behaviour.
Following example allocates dynamic memory, initializes array elements with random number, reduces the size of the array to half with realloc
and output before and after the reallocation proves that realloc
kept old values in the array.
Notice that regardless of how much bytes the whole array pointed to by parr
is taking, sizeof(parr)
equals to the size of a pointer variable in your platform.