SrcForge

Lesson 25

Dynamic Memory Management

Dynamic Memory Management is the process of allocating and releasing memory during program execution using malloc(), calloc(), realloc(), and free(). Unlike static allocation, dynamic allocation allows programs to request memory at runtime and release it when no longer needed.

C Track

Save progress as you learn.

44 lessons

Lesson content

Dynamic Memory Management in C Programming: A Complete Beginner to Advanced Guide

What is Dynamic Memory Management in C Programming?

Dynamic Memory Management is the process of allocating and releasing memory during program execution (runtime) instead of at compile time.

Unlike static memory allocation, where the size of variables is fixed, dynamic memory allocation allows programs to request memory whenever needed and release it when it is no longer required.

For example, if a program needs to store the marks of an unknown number of students entered by the user, dynamic memory allocation is the ideal solution.

Think of dynamic memory like booking hotel rooms: you reserve only the number of rooms you need and check out when you're done, making efficient use of available resources.

Why Does Dynamic Memory Management Exist?

In many applications, the amount of memory required is not known until the program runs. Dynamic memory management helps to:

  • Allocate memory when needed
  • Reduce memory wastage
  • Handle variable-sized data
  • Create dynamic data structures
  • Improve program flexibility

Real-World Use Cases

Dynamic memory management is widely used in:

  • Linked lists
  • Stacks and queues
  • Trees and graphs
  • Dynamic arrays
  • Database systems
  • File processing
  • Operating systems
  • Game development
  • Embedded systems

Prerequisites

Before learning Dynamic Memory Management in C Programming, you should know:

  • Variables
  • Data types
  • Arrays
  • Pointers
  • Functions
  • Structures (recommended)

Core Concepts of Dynamic Memory Management

Static vs Dynamic Memory Allocation

FeatureStatic MemoryDynamic Memory
Allocation TimeCompile timeRuntime
Memory SizeFixedFlexible
Managed ByCompilerProgrammer
Memory AreaStackHeap
Resize PossibleNoYes

What is the Heap?

The heap is a region of memory used for dynamic allocation. Memory allocated from the heap:

  • Exists until explicitly released
  • Can be resized
  • Must be freed manually using free()

Dynamic Memory Functions

All dynamic memory functions are declared in:

#include <stdlib.h>

The four primary functions are:

FunctionPurpose
malloc()Allocates uninitialized memory
calloc()Allocates and initializes memory to zero
realloc()Changes the size of previously allocated memory
free()Releases allocated memory

1. malloc()

The malloc() (Memory Allocation) function allocates a block of memory.

Syntax

pointer = (data_type *)malloc(number_of_elements * sizeof(data_type));
int *ptr = (int *)malloc(5 * sizeof(int));

If allocation fails, malloc() returns NULL.

2. calloc()

The calloc() (Contiguous Allocation) function allocates memory for multiple elements and initializes all bytes to zero.

Syntax

pointer = (data_type *)calloc(number_of_elements, sizeof(data_type));
int *ptr = (int *)calloc(5, sizeof(int));

3. realloc()

The realloc() function changes the size of an existing memory block.

Syntax

pointer = realloc(pointer, new_size);
ptr = realloc(ptr, 10 * sizeof(int));

If successful, the returned pointer may be the same as or different from the original.

4. free()

The free() function releases previously allocated memory.

Syntax

free(pointer);
free(ptr);

ptr = NULL;

Setting the pointer to NULL after freeing helps prevent accidental use of a dangling pointer.

Code Examples

Example 1: Beginner – Allocate Memory Using malloc()

#include <stdio.h>                      // Include standard input/output library
#include <stdlib.h>                     // Include memory allocation functions

int main(void)                          // Program entry point
{
    int *ptr;                           // Declare a pointer

    ptr = (int *)malloc(sizeof(int));   // Allocate memory for one integer

    if (ptr == NULL)                    // Check whether allocation failed
    {
        printf("Memory allocation failed.\n"); // Print an error message

        return 1;                       // Exit with an error code
    }

    *ptr = 100;                         // Store a value in the allocated memory

    printf("Value = %d\n", *ptr);       // Print the stored value

    free(ptr);                          // Release the allocated memory

    ptr = NULL;                         // Avoid a dangling pointer

    return 0;                           // End the program
}

Output: Value = 100

Example 2: Beginner – Allocate an Array Using calloc()

#include <stdio.h>                      // Include standard input/output library
#include <stdlib.h>                     // Include memory allocation functions

int main(void)                          // Program entry point
{
    int *numbers;                       // Declare a pointer

    numbers = (int *)calloc(5, sizeof(int)); // Allocate memory for five integers

    if (numbers == NULL)                // Check for allocation failure
    {
        printf("Memory allocation failed.\n"); // Print an error message

        return 1;                       // Exit with an error code
    }

    for (int i = 0; i < 5; i++)         // Loop through the array
    {
        printf("%d ", numbers[i]);      // Print each element (initialized to zero)
    }

    printf("\n");                       // Move to the next line

    free(numbers);                      // Release the allocated memory

    numbers = NULL;                     // Avoid a dangling pointer

    return 0;                           // End the program
}

Output: 0 0 0 0 0

Example 3: Intermediate – Resize Memory Using realloc()

#include <stdio.h>                              // Include standard input/output library
#include <stdlib.h>                             // Include memory allocation functions

int main(void)                                  // Program entry point
{
    int *numbers;                               // Declare a pointer

    numbers = (int *)malloc(3 * sizeof(int));   // Allocate memory for three integers

    if (numbers == NULL)                        // Check for allocation failure
    {
        return 1;                               // Exit if allocation fails
    }

    for (int i = 0; i < 3; i++)                 // Initialize the first three elements
    {
        numbers[i] = (i + 1) * 10;              // Store values
    }

    int *temp = realloc(numbers, 5 * sizeof(int)); // Request a larger block

    if (temp == NULL)                           // Check whether reallocation failed
    {
        free(numbers);                          // Free the original block

        return 1;                               // Exit with an error code
    }

    numbers = temp;                             // Update the pointer

    numbers[3] = 40;                            // Store new values
    numbers[4] = 50;

    for (int i = 0; i < 5; i++)                 // Print all elements
    {
        printf("%d ", numbers[i]);
    }

    printf("\n");                               // Move to the next line

    free(numbers);                              // Release the memory

    numbers = NULL;                             // Avoid a dangling pointer

    return 0;                                   // End the program
}

Example 4: Intermediate – Dynamic Array Based on User Input

#include <stdio.h>                              // Include standard input/output library
#include <stdlib.h>                             // Include memory allocation functions

int main(void)                                  // Program entry point
{
    int n;                                      // Number of elements

    printf("Enter the number of elements: ");   // Prompt the user

    scanf("%d", &n);                            // Read the number of elements

    int *array = (int *)malloc(n * sizeof(int)); // Allocate memory

    if (array == NULL)                          // Check for allocation failure
    {
        printf("Memory allocation failed.\n");  // Print an error message

        return 1;                               // Exit
    }

    for (int i = 0; i < n; i++)                 // Read array elements
    {
        printf("Enter element %d: ", i + 1);

        scanf("%d", &array[i]);
    }

    printf("Array elements: ");                 // Print a heading

    for (int i = 0; i < n; i++)                 // Display the array
    {
        printf("%d ", array[i]);
    }

    printf("\n");                               // Move to the next line

    free(array);                                // Release the memory

    array = NULL;                               // Avoid a dangling pointer

    return 0;                                   // End the program
}

Example 5: Advanced – Dynamic Structure Allocation

#include <stdio.h>                              // Include standard input/output library
#include <stdlib.h>                             // Include memory allocation functions

struct Student                                  // Define a structure
{
    int rollNo;                                 // Student roll number
    float marks;                                // Student marks
};

int main(void)                                  // Program entry point
{
    struct Student *student;                    // Pointer to a structure

    student = (struct Student *)malloc(sizeof(struct Student)); // Allocate memory

    if (student == NULL)                        // Check for allocation failure
    {
        return 1;                               // Exit if allocation fails
    }

    student->rollNo = 101;                      // Assign the roll number

    student->marks = 95.5f;                     // Assign the marks

    printf("Roll No: %d\n", student->rollNo);   // Print the roll number

    printf("Marks: %.1f\n", student->marks);    // Print the marks

    free(student);                              // Release the allocated memory

    student = NULL;                             // Avoid a dangling pointer

    return 0;                                   // End the program
}

Common Mistakes and Pitfalls

WrongCorrect
Using memory without checking NULLCheck if allocation succeeded before use
Forgetting to call free()Release allocated memory when no longer needed
Using memory after free()Set the pointer to NULL and avoid dereferencing it
Losing the original pointer returned by malloc()Store the result of realloc() in a temporary pointer before assigning
Allocating the wrong amount of memoryUse sizeof(*pointer) or sizeof(data_type) correctly

Wrong:

int *ptr = malloc(sizeof(int));

free(ptr);

*ptr = 10;

Correct:

int *ptr = malloc(sizeof(int));

if (ptr != NULL)
{
    *ptr = 10;

    free(ptr);

    ptr = NULL;
}

Best Practices

  • Always include <stdlib.h> for dynamic memory functions.
  • Check the return value of malloc(), calloc(), and realloc() before using the memory.
  • Release every dynamically allocated block with free().
  • Set pointers to NULL after calling free().
  • Use sizeof(*pointer) to make allocation expressions easier to maintain.
  • Use a temporary pointer when calling realloc() to avoid losing the original memory block if reallocation fails.
  • Allocate only the memory you need and free it as soon as it is no longer required.

When NOT to Use This

Avoid dynamic memory allocation when:

  • The required memory size is known at compile time.
  • Small local variables or fixed-size arrays are sufficient.
  • Performance is critical and frequent allocations/deallocations would add unnecessary overhead.
  • The program has strict memory constraints and allocation failures cannot be tolerated without careful handling.

In these situations, automatic (stack) allocation is often simpler and more efficient.

Summary / Key Takeaways

  • Dynamic Memory Management in C programming allocates memory at runtime.
  • Dynamic memory is allocated from the heap.
  • malloc() allocates uninitialized memory.
  • calloc() allocates zero-initialized memory.
  • realloc() resizes an existing memory block.
  • free() releases allocated memory.
  • Always check allocation results for NULL.
  • Free dynamically allocated memory to prevent memory leaks.
  • Avoid using pointers after they have been freed.
  • Proper memory management is essential for writing efficient and reliable C programs.

FAQ About Dynamic Memory Management in C

1. What is dynamic memory management in C?

Dynamic memory management is the process of allocating and releasing memory during program execution using functions such as malloc(), calloc(), realloc(), and free().

2. What is the difference between malloc() and calloc()?

malloc()calloc()
Allocates a single block of memoryAllocates memory for multiple elements
Memory is uninitializedMemory is initialized to zero
Takes one size argumentTakes the number of elements and the size of each element

3. Why should I check if malloc() returns NULL?

If memory allocation fails, malloc() returns NULL. Dereferencing a NULL pointer results in undefined behavior, so always verify that allocation succeeded before using the memory.

4. Why should I set a pointer to NULL after calling free()?

Setting a pointer to NULL helps prevent accidental access to freed memory through that pointer, reducing the risk of using a dangling pointer.

5. What happens if I forget to call free()?

The allocated memory remains reserved until the program terminates, resulting in a memory leak. In long-running applications, memory leaks can gradually consume available memory and degrade performance or cause failures.

Prev: RecursionBack to hub