Dynamic Memory Allocation in C
Dynamic memory allocation in C enables programs to allocate memory at runtime. This gives flexibility in memory management, unlike static memory allocation (e.g., arrays) where the size must be known at compile time.
1. Functions for Dynamic Memory Allocation
a. malloc()
malloc()
(memory allocation) allocates a block of memory of a specified size and returns a pointer to the beginning of the block. The memory is uninitialized.
Syntax
void* malloc(size_t size);
Example
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr;
ptr = (int*) malloc(5 * sizeof(int)); // Allocating memory for 5 integers
if (ptr == NULL) {
printf("Memory allocation failed\n");
return 1;
}
for (int i = 0; i < 5; i++) {
ptr[i] = i + 1;
printf("%d ", ptr[i]);
}
free(ptr); // Deallocating memory
return 0;
}
b. calloc()
calloc()
(contiguous allocation) allocates memory for an array of elements and initializes all bytes to zero.
Syntax
void* calloc(size_t num, size_t size);
Example
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr;
ptr = (int*) calloc(5, sizeof(int)); // Allocating memory for 5 integers, initialized to 0
if (ptr == NULL) {
printf("Memory allocation failed\n");
return 1;
}
for (int i = 0; i < 5; i++) {
printf("%d ", ptr[i]); // All elements are initialized to 0
}
free(ptr); // Deallocating memory
return 0;
}
c. realloc()
realloc()
(reallocate memory) is used to resize previously allocated memory blocks without losing the original data.
Syntax
void* realloc(void* ptr, size_t new_size);
Example
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr;
ptr = (int*) malloc(5 * sizeof(int)); // Allocating memory for 5 integers
if (ptr == NULL) {
printf("Memory allocation failed\n");
return 1;
}
for (int i = 0; i < 5; i++) {
ptr[i] = i + 1;
}
// Resizing memory block to hold 10 integers
ptr = (int*) realloc(ptr, 10 * sizeof(int));
for (int i = 5; i < 10; i++) {
ptr[i] = i + 1;
}
for (int i = 0; i < 10; i++) {
printf("%d ", ptr[i]);
}
free(ptr); // Deallocating memory
return 0;
}
d. free()
free()
deallocates previously allocated memory, making it available for future use.
Syntax
void free(void* ptr);
Example
int* ptr = (int*) malloc(5 * sizeof(int));
// Use the allocated memory...
free(ptr); // Free the allocated memory
2. Memory Leaks and Best Practices
A memory leak occurs when dynamically allocated memory is not deallocated using free()
. This can cause programs to consume increasing amounts of memory, leading to performance issues.
a. Identifying Memory Leaks
Memory leaks often occur when:
- Memory is allocated but never freed.
- Pointers to dynamically allocated memory are overwritten without first freeing the memory.
Example of a Memory Leak
int* ptr = (int*) malloc(5 * sizeof(int));
ptr = (int*) malloc(10 * sizeof(int)); // Memory leak: previous memory is lost
free(ptr); // Only the second block is freed
b. Best Practices for Memory Management
- Always match every
malloc()
,calloc()
, andrealloc()
call with afree()
to avoid memory leaks. - Avoid memory leaks by ensuring that allocated memory is freed before reassigning a pointer.
- Initialize pointers to
NULL
afterfree()
to prevent dangling pointers. - Use tools like Valgrind to detect memory leaks during testing.
Memory Leak Prevention Example
int *ptr = (int*) malloc(5 * sizeof(int));
if (ptr == NULL) {
printf("Memory allocation failed\n");
return 1;
}
// Always free allocated memory when it's no longer needed
free(ptr);
ptr = NULL; // Prevent dangling pointer
Diagram for Dynamic Memory Allocation
Summary of Dynamic Memory Allocation Functions
malloc()
: Allocates memory but leaves it uninitialized.calloc()
: Allocates memory and initializes it to zero.realloc()
: Resizes a previously allocated memory block.free()
: Deallocates memory to avoid memory leaks.
Best Practices:
- Always free memory after use to prevent memory leaks.
- Avoid losing pointers to dynamically allocated memory by freeing them before reassignment.
- Use debugging tools to monitor memory usage.