Lesson 52 of 60 – Dynamic Memory Allocation in C
87%

Dynamic Memory Allocation in C

Dynamic memory allocation allows a C program to request memory while the program is running. It is useful when the amount of memory needed is not known at compile time.

Note: Dynamic memory allocation functions are declared in the <stdlib.h> header file. Memory obtained dynamically should be released with free() when it is no longer needed.

1. What is Dynamic Memory Allocation?

Dynamic memory allocation means allocating memory during program execution instead of deciding the required amount completely at compile time.

For example, if a program needs an array whose size is entered by the user, dynamic memory allocation can be used.

2. Why Use Dynamic Memory?

Dynamic memory is useful when the required memory size can change at runtime.

  • User-defined array sizes
  • Dynamic data structures
  • Linked lists
  • Trees
  • Queues and stacks
  • Memory-efficient programs

3. Header File for Dynamic Memory

The main dynamic memory allocation functions are declared in <stdlib.h>.

#include <stdlib.h>

Functions such as malloc(), calloc(), realloc(), and free() are provided through this header.

4. malloc() Function

The malloc() function allocates a block of uninitialized memory.

int *ptr;

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

The requested memory is allocated from the dynamic memory area and its address is returned.

5. malloc() Syntax

The general form is:

pointer = malloc(number_of_bytes);

For example:

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

Using sizeof *numbers helps keep the allocation tied to the pointer's actual pointed-to type.

6. malloc() Returns a Pointer

If allocation succeeds, malloc() returns a pointer to the allocated memory.

int *ptr = malloc(sizeof *ptr);

The pointer can then be used to access the allocated object.

7. Check malloc() for Failure

Memory allocation can fail. Therefore, the returned pointer should be checked before using it.

int *ptr = malloc(sizeof *ptr);

if(ptr == NULL)
{
    printf("Memory allocation failed");
}
else
{
    *ptr = 100;
}

8. malloc() Does Not Initialize Memory

Memory returned by malloc() is not initialized to zero. Its initial contents are indeterminate.

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

Initialize the allocated memory before reading its values.

9. calloc() Function

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

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

This allocates space for five integers.

10. calloc() Syntax

The general syntax is:

pointer = calloc(number_of_elements, size_of_each_element);

Example:

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

11. malloc() vs calloc()

malloc() calloc()
Takes one size argument Takes number of elements and element size
Memory is not initialized Allocated bytes are initialized to zero
Useful for a single block of requested bytes Useful for allocating multiple elements

12. free() Function

The free() function releases dynamically allocated memory.

int *ptr = malloc(sizeof *ptr);

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

    free(ptr);
    ptr = NULL;
}

After freeing memory, setting the pointer to NULL can help avoid accidentally using the old address.

13. Why free() is Important

Dynamically allocated memory remains allocated until it is released or the program terminates.

Failing to release memory that is no longer needed can cause a memory leak.

14. realloc() Function

The realloc() function changes the size of a previously allocated memory block.

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

int *temp = realloc(numbers, 10 * sizeof *numbers);

If the reallocation succeeds, the returned pointer represents the resized block.

15. realloc() Syntax

The general syntax is:

new_pointer = realloc(old_pointer, new_size);

The memory block may be moved to a different location when its size is changed.

16. Safe Use of realloc()

It is safer to store the result of realloc() in a temporary pointer before replacing the original pointer.

int *temp = realloc(numbers, 10 * sizeof *numbers);

if(temp != NULL)
{
    numbers = temp;
}
else
{
    printf("Reallocation failed");
}

This preserves the original pointer if the reallocation fails.

17. Dynamic Array

Dynamic memory allocation can be used to create an array whose size is known only during program execution.

int n;

printf("Enter size: ");
scanf("%d", &n);

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

The array can then be accessed using normal indexing.

18. Dynamic Array Example

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

int main()
{
    int n;

    printf("Enter number of elements: ");
    scanf("%d", &n);

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

    if(numbers == NULL)
    {
        printf("Memory allocation failed");
        return 1;
    }

    for(int i = 0; i < n; i++)
    {
        numbers[i] = i + 1;
    }

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

    free(numbers);

    return 0;
}

19. Dynamic Memory for a Structure

Dynamic memory can also be allocated for a structure.

struct Student
{
    int id;
    float marks;
};

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

The structure can be accessed using the arrow operator.

student->id = 101;
student->marks = 85.5f;

20. Dynamic Memory and Strings

Dynamic memory can be used when the required string storage is determined at runtime.

char *name = malloc(50 * sizeof *name);

if(name != NULL)
{
    scanf("%49s", name);
    printf("Name = %s", name);

    free(name);
}

Always ensure that the input fits inside the allocated memory.

21. Pointer Arithmetic with Dynamic Arrays

A dynamically allocated array can be accessed using either array indexing or pointer arithmetic.

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

numbers[0] = 10;
numbers[1] = 20;

printf("%d", *(numbers + 1));

free(numbers);

The expression *(numbers + 1) accesses the second element.

22. Dynamic Memory for Multiple Structures

struct Student
{
    int id;
    float marks;
};

int n = 5;

struct Student *students =
    malloc(n * sizeof *students);

if(students != NULL)
{
    students[0].id = 101;
    students[0].marks = 90.0f;
}

This allocates space for multiple structure objects.

23. Memory Leak

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

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

/* ptr is lost without free() */

Repeated memory leaks can cause a program to consume more and more memory.

24. Dangling Pointer

A dangling pointer is a pointer that refers to memory that has already been released.

int *ptr = malloc(sizeof *ptr);

free(ptr);

/* ptr should not be dereferenced here */

A useful practice is:

free(ptr);
ptr = NULL;

25. Double free

Calling free() more than once on the same allocated pointer without giving it a new valid allocation can result in undefined behavior.

int *ptr = malloc(sizeof *ptr);

free(ptr);
ptr = NULL;

/* Do not free the old allocation again. */

Setting a pointer to NULL after freeing can help make repeated cleanup safer because free(NULL) has no effect.

26. Buffer Overflow in Dynamic Memory

Dynamic memory does not automatically prevent writing outside the allocated block.

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

numbers[0] = 10;
numbers[4] = 50;

/* numbers[5] is outside the allocated array */

Always keep indexes within the allocated range.

27. Complete malloc() Program

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

int main()
{
    int n;
    int sum = 0;

    printf("Enter number of elements: ");
    scanf("%d", &n);

    if(n <= 0)
    {
        printf("Invalid size");
        return 1;
    }

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

    if(numbers == NULL)
    {
        printf("Memory allocation failed");
        return 1;
    }

    for(int i = 0; i < n; i++)
    {
        printf("Enter number %d: ", i + 1);
        scanf("%d", &numbers[i]);

        sum += numbers[i];
    }

    printf("Sum = %d\n", sum);

    free(numbers);

    return 0;
}

28. Complete calloc() and realloc() Example

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

int main()
{
    int *numbers = calloc(3, sizeof *numbers);

    if(numbers == NULL)
    {
        printf("Allocation failed");
        return 1;
    }

    numbers[0] = 10;
    numbers[1] = 20;
    numbers[2] = 30;

    int *temp = realloc(numbers, 5 * sizeof *numbers);

    if(temp == NULL)
    {
        free(numbers);
        return 1;
    }

    numbers = temp;

    numbers[3] = 40;
    numbers[4] = 50;

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

    free(numbers);

    return 0;
}

29. Best Practices for Dynamic Memory

  • Include <stdlib.h>.
  • Check allocation results for NULL.
  • Use sizeof when calculating allocation sizes.
  • Do not read uninitialized memory.
  • Keep track of allocated memory.
  • Release memory with free() when it is no longer needed.
  • Set freed pointers to NULL when appropriate.
  • Use temporary pointers when handling realloc().
  • Never access memory outside the allocated range.

30. Practice Program

Create a C program that:

  1. Asks the user for the number of students.
  2. Uses malloc() to allocate an array of student marks.
  3. Checks whether allocation succeeded.
  4. Accepts marks for every student.
  5. Calculates the total and average.
  6. Uses realloc() to increase the array size.
  7. Adds more student marks.
  8. Displays all marks.
  9. Releases the allocated memory using free().

This exercise will help you practice malloc(), realloc(), pointers, arrays, and free().

📌 Key Points

  • Dynamic memory is allocated during program execution.
  • malloc() allocates uninitialized memory.
  • calloc() allocates memory and initializes the allocated bytes to zero.
  • realloc() changes the size of an existing allocation.
  • free() releases dynamically allocated memory.
  • Dynamic memory functions are declared in <stdlib.h>.
  • Always check whether allocation returned NULL.
  • Use sizeof to calculate allocation sizes safely.
  • Reading uninitialized memory should be avoided.
  • Memory leaks occur when allocated memory is not properly released.
  • Dangling pointers can occur when a pointer is used after its memory has been freed.
  • Accessing outside an allocated block can cause undefined behavior.
  • realloc() should be handled carefully so the original allocation is not accidentally lost on failure.

🧠 Quick Quiz

Question: Which function is used to release dynamically allocated memory?