Let's sum up everything we covered in this module.
Pointer variables encode object's location in memory.
The memory address, which pointer contains,
is just the location of the first byte that makes up an object; however,
compilers should be aware of how many following bytes it
needs to read to get the full object.
This is why we assign data types to pointer variables.
Based on the given data type,
program will know how many bytes it needs to look up in memory
when we decide to dereference a certain pointer.
Pointer's data type does not influence the size of a pointer variable.
Pointer size will always be consistent because it always needs
to store a memory address and nothing else.
For example, on 32‑bit systems, the pointer size will be 4 bytes,
and on 64‑bit systems, 8 bytes.
We can also declare a void pointer, which is a pointer without data type.
You cannot dereference this pointer for obvious reasons,
but the pointer can still hold an address for memory.
This can be used as a placeholder,
which we can later typecast into some other type of pointer.
Every time you declare a local variable,
that variable will be pushed onto the stack.
Stack is a special region in memory controlled by the CPU.
Basically, the processor will use something called a stack pointer,
which always points to the next available piece of memory.
Local variables are allocated next to each other; they are stacked together.
This is a simplified look at how all of this works,
but CPU will also have to keep track of stack frames because they wrap
around all of the variables that belong to the same scope.
Once the program reaches the end of the scope,
CPU will just return the stack pointer,
and all of the local variables from that scope will be removed from memory.
Heap, also known as free store,
is another important region of memory which we can
use to allocate memory at runtime.
New operator will allocate memory on the heap and return
the memory address of that allocation.
The size of the allocation will depend on the data
type we provide to the operator.
We need to store the returned memory address in a pointer; otherwise,
we will not be able to access the allocated memory.
Memory and heap is not managed by the scope,
so we need to manually deallocate it with the delete operator.
This operator needs the address of the allocated space on the heap,
so make sure that you don't lose the pointer to it.
If you don't do this,
memory on the heap will stay allocated until the end of the whole program,
which can cause a memory leak.
Memory leaks are dangerous.
If you don't deallocate memory, at some point,
your program will probably crash because it will not be able to
allocate any more memory to continue with the execution.
Since stack memory is self‑managed,
you should always use it unless you have a special reason to use heap.
Stack has a predefined size, and it is usually small, around 2 MB.
However,
the allocation of memory on stack is really fast because it
usually needs just one CPU instruction.
On the other hand,
your program will need to work with the operating system to
find the available memory on the heap.
The implementation of heap is not the same on every system,
so the allocation time is usually slower and inconsistent.
However, your programs might need more memory than the stack can offer.
Another advantage of using heap is dynamic allocation of memory at runtime,
which means that your programs can be more flexible.
We'll talk more about that in the next module.
New and delete operators don't just allocate and deallocate memory.
They also execute the object's constructor and destructor respectively.
This is why we should use them instead of legacy
allocation functions like malloc and free.
We can also overload these two operators to customize their allocation strategy.
Instead of just allocating and deallocating memory,
we can track the number of allocated bytes to prevent memory leaks,
or we can use that data to create analytics.
If you're working on an embedded system which does not provide heap by default,
you can implement your own version of it by overloading new and delete.
This will allow you to use all of the useful STL container classes which
usually implement heap in the background.
Now you know what heap memory is, why we need it, and how we can access
it. Other than providing you with more memory to store large objects, heap
also allows you to be flexible with allocating memory at runtime. This
will become more apparent once we start to dynamically allocate arrays.
Join me in the next module to learn more about arrays and their relation
to heap and pointers.
Thank you for watching, and if you have any questions,
please ask them in the courses discussion.