C Allocate Memory
Introduction to Memory Allocation
Memory allocation is the process of reserving memory space during program execution. In C, dynamic memory allocation allows programs to request memory from the heap at runtime, enabling flexible data structures and efficient memory usage.
Key benefits of dynamic memory allocation:
- Memory size can be determined at runtime
- Memory can be resized as needed
- Memory persists beyond function scope
- Enables creation of complex data structures
Memory Allocation Functions
Function | Description | Syntax | Return Value |
---|---|---|---|
malloc() | Allocates raw memory | void* malloc(size_t size) | Pointer to allocated memory or NULL |
calloc() | Allocates and zero-initializes memory | void* calloc(size_t num, size_t size) | Pointer to allocated memory or NULL |
realloc() | Resizes existing allocation | void* realloc(void* ptr, size_t size) | Pointer to resized memory or NULL (original block remains valid on failure) |
free() | Deallocates previously allocated memory | void free(void* ptr) | None (void) |
malloc() - Memory Allocation
⚠️ Warning: Always check if malloc() returns NULL. Unchecked NULL pointers lead to undefined behavior when dereferenced.
Example
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *numbers;
size_t count = 5;
// Allocate memory for 5 integers
numbers = malloc(count * sizeof *numbers);
// CRITICAL: Check if allocation succeeded
if (numbers == NULL) {
printf("Memory allocation failed!\n");
return 1; // Exit with error code
}
printf("Memory allocated successfully at address: %p\n", (void*)numbers);
printf("Allocated size: %zu bytes\n", count * sizeof *numbers);
// Initialize the allocated memory
for (size_t i = 0; i < count; i++) {
numbers[i] = (int)((i + 1) * 10); // Values: 10, 20, 30, 40, 50
}
// Use the allocated memory
printf("Array values: ");
for (size_t i = 0; i < count; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
// Don't forget to free the memory later!
free(numbers);
return 0;
}
Output
Memory allocated successfully at address: 0x55a1b2c3d4e0 Allocated size: 20 bytes Array values: 10 20 30 40 50
calloc() - Contiguous Allocation
Example
#include <stdio.h>
#include <stdlib.h>
int main(void) {
float *scores;
int studentCount = 4;
// Allocate and initialize memory to zero
scores = calloc((size_t)studentCount, sizeof *scores);
if (scores == NULL) {
printf("Memory allocation failed!\n");
return 1;
}
printf("calloc() initialized values: ");
for (int i = 0; i < studentCount; i++) {
printf("%.1f ", scores[i]); // All 0.0
}
printf("\n");
// Assign values
scores[0] = 85.5f;
scores[1] = 92.0f;
scores[2] = 78.5f;
scores[3] = 88.0f;
printf("After assignment: ");
for (int i = 0; i < studentCount; i++) {
printf("%.1f ", scores[i]);
}
printf("\n");
free(scores);
return 0;
}
Output
calloc() initialized values: 0.0 0.0 0.0 0.0 After assignment: 85.5 92.0 78.5 88.0
ℹ️ Note: calloc() is preferred when you need zero-initialized memory or when allocating arrays of elements.
Allocation Best Practices
- Always check if allocation functions return NULL
- Prefer `sizeof *ptr` over `sizeof(type)` to avoid mismatches
- Do NOT cast the return value of malloc/calloc/realloc in C
- Use calloc() when zero-initialization is required
- Calculate size carefully to avoid integer overflow
- Consider memory alignment requirements for your platform
Common Allocation Errors
⚠️ Warning: These examples demonstrate common pitfalls. Always follow best practices to avoid these errors.
Example
#include <stdio.h>
#include <stdlib.h>
int main(void) {
// ERROR: Forgetting to check for NULL
int *badPtr = malloc(1000000000ULL * sizeof *badPtr);
// If allocation fails, badPtr is NULL -> dereferencing would crash
// if (badPtr) { /* use badPtr */ }
// ERROR: Using memory before allocation
int *uninitialized;
// printf("%d\n", *uninitialized); // UNDEFINED BEHAVIOR!
// ERROR: Wrong size calculation
int *wrongSize = malloc(5); // Should be 5 * sizeof *wrongSize
// ERROR: Memory leak - allocating without freeing
int *leaky = malloc(10 * sizeof *leaky);
// Forgot to free(leaky) -> MEMORY LEAK!
// Clean up anything we actually allocated for this demo (avoid compiler warnings)
free(badPtr);
free(wrongSize);
free(leaky); // (Still illustrates that forgetting this would leak.)
return 0;
}
Advanced Allocation Patterns
Example
#include <stdio.h>
#include <stdlib.h>
// Allocate a 2D array dynamically
int **create2DArray(int rows, int cols) {
int **array = malloc((size_t)rows * sizeof *array);
if (array == NULL) return NULL;
for (int i = 0; i < rows; i++) {
array[i] = malloc((size_t)cols * sizeof *array[i]);
if (array[i] == NULL) {
// Clean up previously allocated rows
for (int j = 0; j < i; j++) {
free(array[j]);
}
free(array);
return NULL;
}
}
return array;
}
int main(void) {
int rows = 3, cols = 4;
int **matrix = create2DArray(rows, cols);
if (matrix != NULL) {
printf("2D array allocated successfully\n");
// Example use (initialize to i*j)
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
matrix[i][j] = i * j;
// Free each row and then the array
for (int i = 0; i < rows; i++) {
free(matrix[i]);
}
free(matrix);
}
return 0;
}