Fundamentals of Programming: Stack Frames
We've previously discussed the benefits of using functions and subroutines when programming, but since each function is stored independently, the computer needs to be able to store what it has currently been working on (including its variables and parameters) and put it aside, so it can go to the new function and then be able to return to where it was. This is where a stack frame is used.
Consider the following program:
Sub Main
openFile("birthday_picture.png")
Console.WriteLine("Finished opening file... goodbye!")
End Sub
Sub openFile(fileName as String)
If fileExists(fileName) Then
' code to open file goes here!
Else
Console.WriteLine("The file called {0} doesn't exist!", fileName)
End If
End Sub
Function fileExists(fileNameToCheck as String) as Boolean
Dim filePath as String
filePath = "C:\\Users\\My Pictures\\" + fileNameToCheck
' code to check if filePath exists and return True if it does, or False if it doesn't
End Sub
The program tries to open a file (called birthday_picture.png) by calling the subroutine openFile. This subroutine calls a function to make sure the file exists and based on the boolean value it returns (either True or False), the subroutine will continue to open the file or print out an error message. When the file is opened (or in the case the file doesn't exist, an error is printed out) the program writes a message before finishing.
To understand why a stack frame is needed, consider the very first subroutine the program starts in: Main. Once the program starts executing, it will look at the first line of instructions and go to the subroutine openFile. However, the computer needs to remember to come back to Main once done with openFile, otherwise it will never get to printing out the goodbye message! Similarly if we look at openFile, it has a call to fileExists, but the computer also needs to know to go back to openFile, and at the right point within openFile, otherwise it may try to open a file that doesn't exist!
The way the computer keeps track of all this is by creating a stack frame every time it gets called to another subroutine or function. Within this stack frame, it stores:
- the return address; this is the point it should go back to when it is done with the call
- local variables; these are the variables in the current subroutine/function that it should restore
- parameters; the data that is passed to the function/subroutine
A diagram may help you visualise this:
As the computer encounters a function or subroutine call, it stores the local variables, parameters and current address in memory and adds it to the stack. Once it is done with the call, it removes that frame from the stack and looks at the return address of the next frame (which would belong to the function that called it) and resumes executing at that point. This goes on until the stack is empty (i.e., it returns to the first subroutine in the program) and the program finishes.