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()
| Feature | malloc() | calloc() |
|---|---|---|
| Arguments | One size argument | Number of elements and element size |
| Allocation | Allocates a block of memory | Allocates space for multiple elements |
| Initial contents | Indeterminate | All 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/Concept | Purpose |
|---|---|
| malloc() | Allocates a block of memory |
| calloc() | Allocates multiple elements and zero-initializes the bytes |
| realloc() | Resizes an allocated block |
| free() | Releases allocated memory |
| NULL | Represents a null pointer |
| sizeof | Determines the size of a type/object |
| Heap | Common area used for dynamic allocation |
| Memory Leak | Allocated memory not released and no longer reachable |
| Dangling Pointer | Pointer referring to released/invalid memory |
| stdlib.h | Header 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.