How Computers Run Programs
A beginner's model of CPUs, memory, and what really happens between "Run" and "Hello, World!".
Before we keep writing C++, we need a mental model of what a computer actually is and how it runs a program. You do not need to be an electrical engineer to write good code — but the more accurate your mental model, the easier every later concept (variables, pointers, the stack) will be.
The simplest useful model
Strip away every detail and a computer is just three things:
- Memory is one long row of numbered boxes. Each box holds a single byte (a number from 0 to 255). The boxes are numbered starting at 0; that number is called the box's address.
- A CPU is a small worker that does one tiny operation at a time: copy this box into that box, add the numbers in these two boxes, jump back ten boxes, and so on.
- Input/Output devices — the keyboard, the screen, the disk, the network — let memory and the outside world exchange data.
Everything more complicated is built on top of those three ideas.
Bytes, bits, and addresses
Inside a single box (one byte), data is stored as eight tiny
on/off switches called bits. Eight bits give you 2^8 = 256
possible patterns, which is why one byte can hold a number from 0 to
255.
Address: 0 1 2 3 4 5 6 7
Box: [42] [13] [ 0] [97] [98] [99] [ 0] [255]
'a' 'b' 'c'Letters are just numbers under an agreement called ASCII or
Unicode. The letter a is the number 97. The letter b is 98.
Larger numbers are stored across several boxes side by side. The
integer 1000 fits in two bytes; on a typical modern machine an int
is stored in four consecutive bytes.
The sizeof operator tells you, in bytes, how big a type is on the
machine the program is currently running on. Try running the block
above — the numbers depend on the CPU. (On the in-browser WebAssembly
target, pointers are 4 bytes.)
The CPU's instruction loop
The CPU does exactly one thing, over and over, billions of times per second. It is called the fetch–decode–execute loop:
The CPU keeps a special variable called the instruction pointer
that says "the next instruction is at memory address X". After
each instruction, the pointer advances. A jump instruction sets
the pointer to a different address, which is how loops, if
branches, and function calls work under the hood.
The CPU also has a tiny set of very fast storage slots called registers (typically 16 to 32 of them, each holding 4 or 8 bytes). Registers are where actual arithmetic happens. Adding two numbers means: copy them into registers, add the registers, copy the result back to memory.
What "running a program" actually means
When you double-click an .exe file (or run ./a.out from a
terminal), the operating system does roughly this:
That fresh region of memory is called the program's process address space. It is a private playground: the program thinks it is the only thing in memory, even though many other programs are running at the same time. The operating system uses hardware trickery called virtual memory to keep them separated.
A program's memory has regions
Within its address space, your program organises memory into a few distinct regions. You will hear about these for the rest of the course, so it helps to meet them now:
- Text / code — the actual machine instructions of your program. Usually read-only.
- Data — global variables, string literals, and other things that exist for the entire run of the program.
- Heap — memory you ask for while the program runs, often with
new(ormallocin C). It stays alive until you release it. - Stack — a tidy area used for function calls and local variables. Each time you call a function, the CPU grows the stack by a small "frame"; when the function returns, the frame is popped off.
We will spend an entire section on each of these. For now you only need the picture: memory is split into regions, each with rules about who can put what there and for how long.
Why this matters for C++
Languages like Python or JavaScript hide memory from you. They give you "objects" and "lists" and quietly manage everything else. That is wonderful for productivity, but it means you cannot really predict where your data lives, how fast access will be, or when memory is freed.
C++ exposes the model. When you write
int x = 42;you are saying "allocate four bytes on the stack, in this function's frame, and put the number 42 in them." When you write
int* p = new int(42);you are saying "allocate four bytes on the heap, store 42 in them,
and give me back the address as p." That distinction has real
performance and lifetime consequences. By the end of the course you
will be making it without thinking.
A tiny step through a program
Let's mentally execute a real example. Read the code, predict what prints, then run it.
Step by step:
- The OS loads the program into memory and jumps to
main. int x = 5;reserves 4 bytes on the stack insidemain's frame and writes5into them.square(x)pushes a new frame on the stack forsquare, copies the value5into a parameter namedn.- Inside
square,int result = n * n;reserves another 4 bytes and stores25. return result;writes25into a special "return value" slot, then popssquare's frame off the stack.- Back in
main,25is copied into the 4-byte slot fory. std::coutwrites characters to the screen via the operating system.return 0;signals "this program succeeded" to whoever launched it; the OS reclaims memory.
You just simulated a CPU in your head. That is the right level of detail to keep in mind for the next several chapters.
Test your understanding
What is the smallest individually-addressable unit of memory in this model?
A bit
A byte
A word (4 or 8 bytes)
A page (typically 4096 bytes)
What does the CPU's instruction pointer do?
It points to the start of the program file on disk.
It holds the memory address of the next instruction to execute.
It tells the operating system which process to schedule next.
It stores the result of the most recent arithmetic operation.
When you call a function in C++, where do its local variables typically live?
In CPU registers exclusively.
In a new frame on the call stack.
On the heap, allocated by new.
In the data segment, alongside global variables.
Why does C++ care so much about where memory comes from (stack vs heap)?
It does not — they are interchangeable.
The stack is faster to read than the heap.
Because the lifetime, allocation cost, and management rules of stack and heap memory are different, and C++ exposes those differences so you can reason about them.
Only the heap can be freed; the stack lives forever.
Next: how your source code becomes machine instructions in the first place.