Memory Management
Main #
int main(int argc, char *argv[])
Arguments #
argc contains the number of strings inputted. The executable is one, and each argument is one.
argv is a pointer to an array with the argument strings. Can also be represented as char **argv
Memory Management #

The Stack #
The stack contains local variables (exist inside functions).
- Grows from the top down
- Last in first out (LIFO)
- Memory is freed when the function returns.
main()is treated like a function- Automatic memory management: deleted without manual deletion
- A new stack frame gets created every time a new function is called
- Return address (parent)
- Arguments
- Local variables
The Heap #
The heap contains memory that is specifically requested. It grows dynamically upwards.
We can work with the heap using the following commands:
void *malloc(size_t n)allocates a block of uninitialized memory- Does not guarantee adjacent blocks if called multiple times
- Returns a pointer to the block (or
NULLif out of memory) - Usage:
int *p = (int *) malloc(sizeof(int));
calloc()allocates a block of zeroesfree(void *p)frees a previously allocated block of memoryrealloc(void *p, int size)changes the size of a previously allocated block- If
*pisNULL, thenreallocacts likemalloc
- If
Heap Management errors:
- Memory Leak: forgot to deallocate memory, resulting in inaccessible blocks that can’t be cleared properly. Can lead to running out of memory
- Double Free: call free() twice on the same memory
- Use after free: attempt to access data after freeing it
Static #
Static Data includes all variables that are declared outside functions. This data is loaded at the start and cannot be modified.
Code is like static data in that it cannot be modified after the program is loaded. This includes #define symbols and function definitions.
Endianness #
Endianness is the order in which data is stored.
Big Endian: The first character is the most significant byte.
Litle endian: The first character is the least significant byte.
x86 is little endian, network communications are done in big endian.
Alignment #
For structs and other memory things where storing different types might need to be standardized, we have default alignment rules that are centered around the 32-bit architecture.
int needs to be word aligned (starts at multiples of 4).
short needs to be half-word aligned (starts at multiples of 2)
For example, if we have a struct with an int, char, short, char*, char:
- The int takes 4 bytes.
- The char takes 1 byte → now at 5.
- The short needs to be aligned to 6 → now at 8.
- The char* doesn’t need to be aligned and takes 4 bytes → now at 12.
- The char doesn’t need to be aligned → now at 13.
- At the end, we need to add 3 bytes to align it to 16.