MEMORY MANAGEMENT
This refers to how a system or a programmer handles the allocation and deallocation of memory for data storage. Unlike languages like Java or Python, C is not a memory-managed language, so the system does not automatically handle dynamic memory for you, instead, the programmer must explicitly manage it.
All data in C must be located in one of three places, that is;
The Stack (Automatic Storage) → This is used for local variables and unction arguments.
The Data Segment (Static Storage) → Used for global variables, constants and literals.
The Heap (Allocated Storage) → Used for dynamic memory allocation, where the size of the data may not be known at runtime.
For Dynamic Memory Allocation and managing memory on the Heap, C uses standard library functions that are defined in <stdlib.h>. These functions return a void pointer (void*), which simply records a memory location without an associated type.
malloc(size_t size)
//requests a block of memory of a specific size. The initia values of the memory are indeterminate
calloc(size_t nmemb, size_t size)
//Allocates memory for an array of n elements, each of a specific size and initializes all bits to zero
realloc(void *pntr, size_t size)
//Changes the size of a previously allocated memory block. It deallocates the old object and returns a pointer to a new ine, preserving the original contents up to the lesser of the new and old sizes.
free(void *pntr)
//Returns the allocated memory back to the operating sysytem. If null, no action occurs. Attempting to free memory that was not dynamically allocated results in undefined behaviour. For Good Practice:
Every malloc call needs exactly one free
Never use a pointer after freeing it, set it to NULL afterward as a safety habit
Never free a pointer twice
Always check the return value of malloc
Never return a pointer to a local variable