C realloc, free and Memory Leaks
Memory from malloc and calloc stays reserved until the program gives it back with free. This topic shows how to change the size of a block, how to free memory correctly, and the mistakes to avoid.
realloc: change the size
realloc(pointer, newBytes) makes a block bigger or smaller and keeps its contents. It may move the block to another address, so always use the pointer it returns. If it fails it returns NULL and leaves the old block untouched, so store the result in a temporary pointer first.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int size = 3;
int *a = malloc(size * sizeof(int));
if (a == NULL) return 1;
for (int i = 0; i < size; i++) a[i] = i + 1;
int *bigger = realloc(a, 6 * sizeof(int)); // grow to 6 elements
if (bigger == NULL) { free(a); return 1; }
a = bigger;
for (int i = size; i < 6; i++) a[i] = (i + 1) * 10;
size = 6;
for (int i = 0; i < size; i++) printf("%d ", a[i]);
printf("\n");
free(a);
return 0;
}1 2 3 40 50 60
free and the rules around it
- Every block from
malloc,callocorreallocmust be freed exactly once. - After
free(p), the memory no longer belongs to you. Using it is a dangling pointer bug. Setp = NULLafter freeing to make such mistakes visible. - Freeing the same block twice (double free) or freeing something that did not come from
malloccan crash the program. free(NULL)is allowed and does nothing.
Memory leaks
A leak is memory that is never freed. In a short program the system cleans up at the end, but in programs that run for a long time, such as servers or games, leaks pile up until memory runs out. With Safe mode on, our editor reports blocks that were never freed when the program ends. Try removing the free(a); line above with Safe mode on.
A linked list
Dynamic memory lets data structures grow one piece at a time. In a linked list, each node holds a value and a pointer to the next node:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int value;
struct Node *next;
} Node;
Node *push(Node *head, int value) {
Node *n = malloc(sizeof *n);
if (n == NULL) return head;
n->value = value;
n->next = head; // the new node goes in front
return n;
}
int main(void) {
Node *list = NULL;
for (int v = 10; v <= 30; v += 10) {
list = push(list, v);
}
for (Node *p = list; p != NULL; p = p->next) {
printf("%d ", p->value);
}
printf("\n");
while (list != NULL) { // free every node
Node *next = list->next;
free(list);
list = next;
}
return 0;
}30 20 10
The freeing loop saves next before calling free, because after free(list) reading list->next would use freed memory.
Practice exercises
- Read numbers until the user types 0, storing them in memory that doubles its size with
reallocwhenever it is full. Print them at the end. - Change the linked list so new nodes are added at the end instead of the front.
- Write a function that counts the nodes in a list.
- With Safe mode on, free a block twice and read the message.