Sitemap

Call Stack and Stack Frames

5 min readSep 23, 2025

--

1. What is the Call Stack and How It Works?

The Call Stack is a special region of your computer’s memory that works like a stack of plates. It follows a “Last-In, First-Out” (LIFO) rule. The last item you put on the stack is the first one you take off.

The Call Stack’s job is to manage the flow of your program’s function calls. When a function is called, it gets “pushed” onto the stack. When it’s finished, it gets “popped” off. This simple mechanism keeps track of where your program is and where it needs to go back to.

Every time a function is called and pushed onto the stack, a dedicated block of memory called a Stack Frame (or Activation Record) is created for it. This stack frame contains all the information the function needs to do its job, including:

  • Parameters: The values passed to the function.
  • Local Variables: Variables declared inside the function.
  • Return Address: The address in the code that the program must return to after the function is done. This is the most crucial part.

Let’s walk through a simple example to see it in action.

Imagine this C-style program:

void sayHello(int times) {
// Line A
printf("Hello there!\n");
// Line B
}
void doStuff() {
// Line C
int number = 5;
// Line D
sayHello(number);
// Line E
printf("Finished doing stuff.\n");
// Line F
}
int main() {
// Line G
doStuff();
// Line H
return 0;
}

Here’s how the Call Stack manages this:

  • Program starts: The main() function is called. A stack frame for main() is pushed onto the Call Stack. This frame contains its local variables (if any) and its return address (which, for main, is typically the program's exit point).
  • main() calls doStuff(): The program reaches Line G. The next instruction is to call doStuff(). A stack frame for doStuff() is created and pushed on top of main's frame. This new frame stores doStuff's return address (Line H) and its local variables (like number).
  • doStuff() calls sayHello(): The program executes up to Line D. The next instruction is to call sayHello(). A stack frame for sayHello() is created and pushed on top of doStuff's frame. This frame stores its return address (Line E), its parameter (times), and any local variables.
  • sayHello() finishes: The sayHello() function completes its work (executes up to Line B). The program looks at the return address stored in sayHello's stack frame, which is Line E. The sayHello() stack frame is then popped off the stack. The stack now only contains the frame for doStuff() and main(). Control returns to Line E in doStuff().
  • doStuff() finishes: The doStuff() function continues from Line E and executes to Line F. It is now complete. The program looks at the return address in doStuff's stack frame (Line H). The doStuff() stack frame is popped off the stack. Control returns to Line H in main().
  • main() finishes: The main() function executes its final line and returns 0. Its return address is the program's exit. The main() stack frame is popped off the stack, and the program terminates.

This process ensures that no matter how many functions are nested, the program always knows exactly where to go back to after a function call completes.

The Secret Life of Your Code: A Fun Guide to the Call Stack

Have you ever wondered what happens behind the scenes when your code runs? When one function calls another, and then that one calls another, how does the computer keep track of where to return?

Get Cyber Gee’s stories in your inbox

Join Medium for free to get updates from this writer.

It’s all thanks to a neat, little helper called the Call Stack.

Think of the Call Stack like a stack of plates at a buffet. When a new person (a new function) comes up, they put their plate on top. When someone (a function) finishes their meal, they take their plate off the top. You can’t just take a plate from the middle — it would be chaos!

This is the “Last-In, First-Out” (LIFO) principle, and it’s exactly how your computer manages every single function call.

The Magic Is in the “Frames”

Every time your program calls a function, it doesn’t just put the function’s name on the stack. It creates a complete little workspace for that function, known as a Stack Frame.

Imagine your code running main(). A main stack frame is created and placed at the bottom of the stack. This frame contains everything main needs to work: its local variables and, most importantly, the address of the next instruction after it's done.

Now, let’s say main() calls doStuff(). A new, completely separate stack frame for doStuff() is placed right on top of main's. This new frame has its own local variables and a crucial piece of information: doStuff's return address, which points back to the line in main() that called it.

When doStuff() finishes, its entire stack frame is instantly removed. The computer then looks at the frame now on top (the main frame) and continues executing from where it left off, using the return address that was patiently waiting there.

What About Recursion?

The Call Stack is also what makes recursion possible. A recursive function is one that calls itself. Each time it calls itself, a new stack frame is created and pushed onto the stack.

For example, a function to calculate a factorial might call itself over and over. Each call gets its own stack frame until a “base case” is reached (e.g., when the number is 1). Then, the stack begins to “unwind” as each function completes and its frame is popped, allowing the results to be returned back down the chain of calls.

What Can Go Wrong? The dreaded “Stack Overflow”

Remember the stack of plates analogy? What happens if you keep adding plates without anyone ever taking them off? The stack gets too high and eventually falls over!

This is what a stack overflow error is. It happens when a program creates too many stack frames — usually due to an infinite recursion loop — and runs out of the limited memory allocated for the Call Stack. The program crashes because it has no more room to create new stack frames.

--

--