Visual walkthrough — Stack frames — how function calls work at the memory level
5.1.16 · D2· Coding › C Programming › Stack frames — how function calls work at the memory level
Step 1 — Memory sirf numbered boxes hain, aur ek number "top" yaad rakhta hai
KYA. Computer ki memory (RAM) ko ek lamba column of boxes samjho. Har box ek chhoti si value rakhta hai aur har ek ka ek address hota hai — ek whole number jo use naam deta hai. Figure mein address har box ke left side pe printed hai.
KYU. Jab tak hum "function apna saman kahaan rakhta hai" ki baat nahi kar sakte, humein kisi box ko point karne ka tarika chahiye. Address bas itna hi hai: box ka house-number. Humein ek special helper bhi chahiye jo hamesha yaad rakhe currently-used region kahan khatam hoti hai. Woh helper ek register hai (CPU ke andar ek chhota built-in storage slot) jise stack pointer kehte hain, likha jaata hai .
PICTURE. Orange arrow dekho jis pe likha hai. Yeh data ka box nahi hai — yeh ek finger hai jo us address ko point karta hai jo topmost box ka address hai aur jo hum currently use kar rahe hain.

Step 2 — "Neeche" growth ki direction hai (yeh sabko confuse karta hai)
KYA. Har mainstream CPU (x86, ARM) pe, stack upar se shuru hota hai aur chhote addresses ki taraf grow karta hai. "Stack ko bada karna" matlab hai se subtract karna.
KYU dusri taraf nahi? Yeh ek historical convention hai taaki stack (neeche grow karta hua) aur dusri memory (upar grow karti hui) ek region share kar sakein aur sirf tab collide karein jab program sach mein memory se bahar ho. Yeh key rule tum par burn in ho jaani chahiye:
- — push: hum current top ke neeche naye boxes claim karte hain, isliye address number neeche jaata hai.
- — pop: hum boxes wapas dete hain, isliye address number upar jaata hai.
PICTURE. Do arrows: ek magenta arrow ek push dikhata hai jo ko neeche kheenchta hai (address 1000 → 992), ek violet arrow ek pop dikhata hai jo ko wapas upar jaane deta hai. Same finger, opposite directions.

Step 3 — Ek call ko teen cheezein chahiye, isliye ek frame ke teen parts hote hain
KYA. Jab main ek function f ko call karta hai, teen sawaalon ka jawab dena padta hai. Har jawab f ke private region mein — uske stack frame mein — ek slot ban jaata hai.
KYU yeh teen? Kyunki ek call ko khud kuch aur call karne se interrupt hone ke baad bhi survive karna hai, aur saaf wapas aana hai. Teen sawaal:
| Sawaal jo call ko answer karna hai | Slot jo jawab deta hai |
|---|---|
| "Kaam khatam hone pe main kahaan wapas jump karun?" | return address |
| "Main apne locals kahaan rakhu bina caller ke locals kharab kiye?" | local-variable slots |
| "Mujhe apne locals kaise milenge jab move kare?" | ==frame pointer == |
PICTURE. Ek frame, uske parts mein explode kiya gaya: return address sabse upar (frame ka highest address), phir saved old , phir neeche locals ka fresh region (lowest addresses). Ek green finger ek fixed spot pe planted hai; ek orange finger bilkul neeche baitha hai.

Step 4 — Caller ka kaam: arguments pass karo, phir CALL karo
KYA. f mein jump karne se pehle, caller argument values push karta hai (ya ARM/x64 pe aksar registers mein load karta hai — dekho Calling conventions (cdecl, stdcall)), phir CALL f execute karta hai.
KYU do sub-steps?
- Pehle arguments push karo —
fko woh values chahiye jo use di gayi hain, isliye woh kaheen honi chahiye jahanfunhe read kar sake. CALLbaad mein — x86 peCALLinstruction atomically do kaam karta hai: yeh return address push karta hai (us instruction ka address jo call ke theek baad aata hai) aur phirfpe jump karta hai. Yahi hai "main kahaan wapas aaun?" wale sawaal ka jawab milna.
PICTURE. Left half: main ka frame x ke saath. Do magenta pushes dekho: pehle 3 phir 2, x ke neeche land karte hain, phir ek violet push return address upar drop karta hai. teen boxes neeche crawl kar chuka hai.

Step 5 — Callee ka prologue: BP nail karo, locals ke liye jagah nikalo
KYA. f ke andar pehle kuch instructions boilerplate hote hain jinhein prologue kehte hain. Iss order mein:
push BP— caller ka frame pointer save karo taaki hum baad mein restore kar sakein.BP = SP— apna finger yahaan plant karo, is frame ka base mark karo.SP -= N— ko bytes neeche slide karo taakifke locals ke liye room reserve ho.
KYU har line?
- Old save karo — shared hardware hai; agar hum ise save kiye bina overwrite karein, toh caller apna frame track kho dega. Isliye pehle old value stash karo.
- — ab hamare frame ke andar ek fixed landmark mark karta hai.
- — ek subtraction mein bytes reserve karna har local ko alag alag push karne se sasta hai, aur yeh sabhi locals ko ke relative ek constant distance pe addressable banata hai.
- — locals ke neeche carved hue hain (lower addresses) → subtract.
- — arguments aur return address se pehle push kiye gaye → woh upar baithe hain → add.
PICTURE. f ka poora frame. Green finger saved-old- box ko point karta hai. Uske upar, ke saath labelled, args aur return address hain; neeche, ke saath labelled, freshly carved local slots hain. Orange bilkul neeche rested hai.

Step 6 — Worked trace: add(2,3) ek frame build aur tear down karta hai
KYA. Chalte hain ek real frame ki poori zindagi trace karte hain.
int add(int a, int b) {
int s = a + b; // one local: s
return s;
}
int main(void) {
int x = add(2, 3);
return 0;
}KYU trace karo? Yeh dekhne ke liye ki cleanup sirf ko wapas move karna hai — kuch individually erase nahi hota.
PICTURE. Chaar panels, left se right:
mainmein: stack pe sirfx.- Args +
CALLpush karne ke baad:[x][3][2][retaddr]. addke prologue ke baad:[x][3][2][retaddr][savedBP][s],s = 2+3 = 5computed hai.RETke baad: bilkul upar wapas jump kar chuka hai;addke use kiye hue chaar boxes logically gone hain; value5ek register mein ghar aayi aurxmein store ho gayi.

Step 7 — Recursion: same picture, N baar stack hoti hai
KYA. Recursion koi naya mechanism nahi hai — yeh Step 5 hai jo pehle waale ke khatam hone se pehle dobara ho raha hai. Dekho Recursion.
int fact(int n) {
if (n <= 1) return 1;
return n * fact(n - 1);
}KYU yeh har n "yaad" rakhta hai. Har call apna prologue run karta hai, isliye har ek ko n ke liye apna alag slot milta hai. Teen simultaneous calls ⇒ teen alag n boxes stacked up, har ek neeche waale ka wait kar raha hai.
PICTURE. fact(3) apni gehraai mein: teen frames neeche ki taraf piled, n=3 upar wait kar raha hai, n=2 neeche wait kar raha hai, n=1 sabse neeche 1 return karne wala hai pehle (deepest returns first — strict LIFO). Phir unhe upar unwind hote dekho: .

Step 8 — Degenerate case: ek local ka pointer return karna
KYA. Dangerous edge case. Kya ho agar ek function apne kisi local ka address wapas de?
int *bad(void) {
int local = 42;
return &local; // BUG
}KYU yeh poison hai. Step 6 se humne seekha ki RET sirf ko wapas upar move karta hai — frame ke boxes erase nahi hote, lekin ab woh fair game hain next call ke liye overwrite hone ke liye. Return kiya gaya pointer un boxes ko point karta hai jo ab tumhare nahi hain. Yeh sheer luck se 42 read kar sakta hai, jab tak next function call exactly wahi boxes reuse na kare.
PICTURE. Do panels: (1) bad ke andar, pointer 42 wale box ko point karta hai. (2) return ke baad, us box ke upar chadh chuka hai, aur ek naya call other() aaya hai aur wahan 99 likh diya hai — pointer ab garbage read karta hai.

Ek-picture summary
Upar ki saari baatein ek single frame diagram mein compress ki gayi hain: upar caller region, neeche ek poora callee frame, dono fingers ( nailed down, neeche), har slot labelled kiya gaya hai teeno sawaalon mein se kaunsa sawaal yeh answer karta hai aur kis direction mein push kiya gaya tha.

Recall Feynman: poora walkthrough apne words mein batao
Memory ek tall stack of numbered boxes hai, aur ek finger () hamesha us top box ko point karta hai jo hum use kar rahe hain. Real chips pe "stack grow karna" matlab hai finger neeche chhote numbers ki taraf move karna. Jab ek function doosre ko call karta hai, caller argument values boxes mein daalta hai, phir CALL ek return address bhi daalta hai — ek note jo kehta hai "yahaan wapas aao." Called function phir ek doosra finger () ek fixed landmark pe plant karta hai taaki woh apne locals hamesha find kar sake, aur top finger ko neeche slide karta hai unke liye blank boxes reserve karne ke liye. Real kaam karna matlab hai un boxes ko se fixed distances pe read aur write karna. Jab woh khatam ho jaata hai, woh sirf top finger ko wapas upar slide karta hai — boxes scrub nahi hote, woh sirf abandon ho jaate hain, isliye cleanup instant hai aur isliye unka pointer return karna ek time bomb hai. Recursion yahi ritual hai jo pehle waale ke khatam hone se pehle dobara hota hai, isliye ek local ki kaafi saari copies stack up ho jaati hain, aur sabse deep wala hamesha pehle return karta hai. Yahi last-in-first-out pile call stack hai.
Recall
push pe kis direction move karta hai? ::: Neeche — ek chhote address ki taraf (x86/ARM pe).
KYU locals use karte hain lekin args use karte hain? ::: Locals ke neeche carved hue the (lower addresses → subtract); args aur return address se pehle push kiye gaye the, isliye woh upar baithe hain (add).
KYU &local return karna fail hota hai? ::: Return pe upar move karta hai aur frame ke boxes abandon ho jaate hain; next call unhe overwrite kar sakta hai, isliye pointer reusable/garbage memory ko point karta hai.
fact(3) mein, kaunsa frame pehle return karta hai? ::: fact(1) — sabse deepest wala — strict LIFO.