Skip to content

Dynamic Memory Allocations

The memory is allocated at compile-time (known as static memory allocation) and size cannot be changed at runtime. DMA allows you to allocate memory at runtime (during program execution), and free it when no longer needed.

  • Memory is allocated on the heap (not stack).
  • Gives flexibility to allocate memory as per program needs.
  • You must free the memory manually after use, or you’ll create a memory leak.

C provides 4 main functions in <stdlib.h>:

FunctionPurpose
malloc()Allocates memory block.
calloc()Allocates memory block and initializes to zero.
realloc()Resizes previously allocated memory.
free()Frees allocated memory.
ptr = (cast_type*) malloc(size_in_bytes);
  • Allocates size_in_bytes of memory.
  • Returns a pointer to void (must be typecast).
  • Contents are uninitialized (garbage values).
int *ptr;
ptr = (int*) malloc(5 * sizeof(int)); // allocate memory for 5 integers
for(int i=0; i<5; i++)
ptr[i] = i+1;
for(int i=0; i<5; i++)
printf("%d ", ptr[i]);
free(ptr); // always free after use
  • If forget to call free(), the memory remains occupied → Memory Leak.
ptr = (cast_type*) calloc(n, size_of_each_element);
  • Allocates memory for n elements, each of size size_of_each_element.
  • Initializes all bytes to zero.
int *ptr;
ptr = (int*) calloc(5, sizeof(int)); // all values start as 0
for(int i=0; i<5; i++)
printf("%d ", ptr[i]); // prints 0 0 0 0 0
free(ptr);
  • When to use: Use calloc() when you want initialized memory.
ptr = (cast_type*) realloc(ptr, new_size_in_bytes);
  • Changes the size of previously allocated memory block.
  • Old values remain unchanged (up to the smaller of old/new size).
  • If it cannot expand in place, it allocates a new block and copies old data.
int *ptr = (int*) malloc(3 * sizeof(int));
ptr[0]=10; ptr[1]=20; ptr[2]=30;
ptr = (int*) realloc(ptr, 5 * sizeof(int)); // expand to 5 integers
ptr[3]=40; ptr[4]=50;
for(int i=0; i<5; i++)
printf("%d ", ptr[i]);
free(ptr);
  • Always check if realloc() returns NULL before using the new pointer.
free(ptr);
  • Deallocates memory previously allocated by malloc(), calloc(), or realloc().
  • Does not set pointer to NULL automatically (do it manually).
free(ptr);
ptr = NULL; // Best practice
  • Why set NULL: Accessing a freed pointer (dangling pointer) can crash the program.
  • Forgetting to free memory → Memory Leak.
  • Accessing memory after free() → Dangling Pointer.
  • Using malloc() without checking if it returned NULL.
  • Allocating less memory than required (e.g., forgetting sizeof(type)).
Best Practices from My 35+ Years of Experience
Section titled “Best Practices from My 35+ Years of Experience”
  • Always check return value of malloc()/calloc():
if(ptr == NULL) {
printf("Memory allocation failed!");
exit(1);
}
  • Always free memory when no longer needed.
  • For large programs, track allocations with comments or logs.
  • Use calloc() when you need zero-initialized memory (e.g., arrays).
  • Avoid memory leaks by setting ptr = NULL after free().
  • Never use uninitialized pointers with DMA.
  • Dynamic arrays (e.g., resizing array when data grows).
  • Linked lists, stacks, queues.
  • Trees and graphs.
  • Dynamic string handling (for unknown input sizes).
  • Loading large files dynamically.
  • Memory allocated as per need → saves memory.
  • Flexible – can resize using realloc().
  • Enables advanced data structures.
  • Manual management (forgetting free() causes leaks).
  • Slower than static allocation (because it uses heap).
  • Fragmentation in long-running programs.
#include <stdio.h>
#include <stdlib.h>
int main() {
int n;
printf("Enter number of elements: ");
scanf("%d", &n);
int *arr = (int*) malloc(n * sizeof(int));
if(arr == NULL) {
printf("Memory allocation failed!\n");
return 1;
}
for(int i=0; i<n; i++) {
printf("Enter element %d: ", i+1);
scanf("%d", &arr[i]);
}
printf("You entered: ");
for(int i=0; i<n; i++)
printf("%d ", arr[i]);
free(arr);
return 0;
}