14 Intermediate C Programming
Function f3 calls f2 at line 15, and f2 calls f1 at line 8. When f1 finishes, the program
continues from the line after calling f1 (line 9). When f2 finishes, the program continues
from the line after calling f2 (line 16). How does the program know where to continue after
a function finishes? When f3 calls f2, the machine-code equivalent to “line number 16” is
pushed to the stack memory. Fig. 2.4 shows the flow of function calls when running this
program.
FIGURE 2.4: The flow of the program with the three functions.
Imagine that the line after each function call is marked as a return location (RL), as
shown in Fig. 2.5. This book uses line numbers as the return locations. The call stack in
this book is a simplified conceptual model and does not reflect any specific processor. Real
processors use program counters instead of line numbers.
FIGURE 2.5: The return locations (RLs) are marked at the lines after calling f2 (RL A)
and f1 (RL B).
Why is the last in, first out nature of stack memory important? The stack memory
stores the reverse order of function calls. This is how the program knows that it should
continue from RL B instead of RL A after f1 finishes. The program uses the stack memory to
remember the return locations. This stack memory is also called the call stack (or callstack),
and every C program has one to control the flow of execution of its functions. Almost all
computer programming languages employ this scheme.
As our three-function program executes, the call stack may appear as follows: When f3
calls f2, the line number after calling f2 (RL A) is pushed to the call stack.
line number (16) after calling f2, i.e., RL A
Stack Memory 15
When f2 calls f1, the line number after calling f1 (RL B) is pushed to the call stack.
line number (9) after calling f1, i.e., RL B
line number (16) after calling f2, i.e., RL A
When f1 finishes, the line number 9 is popped and the program continues at this line
number (9). The call stack now has line number 16.
line number (16) after calling f2, i.e., RL A
When f2 finishes, the line number is popped and the program continues at this line num-
ber (16). Programmers do not need to worry about marking return locations; the compiler
takes care of inserting the appropriate code to do this.
It is instructive to note why the stack must store the return locations. Consider this
example:
void f1 ( void)1
{2
// ...3
}4
5
void f2 ( void)6
{7
f1 () ;8
// RL A9
// some statement s ...10
f1 () ;11
// RL B12
// ...13
}14
Function f1 is called in two different locations (line 8 and line 11). When f1 is called
the first time at line 8, the program continues from line 9 (RL A) after f1 finishes. When
f1 is called the second time at line 11, the program continues from line 12 (RL B) after f1
finishes. A call stack is a simple scheme to manage the fact that, since the same function
(f1) can be called from multiple places, something must track the next line of code to
execute.
The rules for the call stack can be summarized as follows:
When a function is called, the line number after this call is pushed onto the call stack.
This line number is the “return location” (RL). This is the place from which the
program will continue after the called function finishes (i.e., returns).
If the same function is called from multiple lines, then each call has a corresponding
return location (the line after each function call).
When a function finishes, the program continues from the line number stored at the
top of the call stack. The top of the call stack is then popped.
2.3.2 Function Arguments
To understand function arguments, we must elaborate on the rather simplified examples
seen so far. To start with, most functions take input arguments and have return values. The
Merriam-Webster Dictionary defines an argument as “one of the independent variables upon
whose value that of a function depends”. For a mathematical function, such as f (x, y, z),
16 Intermediate C Programming
the variables x, y, and z are the arguments of the function f. In C programs, functions have
a similar syntax. Consider the following example:
void f1 ( i n t a , char b , double c)1
{2
// ...3
}4
5
void f2 ( void)6
{7
f1 (5, m , 3.7) ;8
// RL A9
// ...10
}11
The inputs a, b, and c are the arguments for f1. When f1 is called, f2 must provide
three arguments and this information is pushed onto the call stack. The call stack stores
the arguments and their values above the return location.
Symbol Value
c 3.7
b ‘m’
a 5
Return Location line 9
Remember that there are no symbols inside of a computer program. Instead, as pre-
viously discussed, the computer’s memory has only addresses and values. Thus, the table
above is extended with another column to show the addresses. Every value has a unique
address—the arguments are stored in different physical parts of the computer’s circuitry—
and this property is guaranteed by the operating system and the hardware. A programmer
has no control over the precise addresses used. The addresses can vary widely on different
types of computers. This book uses 100, 101, ... for these addresses. By convention, the
addresses start from a smaller number at the bottom and increase upward.
Symbol Address Value
c 103 3.7
b 102 ‘m’
a 101 5
Return Location 100 line 9
The return location and the arguments together form a frame for the called function f1.
A frame occupies a contiguous chunk of memory. The above table can now be extended to
show the frame that the symbols, addresses, and values belong to.
Frame Symbol Address Value
f1
c 103 3.7
b 102 ‘m’
a 101 5
Return Location 100 line 9
What happens when there is another function call? Consider the following example:
void f1 ( i n t t , int u)1
{2
// ...3
Stack Memory 17
}4
5
void f2 ( i n t a , int b)6
{7
f1 (a - b , a + b) ;8
// RL B9
// ...10
}11
12
void f3 ( void)13
{14
f2 (5, -17);15
// RL A16
// ...17
}18
Function f3 calls f2 so f2’s frame is pushed to the call stack. Argument a’s value is 5
because that is the value given to a when f3 calls f2 at line 15. Similarly, argument b’s
value is 17 because that is the value given to b when f3 calls f2 at line 15.
Frame Symbol Address Value
f2
b 102 17
a 101 5
Return Location 100 line 16
Function f2 calls f1 and f1’s frame is pushed onto the call stack. Argument t’s value is
22 because that is the value of ab at line 8. Similarly, argument u’s value is 12 because
that is the value of a + b at line 8.
Frame Symbol Address Value
f1
u 105 12
t 104 22
Return Location 103 line 9
f2
b 102 17
a 101 5
Return Location 100 line 16
Please remember that frames and symbols are for humans only. Computers do not under-
stand frames and symbols. Instead, they only work with addresses and values. Previously,
in Section 2.3.1, we listed the rules of the call stack; now we add some more.
If a function has arguments, then the arguments are stored above the return location.
The arguments and the return location together form the frame of the called function.
When a function is called, the line number after this call is pushed onto the call stack.
This line number is the “return location” (RL). This is the place from which the
program will continue after the called function finishes (i.e., returns).
If the same function is called from multiple lines, then each call has a corresponding
return location (the line after each function call).
When a function finishes, the program continues from the line number stored at the
top of the call stack. The top of the call stack is then popped.
18 Intermediate C Programming
2.3.3 Local Variables
If a function has local variables, then the local variables are stored in the call stack.
Consider the following program:
void f1 ( i n t k , in t m , int p)1
{2
int t = k + m;3
int u = m * p;4
}5
6
void f2 ( void)7
{8
f2 (5 , 11 , -8) ;9
// RL A10
}11
The arguments k, m, and p are stored above the return location A. The local variables
t and u are stored on the call stack above the arguments.
Frame Symbol Address Value
f1
u 105 -88
t 104 16
p 103 -8
m 102 11
k 101 5
Return Location 100 line 12
Now one more call stack rule must be added.
If a function has local variables, then the local variables are stored above the argu-
ments.
If a function has arguments, then the arguments are stored above the return location.
The arguments and the return location together form the frame of the called function.
When a function is called, the line number after this call is pushed onto the call stack.
This line number is the “return location” (RL). This is the place from which the
program will continue after the called function finishes (i.e., returns).
If the same function is called from multiple lines, then each call has a corresponding
return location (the line after each function call).
When a function finishes, the program continues from the line number stored at the
top of the call stack. The top of the call stack is then popped.
Local variables are always stored on the stack, where they reside for the duration of the
function call. They exist in contrast to “global variables”, which persist between function
calls. Global variables are usually specified at the top of a given source file, and any function
can read and write to them. While sometimes convenient, global variables can lead to subtle
software bugs. In 1973, Wulf et al. wrote an article, “Global Variables Considered Harmful”.
It explained in some detail why programmers should avoid global variables. The software
community generally concurs, and use of global variables has been strongly discouraged
since then. Although C allows global variables, well-written software almost always avoids
global variables. The main problem is that global variables may be changed anywhere in a
program. As the program becomes larger and more complex, it becomes increasingly harder
to track the places where these global variables may change. Losing track of the changes
can often lead to surprising behavior in the program. For further information, please read
Wulf’s paper to understand why global variables are problematic. Although global variables
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset