-->

C Programming Day 12: Dynamic Memory Allocation in C | malloc(), calloc(), realloc(), free()

C Programming Day 12

Final Practical Projects

C Programming Day 12 Dynamic Memory Allocation in C tutorial





    Introduction

    C Programming Day 12 — Dynamic Memory Allocation in C: malloc(), calloc(), realloc(), free() & Final Practical Projects

    Welcome to Day 12 of the C Programming Full Course.

    Congratulations! 🎉 You have reached the final major lesson in this C Programming learning journey.

    In the previous lesson, you learned about File Handling in C and how programs can store information permanently using files. Today, we will go one step deeper and learn how C programs can manage memory dynamically during program execution.

    In this lesson, you will learn Dynamic Memory Allocation in C using malloc(), calloc(), realloc(), and free(). You will also learn about dynamic arrays, memory leaks, dangling pointers, and practical C programming projects.


    What is Dynamic Memory Allocation?

    Dynamic Memory Allocation is the process of requesting memory while a program is running.

    Instead of deciding the exact amount of memory in advance, a program can request memory when it is needed.

    #include <stdlib.h>
    
    int *numbers;
    
    numbers = malloc(5 * sizeof(int));

    In this example, the program requests enough memory to store five integers.


    Why Do We Need Dynamic Memory?

    Consider the following fixed-size array:

    int numbers[1000];

    This creates space for 1,000 integers even if the program only needs a few elements.

    With dynamic memory allocation, the program can determine the required size during execution.

    int *numbers;
    
    numbers = malloc(size * sizeof(int));

    This approach is especially useful when the required amount of data is not known before the program starts.


    Static vs Dynamic Memory

    Feature Fixed Array Dynamic Memory
    Size Usually fixed Can be determined at runtime
    Flexibility Limited High
    Allocation Array declaration malloc(), calloc(), realloc()
    Resizing Not directly possible realloc() can resize an allocation
    Release Automatic for local arrays Use free() for allocated memory


    Stack and Heap Memory

    To understand dynamic memory allocation, you should know the basic difference between stack and heap storage.

    Stack Memory

    Local variables commonly have automatic storage duration.

    void example()
    {
        int x = 10;
    }

    When the function finishes, its local automatic objects cease to exist.

    Heap Memory

    Dynamic allocation obtains storage from an area commonly called the heap.

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

    The allocated storage remains available until it is released using free().


    The stdlib.h Header

    The dynamic memory allocation functions are declared in the standard library header:

    #include <stdlib.h>

    A typical program using dynamic memory may therefore begin with:

    #include <stdio.h>
    #include <stdlib.h>


    malloc() in C

    malloc() stands for memory allocation. It allocates a specified number of bytes.

    Syntax:

    malloc(number_of_bytes);

    Example:

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

    This requests enough storage for one integer object.


    Understanding sizeof

    Instead of manually assuming the size of a data type, use the sizeof operator.

    sizeof(int)

    For an array of 10 integers:

    10 * sizeof(int)

    A better general pattern is:

    int *numbers = malloc(10 * sizeof(*numbers));


    Basic malloc() Example

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        int *ptr;
    
        ptr = malloc(sizeof(int));
    
        if(ptr == NULL)
        {
            printf("Memory allocation failed.\n");
            return 1;
        }
    
        *ptr = 100;
    
        printf("Value = %d\n", *ptr);
    
        free(ptr);
    
        return 0;
    }

    Here, ptr stores the address of dynamically allocated memory, and *ptr accesses the integer stored there.


    malloc() for Multiple Elements

    Suppose you need memory for five integers:

    int *numbers;
    
    numbers = malloc(5 * sizeof(*numbers));

    You can access the allocated elements using array notation:

    numbers[0]
    numbers[1]
    numbers[2]
    numbers[3]
    numbers[4]

    Example

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        int *numbers;
        int i;
    
        numbers = malloc(5 * sizeof(*numbers));
    
        if(numbers == NULL)
        {
            printf("Memory allocation failed.\n");
            return 1;
        }
    
        for(i = 0; i < 5; i++)
        {
            numbers[i] = (i + 1) * 10;
        }
    
        for(i = 0; i < 5; i++)
        {
            printf("%d ", numbers[i]);
        }
    
        free(numbers);
    
        return 0;
    }

    Output:

    10 20 30 40 50


    Important: malloc() Does Not Initialize Memory

    Memory returned by malloc() has indeterminate values. You should not assume that allocated integers automatically contain zero.

    If you need specific initial values, initialize the elements yourself or use calloc() when zero-initialized storage is appropriate.


    calloc() in C

    calloc() stands for contiguous allocation.

    Syntax:

    calloc(number_of_elements, size_of_each_element);

    Example:

    int *numbers;
    
    numbers = calloc(5, sizeof(*numbers));

    The allocated bytes are initialized to zero.

    calloc() Example

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        int *numbers;
        int i;
    
        numbers = calloc(5, sizeof(*numbers));
    
        if(numbers == NULL)
        {
            printf("Memory allocation failed.\n");
            return 1;
        }
    
        for(i = 0; i < 5; i++)
        {
            printf("%d ", numbers[i]);
        }
    
        free(numbers);
    
        return 0;
    }

    Output:

    0 0 0 0 0


    Difference Between malloc() and calloc()

    Feature malloc() calloc()
    Arguments 1 2
    Purpose Allocates a block of bytes Allocates an array-like block
    Initial contents Indeterminate All allocated bytes are initialized to zero
    Example malloc(10 * sizeof(int)) calloc(10, sizeof(int))


    realloc() in C

    realloc() is used to attempt to resize an existing dynamic memory allocation.

    Syntax:

    realloc(pointer, new_size);

    Example:

    int *numbers;
    
    numbers = malloc(5 * sizeof(*numbers));
    
    numbers = realloc(numbers, 10 * sizeof(*numbers));

    The resized allocation may remain at the same address or may be moved to another location. The pointer returned by realloc() must therefore be used.


    Safe Use of realloc()

    A safer pattern is to store the return value in a temporary pointer.

    int *temp;
    
    temp = realloc(numbers, new_size);
    
    if(temp == NULL)
    {
        printf("Reallocation failed.\n");
    }
    else
    {
        numbers = temp;
    }

    This preserves the original pointer if the reallocation fails.


    Complete realloc() Example

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        int *numbers;
        int *temp;
        int i;
    
        numbers = malloc(3 * sizeof(*numbers));
    
        if(numbers == NULL)
        {
            printf("Initial allocation failed.\n");
            return 1;
        }
    
        for(i = 0; i < 3; i++)
        {
            numbers[i] = i + 1;
        }
    
        temp = realloc(numbers, 5 * sizeof(*numbers));
    
        if(temp == NULL)
        {
            printf("Reallocation failed.\n");
            free(numbers);
            return 1;
        }
    
        numbers = temp;
    
        numbers[3] = 4;
        numbers[4] = 5;
    
        for(i = 0; i < 5; i++)
        {
            printf("%d ", numbers[i]);
        }
    
        free(numbers);
    
        return 0;
    }

    Output:

    1 2 3 4 5


    free() in C

    When dynamically allocated memory is no longer needed, release it using free().

    free(pointer);

    Example:

    int *numbers;
    
    numbers = malloc(10 * sizeof(*numbers));
    
    /* Use numbers */
    
    free(numbers);
    numbers = NULL;

    Calling free() releases the allocated storage so it can be reused by the memory-management system.


    Why Is free() Important?

    If a program continuously allocates memory without releasing it, it may consume increasing amounts of memory. This problem is called a memory leak.

    A good memory-management pattern is:

    Allocate
       ↓
    Use
       ↓
    Free


    Setting a Pointer to NULL After free()

    After freeing dynamically allocated storage, a pointer no longer points to a valid allocated object.

    A common defensive practice is:

    free(ptr);
    ptr = NULL;

    This makes it explicit that the pointer should no longer be used to access the former allocation.


    What is a Memory Leak?

    A memory leak occurs when dynamically allocated memory is no longer reachable by the program but has not been released.

    Incorrect example:

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

    The original allocation has been lost.

    Correct approach:

    int *ptr;
    
    ptr = malloc(100 * sizeof(*ptr));
    
    if(ptr != NULL)
    {
        free(ptr);
        ptr = NULL;
    }


    What is a Dangling Pointer?

    A dangling pointer is a pointer whose referenced storage is no longer valid.

    Example:

    int *ptr = malloc(sizeof(*ptr));
    
    free(ptr);
    
    /* ptr must not be dereferenced here */

    Never access the former allocation after it has been freed.


    What is Double Free?

    A double free occurs when the same allocation is released more than once.

    Incorrect:

    free(ptr);
    free(ptr);

    This results in undefined behavior.

    A safer pattern is:

    free(ptr);
    ptr = NULL;


    Checking Allocation Failure

    Dynamic memory allocation can fail, so always check the returned pointer.

    int *numbers = malloc(1000 * sizeof(*numbers));
    
    if(numbers == NULL)
    {
        printf("Unable to allocate memory.\n");
        return 1;
    }


    Practical Program 1 — Dynamic Array

    Let's create a program that asks the user how many numbers they want to store.

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        int *numbers;
        int n;
        int i;
    
        printf("How many numbers? ");
        scanf("%d", &n);
    
        if(n <= 0)
        {
            printf("Invalid size.\n");
            return 1;
        }
    
        numbers = malloc((size_t)n * sizeof(*numbers));
    
        if(numbers == NULL)
        {
            printf("Memory allocation failed.\n");
            return 1;
        }
    
        for(i = 0; i < n; i++)
        {
            printf("Enter number %d: ", i + 1);
            scanf("%d", &numbers[i]);
        }
    
        printf("\nNumbers:\n");
    
        for(i = 0; i < n; i++)
        {
            printf("%d ", numbers[i]);
        }
    
        free(numbers);
        numbers = NULL;
    
        return 0;
    }


    Practical Program 2 — Dynamic Array Average

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        int *numbers;
        int n;
        int i;
        long long sum = 0;
        double average;
    
        printf("Enter number of elements: ");
        scanf("%d", &n);
    
        if(n <= 0)
        {
            printf("Invalid number of elements.\n");
            return 1;
        }
    
        numbers = malloc((size_t)n * sizeof(*numbers));
    
        if(numbers == NULL)
        {
            printf("Memory allocation failed.\n");
            return 1;
        }
    
        for(i = 0; i < n; i++)
        {
            printf("Enter number %d: ", i + 1);
            scanf("%d", &numbers[i]);
            sum += numbers[i];
        }
    
        average = (double)sum / n;
    
        printf("Sum = %lld\n", sum);
        printf("Average = %.2f\n", average);
    
        free(numbers);
    
        return 0;
    }


    Practical Program 3 — Dynamic Array with calloc()

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        int *numbers;
        int n;
        int i;
    
        printf("Enter array size: ");
        scanf("%d", &n);
    
        if(n <= 0)
        {
            printf("Invalid size.\n");
            return 1;
        }
    
        numbers = calloc((size_t)n, sizeof(*numbers));
    
        if(numbers == NULL)
        {
            printf("Memory allocation failed.\n");
            return 1;
        }
    
        printf("Initial values:\n");
    
        for(i = 0; i < n; i++)
        {
            printf("%d ", numbers[i]);
        }
    
        free(numbers);
    
        return 0;
    }


    Practical Program 4 — Expand a Dynamic Array

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        int *numbers;
        int *temp;
        int oldSize = 3;
        int newSize = 6;
        int i;
    
        numbers = malloc((size_t)oldSize * sizeof(*numbers));
    
        if(numbers == NULL)
        {
            printf("Allocation failed.\n");
            return 1;
        }
    
        for(i = 0; i < oldSize; i++)
        {
            numbers[i] = i + 1;
        }
    
        temp = realloc(numbers, (size_t)newSize * sizeof(*numbers));
    
        if(temp == NULL)
        {
            printf("Reallocation failed.\n");
            free(numbers);
            return 1;
        }
    
        numbers = temp;
    
        for(i = oldSize; i < newSize; i++)
        {
            numbers[i] = i + 1;
        }
    
        printf("Expanded array:\n");
    
        for(i = 0; i < newSize; i++)
        {
            printf("%d ", numbers[i]);
        }
    
        free(numbers);
    
        return 0;
    }


    Dynamic Memory and Structures

    Dynamic memory allocation becomes especially useful when working with structures.

    struct Student
    {
        int id;
        char name[50];
        float marks;
    };

    You can dynamically allocate one structure:

    struct Student *student;
    
    student = malloc(sizeof(*student));

    Then use the arrow operator:

    student->id = 101;
    student->marks = 90.5;


    Practical Program 5 — Dynamic Structure

    #include <stdio.h>
    #include <stdlib.h>
    
    struct Student
    {
        int id;
        char name[50];
        float marks;
    };
    
    int main()
    {
        struct Student *student;
    
        student = malloc(sizeof(*student));
    
        if(student == NULL)
        {
            printf("Memory allocation failed.\n");
            return 1;
        }
    
        printf("Enter ID: ");
        scanf("%d", &student->id);
    
        printf("Enter name: ");
        scanf("%49s", student->name);
    
        printf("Enter marks: ");
        scanf("%f", &student->marks);
    
        printf("\n===== Student Information =====\n");
        printf("ID: %d\n", student->id);
        printf("Name: %s\n", student->name);
        printf("Marks: %.2f\n", student->marks);
    
        free(student);
    
        return 0;
    }


    Practical Program 6 — Dynamic Array of Structures

    #include <stdio.h>
    #include <stdlib.h>
    
    struct Student
    {
        int id;
        char name[50];
        float marks;
    };
    
    int main()
    {
        struct Student *students;
        int n;
        int i;
    
        printf("Enter number of students: ");
        scanf("%d", &n);
    
        if(n <= 0)
        {
            printf("Invalid number.\n");
            return 1;
        }
    
        students = malloc((size_t)n * sizeof(*students));
    
        if(students == NULL)
        {
            printf("Memory allocation failed.\n");
            return 1;
        }
    
        for(i = 0; i < n; i++)
        {
            printf("\nStudent %d\n", i + 1);
    
            printf("ID: ");
            scanf("%d", &students[i].id);
    
            printf("Name: ");
            scanf("%49s", students[i].name);
    
            printf("Marks: ");
            scanf("%f", &students[i].marks);
        }
    
        printf("\n===== Student Records =====\n");
    
        for(i = 0; i < n; i++)
        {
            printf("ID: %d | Name: %s | Marks: %.2f\n",
                   students[i].id,
                   students[i].name,
                   students[i].marks);
        }
    
        free(students);
    
        return 0;
    }


    Dynamic Memory + File Handling

    You can combine the concepts learned in Day 11 and Day 12.

    User enters number of records
              ↓
    Allocate memory dynamically
              ↓
    Input records
              ↓
    Process records
              ↓
    Write records to file
              ↓
    Free memory

    This combination can be used to build practical record-management applications.


    Final Practical Project 1 — Student Management System

    Create a menu-driven Student Management System.

    ================================
          STUDENT MANAGEMENT
    ================================
    
    1. Add Student
    2. View Students
    3. Search Student
    4. Update Student
    5. Delete Student
    6. Save to File
    7. Load from File
    8. Exit

    Use a structure such as:

    struct Student
    {
        int id;
        char name[50];
        float marks;
    };

    This project can combine:

    • Variables
    • Input and Output
    • Conditional Statements
    • Loops
    • Arrays
    • Functions
    • Pointers
    • Structures
    • Dynamic Memory
    • File Handling


    Final Practical Project 2 — Contact Management System

    Create a contact management application with features such as:

    1. Add Contact
    2. Display Contacts
    3. Search Contact
    4. Update Contact
    5. Delete Contact
    6. Save Contacts
    7. Load Contacts
    8. Exit

    Example structure:

    struct Contact
    {
        int id;
        char name[50];
        char phone[20];
        char email[100];
    };


    Final Practical Project 3 — Inventory Management System

    Create an inventory management application.

    struct Product
    {
        int id;
        char name[50];
        float price;
        int quantity;
    };

    Suggested features:

    1. Add Product
    2. Display Products
    3. Search Product
    4. Update Product
    5. Sell Product
    6. Restock Product
    7. Save Inventory
    8. Exit


    Final Practical Project 4 — Expense Tracker

    Create a simple expense management application.

    struct Expense
    {
        int id;
        char category[30];
        float amount;
    };

    Suggested features:

    1. Add Expense
    2. View Expenses
    3. Calculate Total
    4. Search by Category
    5. Save Expenses
    6. Exit


    Final Practical Project 5 — Library Management System

    struct Book
    {
        int id;
        char title[100];
        char author[100];
        int available;
    };

    Suggested features:

    1. Add Book
    2. View Books
    3. Search Book
    4. Borrow Book
    5. Return Book
    6. Save Data
    7. Exit


    Final Practical Project 6 — Quiz Application

    Create a C-based quiz application.

    struct Question
    {
        char question[200];
        char options[4][100];
        int answer;
    };

    Suggested features:

    • Start Quiz
    • Display Questions
    • Accept Answers
    • Calculate Score
    • Save Score
    • Display Result


    Common Dynamic Memory Mistakes

    Mistake 1 — Not Checking NULL

    Always check whether allocation succeeded:

    int *p = malloc(100 * sizeof(*p));
    
    if(p == NULL)
    {
        return 1;
    }

    Mistake 2 — Forgetting free()

    Release dynamically allocated memory when it is no longer needed:

    free(p);
    p = NULL;

    Mistake 3 — Unsafe realloc()

    Avoid overwriting the only pointer before checking whether realloc() succeeded.

    void *temp = realloc(p, new_size);
    
    if(temp != NULL)
    {
        p = temp;
    }

    Mistake 4 — Accessing Memory After free()

    Never dereference a pointer after its allocation has been freed.

    Mistake 5 — Allocating the Wrong Amount

    Use sizeof instead of manually assuming type sizes.

    malloc(10 * sizeof(*p));


    Dynamic Memory Best Practices

    • Allocate only what you need.
    • Check allocation results.
    • Free memory when finished.
    • Use temporary pointers with realloc().
    • Set freed pointers to NULL when appropriate.
    • Avoid use-after-free.
    • Avoid double free.
    • Use sizeof correctly.


    Dynamic Memory Allocation Cheat Sheet

    Include the Header

    #include <stdlib.h>

    Allocate Memory

    ptr = malloc(size);

    Allocate Zero-Initialized Storage

    ptr = calloc(count, size);

    Resize Memory

    temp = realloc(ptr, new_size);

    Release Memory

    free(ptr);

    Set Pointer to NULL

    free(ptr);
    ptr = NULL;


    Day 12 Summary

    In this final lesson, you learned how C programs can dynamically request and release memory while running.

    The four most important functions are:

    malloc()
    calloc()
    realloc()
    free()

    malloc()

    Allocates a specified number of bytes.

    int *p = malloc(10 * sizeof(*p));

    calloc()

    Allocates storage for multiple objects and initializes the allocated bytes to zero.

    int *p = calloc(10, sizeof(*p));

    realloc()

    Attempts to resize an existing dynamic allocation.

    int *temp = realloc(p, 20 * sizeof(*p));

    free()

    Releases dynamically allocated storage.

    free(p);

    You also learned about dynamic arrays, dynamic structures, memory leaks, dangling pointers, double free, allocation failures, and practical C projects.


    C Programming Full Course — Final Roadmap

    Day Topic
    Day 1Introduction to C Programming
    Day 2Variables, Data Types & Constants
    Day 3Operators, Input & Output
    Day 4Conditional Statements
    Day 5Loops in C
    Day 6Arrays in C
    Day 7Strings in C
    Day 8Functions in C
    Day 9Pointers in C
    Day 10Structures & Unions
    Day 11File Handling in C
    Day 12Dynamic Memory Allocation & Final Projects


    Conclusion

    Congratulations! You have completed C Programming Day 12 and reached the end of this C Programming Full Course series.

    You started with basic C syntax and gradually learned how to write increasingly powerful programs.

    Throughout this course, you learned variables, data types, operators, conditions, loops, arrays, strings, functions, pointers, structures, unions, file handling, and dynamic memory allocation.

    Most importantly, you now have a strong foundation for building practical C applications.

    Don't simply read the examples. Type the programs yourself, compile them, modify them, find errors, fix those errors, and create your own projects.

    Learn → Code → Practice → Debug → Build → Repeat.

    Your C Programming journey does not end with Day 12. This is where you start building with C.



    Frequently Asked Questions (FAQ)

    What is Dynamic Memory Allocation in C?
    Dynamic Memory Allocation allows a program to request memory during runtime rather than relying only on fixed-size storage.
    What is malloc()?
    malloc() allocates a specified number of bytes and returns a pointer to the allocated storage, or NULL if the allocation fails.
    What is realloc()?
    realloc() attempts to resize an existing dynamically allocated memory block.
    What is free()?
    free() releases dynamically allocated storage obtained from functions such as malloc(), calloc(), or realloc().
    What happens if I forget free()?
    The allocated memory remains reserved until the process ends, potentially causing memory leaks, especially in long-running programs.
    What is a dangling pointer?
    A dangling pointer is a pointer whose referenced storage is no longer valid, such as a pointer used after the corresponding memory has been freed.
    Why should realloc() use a temporary pointer?
    If realloc() fails, it returns NULL while the original allocation remains valid. A temporary pointer prevents you from accidentally losing the original pointer.
    Is malloc() better than calloc()?
    Neither is universally better. Use malloc() when you want uninitialized allocated storage and calloc() when zero-initialized storage is appropriate.
    What should I build after learning C?
    Good projects include a Student Management System, Contact Management System, Inventory System, Expense Tracker, Library Management System, Quiz Application, and File-Based Record Management System.

    0/Post a Comment/Comments

    Thank You For Visit My Website.
    I Will Contact As Soon As Possible.