7.6 Dynamic Memory: malloc and free
Memory regions and why the heap is needed
At run time, memory is split into several regions: the code region (instructions), the data region (global and static variables), the stack (local variables, allocated and freed automatically by the compiler), and the heap (allocated and freed manually by the programmer).
A local array on the stack is freed when the function returns, so you must not return its address to the caller. Also, once an array is declared, its size is fixed. When the array size is decided at run time, or the data must outlive the function that creates it, you allocate memory dynamically on the heap.
malloc and free
malloc(size) allocates size bytes on the heap and returns a pointer to that memory, or NULL on failure. It returns an untyped pointer void *, which you cast to the type you need. When you are done, return it with free(), otherwise you cause a memory leak.
int *arr = (int *) malloc(n * sizeof(int));
if (arr == NULL) {
return 1; // allocation failed
}
// ... use arr ...
free(arr); // release when donecalloc and realloc
calloc(n, size) allocates space for n items of size bytes each and initializes all of it to 0; malloc does not initialize.
int *arr = (int *) calloc(n, sizeof(int)); // all zerosrealloc(ptr, size) resizes an existing allocation (grow or shrink). It copies the old data into the new block and returns the new pointer, or NULL on failure.
int *next = realloc(arr, new_size * sizeof(int));
if (next == NULL) {
free(arr);
return 1;
}
arr = next;The function below builds a Fibonacci sequence on the heap and returns it; the caller is responsible for free when done:
int *generate_fibonacci(int n) {
int *arr = (int *) malloc(n * sizeof(int));
if (arr == NULL) {
return NULL;
}
arr[0] = 1;
arr[1] = 1;
for (int i = 2; i < n; i++) {
arr[i] = arr[i - 1] + arr[i - 2];
}
return arr;
}Be especially careful with dynamic memory: check for NULL, avoid going out of bounds, avoid double frees, and never use an old pointer after free.