Introduction
In the previous chapters, we explored various aspects of C programming, including pointers. In this chapter, we will focus on memory management. Proper memory management is crucial for writing efficient and robust C programs. It involves allocating, using, and freeing memory correctly to avoid memory leaks, fragmentation, and other issues.
Memory Allocation in C
Memory allocation in C can be categorized into two types:
- Static Memory Allocation: Memory is allocated at compile-time.
- Dynamic Memory Allocation: Memory is allocated at runtime.
Static Memory Allocation
Static memory allocation occurs when memory is allocated during the compile time. Variables declared inside functions, global variables, and static variables are examples of static memory allocation. The memory for these variables is automatically managed by the compiler.
Example: Static Memory Allocation
#include <stdio.h>
int global_var; // Global variable
static int static_var; // Static variable
void function() {
int local_var; // Local variable
static int static_local_var; // Static local variable
printf("Local variable address: %p\n", (void*)&local_var);
printf("Static local variable address: %p\n", (void*)&static_local_var);
}
int main() {
printf("Global variable address: %p\n", (void*)&global_var);
printf("Static variable address: %p\n", (void*)&static_var);
function();
return 0; // Returning 0 to indicate successful execution
}
Output:
Global variable address: 0x56555630
Static variable address: 0x56555634
Local variable address: 0x7ffc0fae0eac
Static local variable address: 0x56555638
In this example, the addresses of global, static, and local variables are printed. The global and static variables are allocated at compile time.
Dynamic Memory Allocation
Dynamic memory allocation occurs when memory is allocated during runtime. It allows you to allocate memory as needed and free it when it is no longer required. Dynamic memory allocation is performed using the following functions:
malloc
: Allocates memory blocks.calloc
: Allocates memory blocks and initializes them to zero.realloc
: Reallocates memory blocks to resize them.free
: Frees allocated memory.
malloc
Function
The malloc
function allocates a block of memory of the specified size and returns a pointer to the beginning of the block. The memory content is not initialized.
Syntax:
void *malloc(size_t size);
Example: Using malloc
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr;
int n = 5;
// Allocating memory for n integers
ptr = (int*)malloc(n * sizeof(int));
if (ptr == NULL) {
printf("Memory allocation failed\n");
return 1; // Exiting the program if memory allocation fails
}
// Storing values in the allocated memory
for (int i = 0; i < n; i++) {
ptr[i] = i + 1;
}
// Accessing and printing the values
printf("Allocated array: ");
for (int i = 0; i < n; i++) {
printf("%d ", ptr[i]);
}
printf("\n");
// Freeing the allocated memory
free(ptr);
return 0; // Returning 0 to indicate successful execution
}
Output:
Allocated array: 1 2 3 4 5
calloc
Function
The calloc
function allocates memory for an array of elements, initializes the memory to zero, and returns a pointer to the memory.
Syntax:
void *calloc(size_t num, size_t size);
Example: Using calloc
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr;
int n = 5;
// Allocating memory for n integers
ptr = (int*)calloc(n, sizeof(int));
if (ptr == NULL) {
printf("Memory allocation failed\n");
return 1; // Exiting the program if memory allocation fails
}
// Accessing and printing the initialized values
printf("Allocated array: ");
for (int i = 0; i < n; i++) {
printf("%d ", ptr[i]);
}
printf("\n");
// Freeing the allocated memory
free(ptr);
return 0; // Returning 0 to indicate successful execution
}
Output:
Allocated array: 0 0 0 0 0
realloc
Function
The realloc
function changes the size of the previously allocated memory block.
Syntax:
void *realloc(void *ptr, size_t new_size);
Example: Using realloc
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr;
int n = 5;
// Allocating memory for n integers
ptr = (int*)malloc(n * sizeof(int));
if (ptr == NULL) {
printf("Memory allocation failed\n");
return 1; // Exiting the program if memory allocation fails
}
// Storing values in the allocated memory
for (int i = 0; i < n; i++) {
ptr[i] = i + 1;
}
// Reallocating memory for n*2 integers
ptr = (int*)realloc(ptr, n * 2 * sizeof(int));
if (ptr == NULL) {
printf("Memory reallocation failed\n");
return 1; // Exiting the program if memory reallocation fails
}
// Storing additional values in the reallocated memory
for (int i = n; i < n * 2; i++) {
ptr[i] = i + 1;
}
// Accessing and printing the values
printf("Reallocated array: ");
for (int i = 0; i < n * 2; i++) {
printf("%d ", ptr[i]);
}
printf("\n");
// Freeing the allocated memory
free(ptr);
return 0; // Returning 0 to indicate successful execution
}
Output:
Reallocated array: 1 2 3 4 5 6 7 8 9 10
free
Function
The free
function deallocates the memory previously allocated by malloc
, calloc
, or realloc
.
Syntax:
void free(void *ptr);
Example: Comprehensive Memory Management
Here is a comprehensive example demonstrating dynamic memory allocation, reallocation, and deallocation:
#include <stdio.h>
#include <stdlib.h>
int main() {
int *arr;
int initial_size = 5, new_size;
// Allocating memory for initial_size integers
arr = (int*)malloc(initial_size * sizeof(int));
if (arr == NULL) {
printf("Memory allocation failed\n");
return 1; // Exiting the program if memory allocation fails
}
// Storing values in the allocated memory
for (int i = 0; i < initial_size; i++) {
arr[i] = i + 1;
}
// Accessing and printing the values
printf("Initial array: ");
for (int i = 0; i < initial_size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// Reallocating memory for new_size integers
printf("Enter new size of the array: ");
scanf("%d", &new_size);
arr = (int*)realloc(arr, new_size * sizeof(int));
if (arr == NULL) {
printf("Memory reallocation failed\n");
return 1; // Exiting the program if memory reallocation fails
}
// Storing additional values in the reallocated memory
for (int i = initial_size; i < new_size; i++) {
arr[i] = i + 1;
}
// Accessing and printing the values
printf("Reallocated array: ");
for (int i = 0; i < new_size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// Freeing the allocated memory
free(arr);
return 0; // Returning 0 to indicate successful execution
}
Output:
Initial array: 1 2 3 4 5
Enter new size of the array: 10
Reallocated array: 1 2 3 4 5 6 7 8 9 10
Conclusion
Proper memory management is crucial for writing efficient and robust C programs. By understanding static and dynamic memory allocation, you can efficiently allocate, use, and free memory in your applications. Dynamic memory allocation functions such as malloc
, calloc
, realloc
, and free
are essential tools for managing memory in C. Mastering memory management techniques helps prevent memory leaks, fragmentation, and other issues, ensuring your programs run smoothly and efficiently.