Learn to allocate and deallocate memory at runtime using `malloc`, `calloc`, `realloc`, and `free`.
Dynamic memory allocation is a process that allows a C program to request memory from the operating system's free store, or 'heap', during its execution. This is in contrast to static and automatic memory allocation, where the size of variables must be known at compile time. Dynamic allocation is essential for situations where the required memory size is unknown until runtime, such as handling user input of variable length or creating data structures like linked lists and trees that can grow or shrink. The C standard library `<stdlib.h>` provides several key functions for this purpose. The `malloc()` (memory allocation) function is the most common. It takes a single argument—the number of bytes to allocate—and returns a `void` pointer to the start of the allocated block of memory. If the request cannot be fulfilled, it returns `NULL`. The allocated memory is not initialized and may contain garbage values. The `calloc()` (contiguous allocation) function is similar to `malloc` but takes two arguments: the number of elements and the size of each element. Its key difference is that it initializes the allocated memory to all zeros. The `realloc()` function is used to change the size of a previously allocated memory block. Finally, and most importantly, the `free()` function is used to release a block of dynamically allocated memory back to the heap. It is crucial to `free` any memory you allocate. Failing to do so results in a **memory leak**, where your program holds onto memory it no longer needs, which can eventually cause the program or the entire system to run out of memory.