C Programming

Chapter 12 – Dynamic Memory Allocation in C Language

Chapter 12 – Dynamic Memory Allocation in C Language

Introduction

In C programming, memory is an important resource. In earlier chapters, we created variables and arrays whose size was generally determined when the program was compiled.

But sometimes the amount of memory required is not known in advance.

For example:

A program may need to store an unknown number of students.

The size of an input may change during execution.

A program may need additional memory only when a particular operation is performed.

Memory may need to be released when it is no longer required.

C provides Dynamic Memory Allocation (DMA) for these situations.

Dynamic memory allocation allows a program to request memory during runtime and release it when it is no longer needed.

The main functions used for dynamic memory allocation are:

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

These functions are declared in:

#include <stdlib.h>

1. What is Dynamic Memory Allocation?

Dynamic Memory Allocation is the process of allocating memory during the execution of a program.

For example, instead of declaring:

int numbers[100];

we can request memory at runtime according to the required number of integers.

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

If n is 20, memory for 20 integers is requested.

If n is 100, memory for 100 integers is requested.

2. Why Do We Need Dynamic Memory Allocation?

Static or automatic arrays have a fixed size.

Example:

int numbers[100];

This may be inconvenient when the required size is unknown.

Dynamic allocation allows the program to request memory according to actual requirements.

Advantages

Memory can be allocated at runtime.

Memory can be resized.

Memory can be released when no longer required.

It can avoid reserving a large fixed-size array unnecessarily.

It is useful for dynamic data structures.

3. Memory Areas in a C Program

A running C program can use different areas of memory for different purposes.

A simplified view is:

+----------------------+ |       Stack          | +----------------------+ |                      | |       Heap           | |                      | +----------------------+ | Static / Global Data | +----------------------+ |       Code           | +----------------------+

Dynamic memory allocation generally uses the heap.

The programmer requests memory from the heap and later releases it using free().

4. Header File

Dynamic memory functions are declared in:

#include <stdlib.h>

Example:

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

5. malloc() Function

malloc() stands for memory allocation.

It requests a block of memory of a specified number of bytes.

Syntax

malloc(number_of_bytes);

Example:

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

This requests enough memory for one int.

6. Using malloc() with an Array

Suppose we want memory for 5 integers.

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

A more complete example:

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

Output

30

7. Why Check for NULL?

Memory allocation can fail.

When malloc() cannot provide the requested memory, it returns a null pointer.

Therefore:

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

is an important safety check.

8. Does malloc() Initialize Memory?

No.

Memory obtained using malloc() has indeterminate values.

For example:

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

The allocated integers should be assigned appropriate values before their values are read.

Do not assume newly allocated memory contains zero.

9. calloc() Function

calloc() stands for contiguous allocation.

It allocates memory for multiple elements and initializes all bytes in the allocated region to zero.

Syntax

calloc(number_of_elements, size_of_each_element);

Example:

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

This requests memory for five integers.

10. Example Using calloc()

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

Output

0 0 0 0 0

For integer objects, zero-initialized bytes result in the integer value 0 on conventional C implementations. More generally, calloc() initializes the allocated bytes to zero.

11. Difference Between malloc() and calloc()

Featuremalloc()calloc()
ArgumentsOne size argumentNumber of elements and element size
AllocationAllocates a block of memoryAllocates space for multiple elements
Initial contentsIndeterminateAll allocated bytes initialized to zero
Header<stdlib.h><stdlib.h>

Example

malloc(5 * sizeof(int));

versus:

calloc(5, sizeof(int));

Both can allocate space for five integers, but their initialization behavior differs.

12. free() Function

Memory allocated dynamically should be released when it is no longer required.

The free() function releases dynamically allocated memory.

Syntax

free(pointer);

Example:

int *ptr; ptr = malloc(sizeof *ptr); if(ptr != NULL) {    *ptr = 50;    printf("%d", *ptr);    free(ptr); }

13. Why Is free() Important?

If dynamically allocated memory is not released when it is no longer needed, a program can accumulate unused allocated memory.

This situation is called a memory leak.

Example:

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

If the program no longer needs this memory, it should eventually do:

free(ptr);

14. realloc() Function

Sometimes a program needs to increase or decrease an already allocated memory block.

The realloc() function can be used to resize a previously allocated block.

Syntax

realloc(pointer, new_size);

Example:

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

The second allocation requests space for 10 integers.

15. Safe Use of realloc()

It is generally better not to overwrite the original pointer immediately because realloc() can fail.

Instead, use a temporary pointer:

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

This preserves the original pointer if the resize operation fails.

16. 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)    {        return 1;    }    for(i = 0; i < 3; i++)    {        numbers[i] = (i + 1) * 10;    }    temp = realloc(numbers, 5 * sizeof *numbers);    if(temp == NULL)    {        free(numbers);        printf("Reallocation failed.");        return 1;    }    numbers = temp;    numbers[3] = 40;    numbers[4] = 50;    for(i = 0; i < 5; i++)    {        printf("%d ", numbers[i]);    }    free(numbers);    return 0; }

Output

10 20 30 40 50

17. Four Main Dynamic Memory Functions

The four important functions are:

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

malloc()

Allocates a specified number of bytes.

calloc()

Allocates space for multiple elements and initializes the allocated bytes to zero.

realloc()

Changes the size of a previously allocated block.

free()

Releases dynamically allocated memory.

18. Dynamic Array

One important use of dynamic memory is creating arrays whose size is determined at runtime.

Example:

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

If the user enters:

5

the program allocates space for five integers.

19. Dynamic Memory and Structures

Dynamic memory can also be used with structures.

Example:

#include <stdio.h> #include <stdlib.h> struct Student {    int rollNo;    float marks; }; int main() {    struct Student *student;    student = malloc(sizeof *student);    if(student == NULL)    {        printf("Memory allocation failed.");        return 1;    }    student->rollNo = 101;    student->marks = 88.5f;    printf("Roll No: %d\n", student->rollNo);    printf("Marks: %.2f\n", student->marks);    free(student);    return 0; }

Here the structure object is stored in dynamically allocated memory.

20. Dynamic Array of Structures

We can allocate memory for multiple structures.

#include <stdio.h> #include <stdlib.h> struct Student {    int rollNo;    float marks; }; int main() {    int n = 3;    struct Student *students;    int i;    students = malloc((size_t)n * sizeof *students);    if(students == NULL)    {        return 1;    }    for(i = 0; i < n; i++)    {        students[i].rollNo = 101 + i;        students[i].marks = 80.0f + i * 5.0f;    }    for(i = 0; i < n; i++)    {        printf("Roll No: %d, Marks: %.2f\n",               students[i].rollNo,               students[i].marks);    }    free(students);    return 0; }

Output

Roll No: 101, Marks: 80.00 Roll No: 102, Marks: 85.00 Roll No: 103, Marks: 90.00

21. Dynamic Memory and Strings

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

Example:

#include <stdio.h> #include <stdlib.h> int main() {    char *name;    name = malloc(50 * sizeof *name);    if(name == NULL)    {        return 1;    }    printf("Enter name: ");    scanf("%49s", name);    printf("Name: %s", name);    free(name);    return 0; }

The allocated memory provides space for up to 49 characters plus the terminating '\0' for the input used here.

22. Dynamic Memory Allocation Process

A typical process is:

Determine required size        ↓ Request memory        ↓ Check allocation result        ↓ Use the memory        ↓ Resize if necessary        ↓ Release memory

For example:

malloc()   ↓ Use memory   ↓ realloc()  ← if required   ↓ Use memory   ↓ free()

23. Memory Leak

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

Example:

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

The allocated memory can no longer be reached through ptr, so the program has lost the reference needed to release it.

This is a memory leak.

Better:

free(ptr); ptr = NULL;

24. Dangling Pointer

A dangling pointer is a pointer that refers to memory that has already been released or is otherwise no longer valid.

Example:

int *ptr = malloc(sizeof *ptr); if(ptr != NULL) {    *ptr = 100;    free(ptr);    /* ptr is now a dangling pointer */ }

A useful practice is:

free(ptr); ptr = NULL;

Setting the pointer to NULL helps prevent accidental reuse of that pointer.

25. Double Free

A program should not release the same allocated memory block twice.

Incorrect:

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

The second free() is invalid.

A safer pattern is:

free(ptr); ptr = NULL;

Then calling free(ptr) again is safe because free(NULL) has no effect.

26. Use-After-Free

A use-after-free occurs when a program accesses memory after it has been released.

Incorrect:

int *ptr = malloc(sizeof *ptr); if(ptr != NULL) {    *ptr = 50;    free(ptr);    printf("%d", *ptr); }

The memory must not be accessed after free(ptr).

27. sizeof and Dynamic Memory

The sizeof operator is very useful when allocating memory.

Instead of:

int *ptr = malloc(10 * 4);

use:

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

This avoids assuming a particular size for int.

For example:

double *values = malloc(10 * sizeof *values);

automatically requests enough space for ten double objects.

28. Allocating Memory for Different Data Types

Integer

int *ptr = malloc(sizeof *ptr);

Float

float *ptr = malloc(sizeof *ptr);

Character

char *ptr = malloc(sizeof *ptr);

Structure

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

Using sizeof *ptr makes the allocation expression easier to maintain if the pointer type changes.

29. malloc() vs calloc() Example

Using malloc()

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

The allocated bytes are not initialized by malloc().

Using calloc()

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

The allocated bytes are initialized to zero.

30. Important Rules for Dynamic Memory

When using dynamic memory:

Rule 1

Include:

#include <stdlib.h>

Rule 2

Check whether allocation succeeded.

if(ptr == NULL)

Rule 3

Do not read uninitialized allocated memory.

Rule 4

Do not access memory after free().

Rule 5

Do not free the same allocation more than once.

Rule 6

Release memory when it is no longer required.

Rule 7

Be careful with array boundaries.

31. Complete Dynamic Array Example

Here is a practical example that calculates the average of dynamically allocated numbers.

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

This example demonstrates:

Runtime-sized array

malloc()

Allocation checking

Array indexing

Calculations

free()

32. Dynamic Memory in Data Structures

Dynamic memory allocation is essential for many advanced data structures.

For example:

Linked List    ↓ Nodes created dynamically Stack    ↓ Can use dynamically allocated storage Queue    ↓ Can use dynamically allocated nodes Tree    ↓ Nodes created dynamically

Understanding malloc(), calloc(), realloc(), and free() is therefore an important foundation for learning data structures in C.

33. Common Mistakes

Mistake 1: Forgetting #include <stdlib.h>

Dynamic memory functions require their declarations from <stdlib.h>.

Mistake 2: Not checking allocation

Always consider the possibility that an allocation can fail.

Mistake 3: Reading before initialization

With malloc(), the allocated memory does not automatically contain useful initialized values.

Mistake 4: Forgetting free()

If memory is no longer required, release it.

Mistake 5: Using memory after free()

Once memory is released, do not access it through the old pointer.

Mistake 6: Incorrect realloc() usage

Avoid:

ptr = realloc(ptr, new_size);

when you need to preserve the original pointer if reallocation fails.

Prefer:

int *temp = realloc(ptr, new_size); if(temp != NULL) {    ptr = temp; }

If realloc() fails, the original allocation remains valid.

34. Quick Revision Table

Function/ConceptPurpose
malloc()Allocates a block of memory
calloc()Allocates multiple elements and zero-initializes the bytes
realloc()Resizes an allocated block
free()Releases allocated memory
NULLRepresents a null pointer
sizeofDetermines the size of a type/object
HeapCommon area used for dynamic allocation
Memory LeakAllocated memory not released and no longer reachable
Dangling PointerPointer referring to released/invalid memory
stdlib.hHeader containing dynamic memory function declarations

35. Practice MCQs

Question 1

Which header file contains the declarations for malloc() and free()?

A. <stdio.h>
B. <string.h>
C. <stdlib.h>
D. <memory.h>

Answer: C. <stdlib.h>

Question 2

Which function is used to allocate memory dynamically?

A. alloc()
B. malloc()
C. memory()
D. new()

Answer: B. malloc()

Question 3

Which function releases dynamically allocated memory?

A. delete()
B. remove()
C. free()
D. release()

Answer: C. free()

Question 4

Which function can resize an allocated memory block?

A. resize()
B. realloc()
C. malloc()
D. change()

Answer: B. realloc()

Question 5

Which function initializes the allocated bytes to zero?

A. malloc()
B. calloc()
C. realloc()
D. free()

Answer: B. calloc()

Question 6

What does malloc() return if allocation fails?

A. 0.0
B. EOF
C. NULL
D. -1

Answer: C. NULL

Question 7

What is a memory leak?

A. A syntax error
B. Memory that is allocated but no longer reachable or released
C. A compiler warning
D. A file error

Answer: B. Memory that is allocated but no longer reachable or released

Question 8

Which operator is useful for determining the size of an object?

A. length
B. sizeof
C. size
D. memory

Answer: B. sizeof

36. Programming Exercises

Try writing C programs to:

Allocate memory for one integer using malloc().

Allocate memory for five integers using malloc().

Allocate an array using calloc().

Find the sum of dynamically allocated numbers.

Find the largest element in a dynamically allocated array.

Calculate the average of dynamically allocated numbers.

Resize an integer array using realloc().

Dynamically allocate memory for a structure.

Create a dynamic array of student structures.

Allocate memory for a string at runtime.

Demonstrate the correct use of free().

Create a simple dynamic student-record program.

37. Key Points to Remember

Dynamic memory is allocated during program execution.

The main functions are malloc(), calloc(), realloc(), and free().

These functions are declared in <stdlib.h>.

malloc() allocates memory without initializing its contents.

calloc() allocates memory and initializes all allocated bytes to zero.

realloc() changes the size of an existing allocation.

free() releases dynamically allocated memory.

Always check whether allocation returned NULL.

Do not access memory after it has been freed.

Avoid memory leaks and double frees.

sizeof is useful for calculating allocation sizes.

Dynamic memory is fundamental to linked lists, trees, and other dynamic data structures.

Chapter Summary

Dynamic Memory Allocation allows a C program to request memory while it is running rather than relying only on fixed-size storage.

The four main functions are:

malloc()   → Allocate memory calloc()   → Allocate and zero-initialize memory realloc()  → Resize allocated memory free()     → Release memory

Dynamic memory provides flexibility for programs whose memory requirements are not known in advance. However, it must be handled carefully. Incorrect memory management can result in memory leaks, dangling pointers, double frees, and undefined behavior.

A good C programmer should always check allocations, respect memory boundaries, avoid accessing freed memory, and release dynamically allocated memory when it is no longer needed.

Next Chapter

Chapter 13 – Preprocessors and Macros in C Language

In the next chapter, you will learn about #include, #define, macros, conditional compilation, header files, and other preprocessing features used in C programs.