×

Advanced Coding & Software Engineering Program

Duration: 1 Year (12 Months)

Join our premium 1-year program to master cutting-edge technologies and become an industry-ready Software Engineer!

Course Coverage

  • Languages: C, C++, Java, JavaScript, Python
  • Web Technologies: HTML, CSS, Bootstrap 5, MERN Stack, Full Stack Development
  • Databases: MySQL, MongoDB
  • Data Science Libraries: Pandas, NumPy
  • Development Tools: Visual Studio Code, IntelliJ IDEA, PyCharm, Postman, Git, GitHub
  • Cloud Platforms: Vercel, MongoDB Atlas

Program Highlights

  • Live Classes: Interactive sessions with real-time doubt resolution
  • Hands-On Sessions: Practical coding exercises to build real-world skills
  • Industry Experts: Learn from professionals with years of experience
  • Live Project: Work on real-world projects to apply your skills
  • Get Certificate: Earn a professional certificate upon program completion

Course Fee: Only ₹1020 / month
Limited Period Offer!

Dynamic Memory Allocation in C: From Basics to Advanced



Last Updated on: 25th Jul 2025 16:36:11 PM

Dynamic memory allocation in C is like renting space in a warehouse—you request exactly what you need, use it, and return it when done. Unlike static arrays with fixed sizes, dynamic memory allows programs to allocate memory at runtime, making them flexible and efficient. This tutorial covers malloc, calloc, realloc, and free, progressing from beginner-friendly concepts to advanced, real-life applications. Designed for your website, it features unique, engaging examples with user input via scanf and fgets to captivate students. Each example includes code, output, and a detailed explanation to ensure clarity and excitement. Let’s master dynamic memory allocation!

 

1. Introduction to Dynamic Memory Allocation

Dynamic memory allocation allows programs to request memory during execution, managed via the C standard library (<stdlib.h>). It’s essential for handling variable-sized data, such as user-defined arrays or complex structures.

 

Key Features:

  • Memory is allocated from the heap (unlike stack for local variables).

  • Functions: malloc, calloc, realloc, free.

  • Flexible sizing, but requires manual management to avoid leaks or errors.

 

Why Use Dynamic Memory Allocation?

  • Handle unknown data sizes (e.g., user-defined lists).

  • Optimize memory usage for large or sparse data.

  • Enable advanced data structures like linked lists or trees.

 

2. Dynamic Memory Allocation Functions

 

2.1. malloc

  • Syntax: void *malloc(size_t size);

  • Allocates size bytes of memory and returns a pointer to the first byte.

  • Memory is uninitialized (contains garbage values).

  • Returns NULL if allocation fails.

 

2.2. calloc

  • Syntax: void *calloc(size_t nmemb, size_t size);

  • Allocates memory for nmemb elements, each of size bytes, and initializes all bytes to zero.

  • Returns NULL if allocation fails.

 

2.3. realloc

  • Syntax: void *realloc(void *ptr, size_t size);

  • Resizes memory pointed to by ptr to size bytes, preserving existing data (up to the smaller of old and new sizes).

  • Returns a new pointer (may move memory) or NULL if resizing fails.

 

2.4. free

  • Syntax: void free(void *ptr);

  • Deallocates memory pointed to by ptr, preventing memory leaks.

  • Sets ptr to NULL after freeing to avoid dangling pointers.

 

3. Basic Dynamic Memory Allocation

 

Basic Example: Allocate and Store User Scores with malloc

This program allocates memory for user-specified exam scores and calculates their average.

#include <stdio.h>
#include <stdlib.h>
int main() {
    int n;
    printf("Enter number of scores: ");
    scanf("%d", &n);
    
    int *scores = (int *)malloc(n * sizeof(int));
    if (scores == NULL) {
        printf("Memory allocation failed!\n");
        return 1;
    }
    
    printf("Enter %d scores:\n", n);
    for (int i = 0; i < n; i++) {
        printf("Score %d: ", i + 1);
        scanf("%d", &scores[i]);
    }
    
    float sum = 0;
    for (int i = 0; i < n; i++) {
        sum += scores[i];
    }
    
    printf("\nScores: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", scores[i]);
    }
    printf("\nAverage: %.2f\n", sum / n);
    
    free(scores);
    scores = NULL;
    return 0;
}

 

Output (example user input: 3, 85, 90, 88):

Enter number of scores: 3
Enter 3 scores:
Score 1: 85
Score 2: 90
Score 3: 88

Scores: 85 90 88 
Average: 87.67

 

Explanation:

  • The user inputs the number of scores (n) using scanf.

  • malloc allocates memory for n integers, checked for NULL to ensure success.

  • Scores are input into the dynamic array scores and summed for the average.

  • free deallocates the memory, and scores is set to NULL to avoid dangling pointers.

 

4. Using calloc for Initialized Memory

 

Example: Allocate and Initialize Matrix with calloc

This program allocates a 2D matrix with user-specified rows, initializing it to zero using calloc.

#include <stdio.h>
#include <stdlib.h>
int main() {
    int rows;
    printf("Enter number of rows: ");
    scanf("%d", &rows);
    
    int **matrix = (int **)calloc(rows, sizeof(int *));
    if (matrix == NULL) {
        printf("Memory allocation failed!\n");
        return 1;
    }
    
    for (int i = 0; i < rows; i++) {
        matrix[i] = (int *)calloc(3, sizeof(int)); // 3 columns
        if (matrix[i] == NULL) {
            printf("Memory allocation failed!\n");
            for (int j = 0; j < i; j++) {
                free(matrix[j]);
            }
            free(matrix);
            return 1;
        }
    }
    
    printf("Enter elements for %dx3 matrix:\n", rows);
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < 3; j++) {
            printf("Element [%d][%d]: ", i, j);
            scanf("%d", &matrix[i][j]);
        }
    }
    
    printf("\nMatrix (initialized to 0, updated with input):\n");
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%4d", matrix[i][j]);
        }
        printf("\n");
    }
    
    for (int i = 0; i < rows; i++) {
        free(matrix[i]);
    }
    free(matrix);
    return 0;
}

 

Output (example user input: 2, {1, 2, 3}, {4, 5, 6}):

Enter number of rows: 2
Enter elements for 2x3 matrix:
Element [0][0]: 1
Element [0][1]: 2
Element [0][2]: 3
Element [1][0]: 4
Element [1][1]: 5
Element [1][2]: 6

Matrix (initialized to 0, updated with input):
   1   2   3
   4   5   6

 

Explanation:

  • The user inputs the number of rows (rows) using scanf.

  • calloc allocates an array of rows pointers, initialized to zero.

  • Each row is allocated as a 3-column array using calloc, also initialized to zero.

  • The user inputs matrix elements, overwriting the zeros.

  • Memory is freed for each row and the pointer array to prevent leaks.

 

5. Resizing Memory with realloc

 

Example: Dynamic List of Names with realloc

This program allows the user to input names, resizing the list dynamically using realloc.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
    int capacity = 2, count = 0;
    char **names = (char **)malloc(capacity * sizeof(char *));
    if (names == NULL) {
        printf("Memory allocation failed!\n");
        return 1;
    }
    
    char buffer[50];
    printf("Enter names (empty line to stop):\n");
    while (1) {
        printf("Name %d: ", count + 1);
        fgets(buffer, 50, stdin);
        buffer[strcspn(buffer, "\n")] = '\0';
        if (strlen(buffer) == 0) {
            break;
        }
        
        if (count >= capacity) {
            capacity *= 2;
            char **temp = (char **)realloc(names, capacity * sizeof(char *));
            if (temp == NULL) {
                printf("Memory reallocation failed!\n");
                for (int i = 0; i < count; i++) {
                    free(names[i]);
                }
                free(names);
                return 1;
            }
            names = temp;
        }
        
        names[count] = (char *)malloc((strlen(buffer) + 1) * sizeof(char));
        if (names[count] == NULL) {
            printf("Memory allocation failed!\n");
            for (int i = 0; i < count; i++) {
                free(names[i]);
            }
            free(names);
            return 1;
        }
        strcpy(names[count], buffer);
        count++;
    }
    
    printf("\nEntered Names:\n");
    for (int i = 0; i < count; i++) {
        printf("%d: %s\n", i + 1, names[i]);
    }
    
    for (int i = 0; i < count; i++) {
        free(names[i]);
    }
    free(names);
    return 0;
}

 

Output (example user input: Alice, Bob, Charlie, empty line):

Enter names (empty line to stop):
Name 1: Alice
Name 2: Bob
Name 3: Charlie
Name 4: 

Entered Names:
1: Alice
2: Bob
3: Charlie

 

Explanation:

  • The program starts with a capacity of 2 names, allocated using malloc.

  • fgets reads names, stopping when an empty line is entered.

  • If count reaches capacity, realloc doubles the capacity, preserving existing pointers.

  • Each name is dynamically allocated and copied using strcpy.

  • Memory is freed for each name and the pointer array to prevent leaks.

 

6. Advanced Example: Task Manager System

This real-life program simulates a task manager, using dynamic memory to store user-defined tasks with priorities and descriptions, allowing addition, display, and sorting by priority.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Task {
    char description[100];
    int priority; // 1 (high) to 5 (low)
};
void addTask(struct Task **tasks, int *count, int *capacity) {
    if (*count >= *capacity) {
        *capacity *= 2;
        struct Task *temp = (struct Task *)realloc(*tasks, *capacity * sizeof(struct Task));
        if (temp == NULL) {
            printf("Memory reallocation failed!\n");
            return;
        }
        *tasks = temp;
    }
    
    printf("Enter task description: ");
    fgets((*tasks)[*count].description, 100, stdin);
    (*tasks)[*count].description[strcspn((*tasks)[*count].description, "\n")] = '\0';
    
    printf("Enter priority (1=high, 5=low): ");
    scanf("%d", &(*tasks)[*count].priority);
    getchar(); // Clear newline
    
    (*count)++;
}
void sortTasks(struct Task *tasks, int count) {
    for (int i = 0; i < count - 1; i++) {
        for (int j = 0; j < count - i - 1; j++) {
            if (tasks[j].priority > tasks[j + 1].priority) {
                struct Task temp = tasks[j];
                tasks[j] = tasks[j + 1];
                tasks[j + 1] = temp;
            }
        }
    }
}
void displayTasks(struct Task *tasks, int count) {
    if (count == 0) {
        printf("No tasks available.\n");
        return;
    }
    printf("\nTask List (Sorted by Priority):\n");
    for (int i = 0; i < count; i++) {
        printf("Task %d: %s, Priority: %d\n", i + 1, tasks[i].description, tasks[i].priority);
    }
}
int main() {
    int capacity = 2, count = 0;
    struct Task *tasks = (struct Task *)calloc(capacity, sizeof(struct Task));
    if (tasks == NULL) {
        printf("Memory allocation failed!\n");
        return 1;
    }
    
    int choice;
    do {
        printf("\nTask Manager Menu:\n");
        printf("1. Add Task\n");
        printf("2. Display Tasks\n");
        printf("3. Exit\n");
        printf("Enter choice: ");
        scanf("%d", &choice);
        getchar(); // Clear newline
        
        switch (choice) {
            case 1:
                addTask(&tasks, &count, &capacity);
                sortTasks(tasks, count);
                break;
            case 2:
                displayTasks(tasks, count);
                break;
            case 3:
                printf("Exiting Task Manager.\n");
                break;
            default:
                printf("Invalid choice!\n");
        }
    } while (choice != 3);
    
    free(tasks);
    return 0;
}

 

Output (example user interaction):

Task Manager Menu:
1. Add Task
2. Display Tasks
3. Exit
Enter choice: 1

 

Enter task description: Finish report
Enter priority (1=high, 5=low): 2

 

Task Manager Menu:
1. Add Task
2. Display Tasks
3. Exit
Enter choice: 1

 

Enter task description: Call client
Enter priority (1=high, 5=low): 1

 

Task Manager Menu:
1. Add Task
2. Display Tasks
3. Exit
Enter choice: 2

 

Task List (Sorted by Priority):
Task 1: Call client, Priority: 1
Task 2: Finish report, Priority: 2

 

Task Manager Menu:
1. Add Task
2. Display Tasks
3. Exit
Enter choice: 3


Exiting Task Manager.

 

Explanation:

  • The Task structure stores a description and priority, allocated dynamically using calloc for initial zero initialization.

  • The addTask function uses realloc to resize the task array when capacity is reached, doubling it each time.

  • fgets and scanf input task details, with getchar() clearing newlines.

  • The sortTasks function sorts tasks by priority using bubble sort.

  • The displayTasks function shows the sorted task list.

  • Memory is freed at the end, modeling a real-life task manager system.

 

7. Why Dynamic Memory Allocation Is Essential

Dynamic memory allocation in C is critical for:

  • Flexible Data Handling: Manage variable-sized data like lists or matrices.

  • Efficient Resource Use: Allocate only what’s needed at runtime.

  • Advanced Data Structures: Support linked lists, trees, and graphs.

 

Pro Tip: Experiment with these examples! Try extending the task manager to delete tasks, add a search function, or create a dynamic string tokenizer. Dynamic memory allocation is your key to scalable programming!

Happy coding

 


Online - Chat Now
Let’s Connect

Inquiry Sent!

Your message has been successfully sent. We'll get back to you soon!

iKeySkills Logo