[Solution] C malloc() Returns NULL — ENOMEM Fix
When malloc(), calloc(), or realloc() cannot allocate the requested memory, it returns NULL and sets errno to ENOMEM. Ignoring this return value causes null pointer dereferences and segmentation faults. Properly handling allocation failures is essential for robust C programs.
Why malloc() Returns NULL
The most common reasons are requesting more memory than the system has available, hitting resource limits (ulimit), or memory fragmentation on embedded systems.
Wrong: Ignoring the Return Value
// WRONG — no check after malloc
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int *arr = malloc(1000000 * sizeof(int));
arr[0] = 42; // segfault if malloc returned NULL
printf("%d\n", arr[0]);
free(arr);
return 0;
}
Correct: Always Check the Return Value
// CORRECT
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(void) {
int *arr = malloc(1000000 * sizeof(int));
if (arr == NULL) {
fprintf(stderr, "malloc failed: %s\n", strerror(errno));
return 1;
}
arr[0] = 42;
printf("%d\n", arr[0]);
free(arr);
return 0;
}
Using calloc Instead of malloc
calloc initializes all allocated memory to zero, which prevents use of uninitialized values and helps detect allocation:
// CORRECT — using calloc
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int count = 1000;
int *arr = calloc(count, sizeof(int));
if (arr == NULL) {
fprintf(stderr, "calloc failed — out of memory\n");
return 1;
}
// arr[0] through arr[999] are guaranteed to be 0
for (int i = 0; i < count; i++) {
printf("%d ", arr[i]);
}
printf("\n");
free(arr);
return 0;
}
Using realloc Safely
realloc can return NULL without freeing the original pointer, so always assign to a temporary variable:
// WRONG — original pointer lost if realloc fails
int *tmp = realloc(buf, new_size);
buf = tmp; // if tmp is NULL, buf is leaked
// CORRECT — preserve original pointer
int *tmp = realloc(buf, new_size);
if (tmp == NULL) {
fprintf(stderr, "realloc failed\n");
free(buf); // free the original buffer
return 1;
}
buf = tmp; // safe to reassign
Checking System Memory
Before allocating large blocks, you can check available memory on Linux:
free -m
ulimit -v
On Linux, overcommit_memory controls whether the kernel allows allocations beyond physical memory:
cat /proc/sys/vm/overcommit_memory
0: Heuristic overcommit (default).1: Always overcommit.2: Never overcommit — allocations are strictly limited.
Avoiding Large Allocations
When possible, stream data instead of loading everything into memory:
// CORRECT — read in chunks
#include <stdio.h>
#include <stdlib.h>
#define CHUNK_SIZE 4096
int main(void) {
FILE *fp = fopen("largefile.bin", "rb");
if (!fp) return 1;
char buf[CHUNK_SIZE];
size_t bytes_read;
while ((bytes_read = fread(buf, 1, CHUNK_SIZE, fp)) > 0) {
process_chunk(buf, bytes_read);
}
fclose(fp);
return 0;
}
Summary
| Strategy | When to Use |
|---|---|
Check malloc return for NULL | Always — every allocation |
Use calloc | When you need zero-initialized memory |
Use temp variable for realloc | Always — preserves original pointer on failure |
| Stream large files in chunks | When processing files larger than available RAM |
Check free -m / ulimit | During debugging allocation failures |
Handle errno with strerror | Always — provides a human-readable error message |