Zasadniczo @Wibowit napisał prawdę i tylko prawdę, ale nie wiem czy potrzebne było takie zagłębianie się w szczegóły.
Otóż to co napisałeś byłoby sensowne, tylko trochę zbyt dosłownie podchodzisz do pojęcia stosu
.
Stos to pewna abstrakcja, tak naprawdę możesz to sobie wyobrazić tak:
byte stack[1000] // stos (z jakimś ograniczeniem wielkości - stąd się StackOverflowy biorą (tak naprawdę to nie takie proste, bo nie od razu cała pamięć jest zajmowana, ale to już nieważne)).
int stackptr; // pokazuje na ostatni element na stosie
Kiedy jakaś funkcja (powiedzmy A) jest wywoływana, wie że przed stackptr
są jej argumenty a później jakieś śmieci
(tzn. zmienne i argumenty poprzednich funkcji)
[śmieci] [śmieci] [argument] <<stackptr>>
I teraz, jeśli chcesz wywołać jakąś funkcję B, wrzucasz
na stos te parametry:
stack[stackptr++] = 1 // wrzuć pierwszy parametr - 1
stack[stackptr++] = 2 // wrzuć drugi parametr - 2
stack[stackptr++] = 3 // wrzuć trzeci parametr - 3
[śmieci] [śmieci] [argument] [1] [2] [3] <<stackptr>>
I skaczesz do kodu wywoływanej funkcji.
Czyli teraz jesteś w funkcji B.
Dla tej wywołanej funkcji, znowu liczą się tylko jej argumenty a wszystko wcześniej traktuje jako śmieci:
[śmieci] [śmieci] [śmieci] [1] [2] [3] <<stackptr>>
Jesli chcesz użyć parametru, używasz odpowiedniego przesunięcia od stackptr:
stack[stackptr] // ostatni parametr
stack[stackptr - 1] // przedostatni parametr
stack[stackptr - 2] // trzeci od końca parametr
A zmienne lokalne gdzie?
Jeśli funkcja chce mieć jakieś (np. 4) zmienne lokalne, rezerwuje sobie miejsce, o tak:
stackptr += 4
[śmieci] [śmieci] [argument] [1] [2] [3] [nic] [nic] [nic] [nic] <<stackptr>>
I co to daje? Że teraz ma wolne i nieużywane przez nic cztery miejsca na stosie. Jeśli wywoła ona jakąś jeszcze kolejną funkcję C, nie będzie ona ruszała tych czterech wolnych miejsc (bo dla niej to śmieci
). No i właśnie dzięki temu może sobie spokojnie po nich pisać.
A kiedy funkcja B się kończy, cofa stackptr do poprzedniej pozycji
[śmieci] [śmieci] [argument] [1] [2] [3] <<stackptr>> [nic] [nic] [nic] [nic]
A jako że wszystko za stackptr jest już niepotrzebne, a argumenty dla B są już niepotrzebne, sterowanie wraca do funkcji A w takim stanie:
[śmieci] [śmieci] [argument] <<stackptr>>
I super, wszystko na stosie jest jak przed wywołaniem funkcji.
Nie wiem w sumie czy to jest czytelniejsze niż post powyżej, ale starałem się to w miarę obrazowo przedstawić...