Visual walkthrough — Functions — declaration vs definition, prototypes, call by value
Step 1 — A variable is a labelled box in memory
WHAT. Before we can talk about copying, we need to know what gets copied. In C, when you
write int a = 1;, the computer sets aside a small region of memory — think of it as a box —
gives it a name (a) and stores a value (1) inside.
WHY. Everything about call by value is about which box a change lands in. So we must be able to point at a specific box and say "this one, not that one." A box has three things worth naming:
- its name
a— how you refer to it in code, - its value
1— what is stored inside right now, - its address — where in memory the box physically sits (we draw it as a house number).
PICTURE. Two boxes a and b, each with a name written on the lid, a value inside, and a
house-number address underneath.

Step 2 — Calling a function builds a fresh scratchpad
WHAT. When main calls square(v), the machine does not let square reach into main's
boxes. Instead it carves out a brand-new region of memory — a stack frame — just for this call.
Inside that frame it creates the parameter box n.
WHY. A function must be reusable and predictable. If every call scribbled directly on the caller's boxes, two functions could quietly stomp on each other. Giving each call its own private scratchpad keeps them isolated. (The mechanism of how these frames stack up is the subject of Stack and Function Call Mechanism.)
PICTURE. main's frame on the left holds box v = 5. A new frame for square appears on the
right, empty, waiting for its parameter n.

Step 3 — The argument's VALUE is copied across
WHAT. Now the copy happens. C reads the value inside v (which is 5) and writes that
number into n. This is the single act named "call by value."
WHY. The parameter n is initialised from the value, not linked to the box v. It is as if
you photocopied the number 5 and pinned the photocopy into n. After this instant, v and n
have no connection — cut the wire, they just happen to both hold 5 for now.
PICTURE. A pink arrow carries the number 5 out of v and drops it into n. The arrow is a
copy, not a bridge — once drawn, it is gone.

Step 4 — Inside the function, changes stay local
WHAT. Suppose square did more than compute: say it ran n = n * n;. That multiplies the
number in n (making it 25) and writes it back into n — square's own box.
WHY. The assignment target is n, and n lives only in square's frame. There is no line of
sight from n back to v. So v is physically untouched; it still reads 5.
PICTURE. n updates from 5 to 25 inside square's frame. Box v in main's frame is drawn
faded/greyed to shout: nothing changed here.

Step 5 — The frame is destroyed on return
WHAT. square finishes by handing back a value (25), which gets copied into r in main's
frame. Then square's entire frame — including box n — is thrown away.
WHY. This seals the isolation. Even if the function had changed n, that box no longer
exists after the call, so there is provably no way for the change to leak upward. The only thing
that survives the return trip is the single value that was explicitly returned.
PICTURE. Square's frame is crossed out / dissolving; a yellow arrow carries the return value
25 into r. Box n vanishes with the frame.

Recall Why can nothing leak out?
Because the change lands in a box (n) that is destroyed the instant the function returns ::: only the explicitly returned value survives, copied into the caller's box.
Step 6 — Edge case: the swap that fails
WHAT. People expect swap(a, b) to exchange a and b. Let us run it under the rules we just
built and watch it fail.
WHY. This is the classic trap. swap receives copies x and y. It faithfully swaps those
two copies inside its own frame — but a and b in main are different boxes at different
addresses, so they never move.
PICTURE. main holds a=1, b=2. Copies flow into x=1, y=2. Inside swap's frame the arrows
cross (x and y swap to 2 and 1), while a and b sit unmoved. Then swap's frame dies —
taking the swapped copies with it.

Step 7 — The fix: copy the ADDRESS, not the value
WHAT. To let swap reach the originals, we hand it the addresses of a and b using
the & operator. The parameters become pointers (int *x), and *x means "the box that this
address points to."
WHY. Call by value still applies — but now the value being copied is an address. A
photocopy of a house number still leads to the same house. So *x = ... writes through the copied
address, straight into main's real box. (Pointers get their own full treatment in
Pointers in C.)
PICTURE. x holds the address of a (drawn as an arrow pointing back at box a), y
points back at b. Writing *x and *y reaches across the frames and swaps the real boxes.

The one-picture summary

The whole derivation on one board: two frames side by side. On the value path (top) a number is photocopied into the parameter, played with, and the result thrown away with the frame — original untouched. On the address path (bottom) an address is photocopied, and following it edits the original box for real. Same rule (copy the value), two outcomes, because what you copy differs.
Recall Feynman retelling of the whole walkthrough
Imagine your variables are labelled shoeboxes on a shelf. When you call a function, the computer
clears a new shelf for it and puts down empty boxes for its parameters. Then it photocopies the
numbers from your boxes and pops the photocopies into the function's boxes. The function scribbles
all over its photocopies — squares them, swaps them, whatever — but your original boxes upstairs
never move, because the function literally cannot see them. When the function is done, its whole
shelf is swept into the bin; the only thing that survives is the one number it hands back to you.
That is why an ordinary swap fails: it swaps photocopies, then bins them. The one trick to reach
your real boxes is to photocopy the house number of a box instead of its contents — a copied
address still points at the same house, so writing "through" it changes your real data. That is
pointers, and it is still call by value, because you copied the address itself.
Connections
- Pointers in C — the address path (Steps 7–8) in full.
- Stack and Function Call Mechanism — how the frames in Steps 2 and 5 are built and destroyed.
- Scope and Lifetime of Variables — why the parameter box dies on return.
- Arrays as Function Arguments — a place where the "copy" rule surprises you (arrays decay to addresses).
- Recursion — many frames of the same function, each with its own private copies.
- Header Files and Separate Compilation — where the prototype lives when the definition is elsewhere.