Neural Sync Active
Dynamic Memory — malloc, calloc, realloc, free
Registry Synced
Dynamic Memory — malloc, calloc, realloc, free
813 words
4 min read
Reading compass
Now · 🎯 Learning Objectives
Dynamic Memory — malloc, calloc, realloc, free
🎯 Learning Objectives
- Allocate and free memory dynamically
- Differentiate malloc, calloc, and realloc
- Implement dynamic arrays and linked lists
- Detect and prevent memory leaks
1. Heap Memory Functions
1.1 malloc
c#include <stdlib.h> // Allocate 10 integers (uninitialized memory) int *arr = (int*)malloc(10 * sizeof(int)); if (arr == NULL) { fprintf(stderr, "Memory allocation failed\n"); exit(1); } // Memory contains garbage values arr[0] = 42; // Initialize after allocation
1.2 calloc
c// Allocate and zero-initialize 10 integers int *arr = (int*)calloc(10, sizeof(int)); // All elements are guaranteed 0 // calloc(10, 4) vs malloc(40): calloc zeros the memory
1.3 realloc
cint *arr = (int*)malloc(5 * sizeof(int)); // ... use 5 elements ... // Resize to 10 elements (may move to new location) int *temp = (int*)realloc(arr, 10 * sizeof(int)); if (temp != NULL) { arr = temp; // Update pointer } else { // realloc failed! arr still valid but unchanged fprintf(stderr, "realloc failed\n"); } // realloc preserves existing content, new space is uninitialized
1.4 free
cfree(arr); // Release memory back to heap arr = NULL; // Prevent dangling pointer
2. Common Patterns
2.1 Dynamic Array (Growth Strategy)
ctypedef struct { int *data; int size; int capacity; } DynArray; void da_init(DynArray *da) { da->size = 0; da->capacity = 4; da->data = (int*)malloc(da->capacity * sizeof(int)); } void da_append(DynArray *da, int value) { if (da->size >= da->capacity) { // Double capacity when full da->capacity *= 2; int *new_data = (int*)realloc(da->data, da->capacity * sizeof(int)); if (new_data) { da->data = new_data; } else { fprintf(stderr, "Failed to grow array\n"); exit(1); } } da->data[da->size++] = value; } void da_free(DynArray *da) { free(da->data); da->data = NULL; da->size = da->capacity = 0; }
2.2 Singly Linked List
ctypedef struct Node { int data; struct Node *next; } Node; Node* create_node(int value) { Node *node = (Node*)malloc(sizeof(Node)); if (node) { node->data = value; node->next = NULL; } return node; } void free_list(Node *head) { while (head) { Node *temp = head; head = head->next; free(temp); } }
3. Common Pitfalls
Pitfall 1: Forgetting to check malloc return
cint *arr = (int*)malloc(1000000000 * sizeof(int)); // May fail! arr[0] = 42; // SEGFAULT if malloc returned NULL
Fix: Always check
if (ptr == NULL) { /* handle error */ }.Pitfall 2: Memory leaks
cvoid leak() { int *p = (int*)malloc(100 * sizeof(int)); // Function returns without freeing p → memory leak }
Fix: Use a systematic deallocation strategy. In long-running programs, every malloc should match with a free.
Pitfall 3: Double free
cint *p = malloc(sizeof(int)); free(p); free(p); // Undefined behavior! Double free
Fix: Set
p = NULL after freeing. free(NULL) is safe.Pitfall 4: Buffer overflow on heap
cint *arr = (int*)malloc(5 * sizeof(int)); arr[100] = 42; // Heap buffer overflow! Corrupts heap metadata
4. 📝 Practice Questions
Q1: What is the difference between malloc and calloc?Answer: malloc allocates uninitialized memory (garbage values). calloc allocates and zero-initializes. calloc also takes separate count and size arguments, which can help detect arithmetic overflow: calloc(n, size) returns NULL if n*size overflows. Q2: What does realloc do if it cannot extend the existing block?Answer: realloc allocates a new block elsewhere, copies the old contents, and frees the old block. If allocation fails, it returns NULL and the original block remains untouched. Always use a temporary pointer for realloc. Q3: Write a function that concatenates two strings using dynamic memory.cchar* concat(const char *s1, const char *s2) { size_t len1 = strlen(s1); size_t len2 = strlen(s2); char *result = (char*)malloc(len1 + len2 + 1); if (result) { strcpy(result, s1); strcat(result, s2); } return result; }Q4: What happens if you forget to free memory in a long-running program?Answer: The program's memory usage grows monotonically (memory leak). Eventually, the OS runs out of memory, causing the program to crash (OOM) or be killed by the OS. This is especially critical in servers that run for weeks or months. Q5: Why is setting freed pointers to NULL a good practice?Answer: It prevents use-after-free bugs (accessing freed memory) and double-free bugs. Accessing a NULL pointer causes an immediate crash (segfault), which is easier to debug than corrupting heap metadata silently.
5. 🔗 Cross-References
- Week 3 - Pointers: Pointer basics for dynamic memory
- Week 1 - Memory Layout: Heap location in process memory
- BSCS4022 (OS): brk/sbrk system calls for heap Join Discord PreviousFunctionsNextStructures & Unions