Dynamic Memory Allocation, Stack & Heap
C Memory Management
So far we have seen:
- Static-duration Variables (Allocated in Main Memory)
- Automatic-duration Variables (Allocated on the Stack)
There are two issues with these types of variables:
- The size of the allocation must be compile-time constant.
- Their persistence cannot be manually controlled.
Dynamic Memory Allocation
Dynamic memory is allocated into the heap which grows in the opposite direction to the stack.
malloc
void *malloc(size_t size);
- It takes the size of the memory to be allocated,
- and returns the pointer to the memory that has been allocated.
We can type cast this pointer into the type that we want to put in that memory.
We can use malloc
like so:
int *arr;
arr = (int *)malloc(10 * sizeof(int));
We can then use this as an array of integers as this is a pointer to 10 int
s worth of space.
calloc
void *calloc(size_t nmemb, size_t size);
nmemb
- The number of things to store.size
- The size of the thing to store.
This function also initialises the memory that is allocated.
- It also returns a pointer to the memory requested.
We can use it like so:
int *arr;
arr = (int *)calloc(10, sizeof(int));
realloc
Increases or decreases the size of the specified block of memory, reallocates it if needed:
void *realloc(pointer, int new_size);
Not Enough Memory
If there isn’t enough memory available then malloc
and calloc
will return NULL
.
We can handle this like so:
int *arr = (int *)malloc(10 * sizeof(int));
if (arr == NULL) {
fprintf(stderr, "out of memory!\n");
exit(1);
}
/* code that uses arr… */
free
We can call free on the pointer to memory to return the memory back to the operating system.
It may be useful to set the pointer to NULL
after the memory has been freed as a reminder.
We can use it like so:
int *j;
j = (int *)malloc(2 * sizeof(int));
free (j);
Memory Leaks
Failure to deallocate memory using free
elads to a build-up of non-reusable memory.
This wastes memory resources and can lead to allocation failures.
We can use tools such as valgrind
to debug memory leaks.
The Stack
Local variables, function arguments and return values are all stored on the stack.
- Each function call generates a new stack frame.
- After a function returns, the stack frame disappears, along with ll local variable and function arguments for that invocation.
Each time we call a recursive function, it’s variables and space for it’s return value is stored on the stack. This will grow until the function unwinds.