Dynamic Memory Management Introduction.
C provides a way to allocate memory at runtime. This is done with the help of DMM.
This is a very important feature in C language, and yet programmers seldom makes mistake while writing a program resulting in program crash.
Different types of Dynamic Memory Allocation functions
There are 3 different types of functions to allocate memory
1. malloc : It will allocate memory in heap. It will not memset the memory to 0.
2. calloc : It will allocate memory in heap and will memset that memory to zero.
3. realloc : It will reallocate memory to a larger or smaller memory already allocated memory
There is one function to free a memory:
1. free : It will return the allocated memory back to heap.
Example 1:
Allocate memory using malloc :
Function prototype of malloc:
void* malloc(size_t);
Example:
int *ptr = (int*) malloc(sizeof(int));
If the memory is allocated, it will return the address of allocated memory. As it is a void pointer, we need to type cast it to the type of data type of memory allocated.
If the memory is not allocated, then it will return NULL.
Example:
#include<stdio.h>
#include<stdlib.h>
int main ()
{
int *ptr = (int *) malloc(sizeof(int));
*ptr = 20;
printf("The value of ptr = %d\n", *ptr);
free(ptr);
ptr = NULL;
return 0;
}
The value of ptr = 20
Example 2:
Allocate memory using calloc :
Function prototype of calloc:
void *calloc(size_t numElements, size_t elementSize);
#include<stdio.h>
#include<stdlib.h>
int main ()
{
int *ptr = (int *) calloc( 1 , sizeof(int));
*ptr = 20;
printf("The value of ptr = %d\n", *ptr);
free(ptr);
ptr = NULL;
return 0;
}
Output:
The value of ptr = 20
Example 3:
Allocate memory using realloc :
Function prototype of realloc:
void *realloc(void *ptr, size_t size);
#include<stdio.h>
#include<stdlib.h>
int main ()
{
int *ptr = (int *) calloc( 1 , sizeof(int));
ptr = (int *) realloc( ptr , sizeof(int));
*ptr = 20;
printf("The value of ptr = %d\n", *ptr);
free(ptr);
ptr = NULL;
return 0;
}
Output:
The value of ptr = 20
Below are the steps for allocating memory dynamically:
1. Create a pointer to store the address.
2. Use malloc() or calloc() to create a dynamic memory.
3. Assign the return address to a pointer.
4. Use that memory to store some values.
5. Free the memory after using it.
6. Point that pointer variable to NULL after freeing.
Below is a code snippet for the same:
int *ptr = (int*) malloc(10);
*ptr = 15;
free(prt);
ptr = NULL;
If the malloc gets the space it will return a pointer to a memory location else it will return NULL value.
Once memory is freed, you should not use the same memory again. It will result in dangling pointer, discussed later in this chapter. To prevent this we should assign pointer to NULL.
Below is the generic error made by programmer:
int *ptr;
*ptr = (int*) malloc(10);
The problem here is, the address returned by the malloc function will be stored in the address pointed by “ptr”. But “ptr” is not pointing to any valid address. Hence this is an error.
Hence we should not use dereferencing operator, and can be corrected as shown below:
ptr = (int *) malloc(10);
Memory Corruption:
Accessing a memory that is out of the allocated memory is called as memory corruption.
Below is a simple example how a memeory corruption occurs.
char *ptr = (char*)malloc(4);
for(i = 0 ; i <= 6; i++)
{
*ptr[i] = 0;
}
In the above program, I am allocating 4 bytes space including for a NULL character. But in the for loop, I am accessing memory beyond allocated memory. This will result in Memory Corruption.
Memory Leaks:
This situation happens, when a memory is allocated, but not deallocated.
The problem here is, when a huge piece of heap memory is used and not de-allocated, when the program needs more heap memory it will not be available to the program. This will make the progrm to crash.
Below is an example code:
int *ptr;
for(i=0; i< 299; i++)
{
ptr = (int*) malloc(20000000);
}
eventually, the program will run out of space then crash.
Loosing the allocated address:
This situation happens when we loose the allocated memory address. This situation happens when a new memory space is allocated, without freeing the previous memory.
Example:
int *ptr = (int *)malloc(3000);
ptr = (int *)malloc(47883);
Here the first memory allocated address is lost.
Deallocating memory using free function:
free() is used to de-allocate the memory. It should be used whenn programmer is no longer using the allocated memory. The freed memory will be released back to heap for further alloacation.
free() prototype:
void free(void *ptr);
Example for free:
int *ptr = (int *)malloc(18);
....
...
free(ptr);
Dangling pointer:
In the above de-allocation there is a problem of Dangling pointer. As the programmer has deallocated the memory but the variable “ptr” still holds the deallocated memory address.
This will lead to segmentation fault or improper utilization of memory in a program.
Below is an example of Dangling pointer:
int *ptr = (int *) malloc(1000);
*ptr = 10;
....
...
free(ptr);
.....
....
*ptr = 45;
Example 2:
When a programmer assigns one pointer address to another pointer, then he frees the first pointer.
int *ptr = (int*) malloc(19);
int *ptr_2 = NULL;
ptr_2 = ptr;
....
...
free(ptr);
....
...
*ptr_2 = 8; //Dangling pointer
Example 3:
When a programmer assigns the local variable address to a global pointer. After the function scope, the local variable address is not valid. Making pointer variable address as a dangling pointer.
int *ptr;
void example()
{
int number = 10;
ptr = &number;
}
//ptr here is a dangling pointer.
Double Free Error:
This occurs when trying to free a memory block that has already been freed.
Example 1:
When freeing same pointer twice
int *ptr = (int *)malloc(10);
....
...
free(ptr);
....
...
free(ptr);
Example 2:
When we are trying to free same memory location twice holding by 2 different pointers.
int *ptr = (int *)malloc(10);
int *ptr_2 = ptr;
free(ptr);
....
...
free(ptr_2);
Using malloc with static pointers
What happens if you allocate to a global static pointer as below:
static int *pi = malloc(sizeof(int));
WKT a static variable is initialized by C, before any function is called.
Because of this, the variables have to be a constant-expression.
Hence you will get an linker error.