Prerequisite: 0454
A parameter is similar to a local variable. However, unlike a local variable, the value of a parameter is specified by the caller. This allows caller-to-function communication.
Observe the following code:
int add(int x, int y) { // line 1
return x+y; // line 2
} // line 3
int main() { // line 4
int x; // line 5
x = add(23,56); // line 6
return 0; // line 7
} // line 8
The function definition starting on line 1 includes two parameters, x
and y
. Parameters are specified in the parentheses of a function definition, comma-separated. Each parameter has its own type specifier. In this case, x
and y
are both integers. Line 2 references the parameters, computes the sum, and returns the sum as the return value.
The trace is as follows:
comments | line# | x |
x |
y |
return |
---|---|---|---|---|---|
5 | x |
||||
? | |||||
each parameter is a column, and the values in the invocation are used to initialize the parameters based on their positions | 6 | x |
y |
return | |
23 | 56 | 6: x=?; |
|||
16 | |||||
17 | 6: x=79; |
||||
parameters are deallocated upon returning | x |
y |
|||
6: x=79; |
79 | ||||
7 | x |
||||
post |
Invoking a function with parameters requires the caller to specify the values of the parameters (each value is called an argument). The parameters are allocated in a trace before return
or ret line #
. When the function is executed, the parameters are accessed like local variables.
Parameters are deallocated when a function returns.
Up to now, there has been no need to reference columns in a trace. However, the following topic requires certain columns to be identified. As a result, it becomes necessary to name columns like in a spreadsheet. It is also helpful to be able to reference rows in some cases.
As a result, the format of the tracing of code is adjusted accordingly. For easier reference to line numbers, the algorithms will be represented in a spreadsheet as follows.
A | |
---|---|
1 | int f(int n) { |
2 | if (n<2) { |
3 | return 1; |
4 | } else { |
5 | return n*f(n-1); |
6 | } |
7 | } |
8 | int main() { |
9 | int x; |
10 | x = f(3); |
11 | return 0; |
12 | } |
The corresponding trace is as follows:
A | B | C | D | E | F | G | H | I | |
---|---|---|---|---|---|---|---|---|---|
1 | pre | ||||||||
2 | 8 | x | |||||||
3 | ? | ||||||||
4 | 10 | n | return | ||||||
5 | 3 | 10: x=?; | |||||||
6 | 1 | ||||||||
7 | n<=1 is F | 2 | |||||||
8 | 5 | n | return | ||||||
9 | 2 | 5: return n*?; | |||||||
10 | 1 | ||||||||
11 | n<=1 is F | 2 | |||||||
12 | 5 | n | return | ||||||
13 | 1 | 5: return n*?; | |||||||
14 | 1 | ||||||||
15 | n<=1 is T | 2 | |||||||
16 | 3 | 5: return n*1; | |||||||
17 | |||||||||
18 | 5: return n*1; | 5: return n*2; | |||||||
19 | |||||||||
20 | 5: return n*2; | 10: x=6; | |||||||
21 | |||||||||
22 | 10: x=6; | 6 | |||||||
23 | 11 | ||||||||
24 | post |
The type of parameter discussed up to this point is “passed by value”. The column representing the parameter has the value of the parameter. As such, this kind of parameter acts much like a local variable.
Although the return value of a function can be used to return the result of a function, many functions have more effects than can be reflected by a single return value. Other times, a function also needs to modify items that do not “belong” to it. Most programming languages, like C++, support a second type of parameter called “passed by reference”.
A pass-by-reference parameter is a reference to something else. A change to a pass-by-reference parameter does not modify the column that represents the parameter but the column that the parameter references. Here is an example:
A | |
---|---|
1 | void f(int &n) { |
2 | n = n + 1; |
3 | } |
4 | int main() { |
5 | int x; |
6 | x = 5; |
7 | f(x); |
8 | return 0; |
9 | } |
The corresponding trace is as follows:
A | B | C | D | E | |
---|---|---|---|---|---|
1 | Comments | line# | |||
2 | pre | ||||
3 | 4 | x | |||
4 | ? | ||||
5 | 6 | 5 | |||
6 | parameter n is allocated like any other parameter | 7 | n | ret line # | |
7 | note how column D is a reference to column C | ref col C | 8 | ||
8 | 1 | ||||
9 | any reference to parameter n is deferred to column C | 2 | 6 | ||
10 | parameter n is deallocated like any other parameter | 3 | |||
11 | 8 | ||||
12 | post |
Trace the following code:
void f(int &x, int &y) {
int t;
t = x;
x = y;
y = t;
}
int main() {
int j,k;
j = 2;
k = 5;
f(j,k);
return 0;
}
In a function definition, parameters are specified. x
and y
are parameters in the following function definition:
int f(int x, int y) {
return x+y;
}
In a function invocation, arguments are specified. 23
and 65
are arguments in the following function invocation:
x = f(23,65);
Both pass-by-value and pass-by-reference parameters require columns to be allocated, one for each parameter. The allocation of columns is the leftmost available column. After a column is allocated, it is labeled with the name of the parameter.
If a parameter of the called function is passed by value, then the argument in the function call is evaluated as a general expression. The value of the expression becomes the initial value of the column of the parameter.
If a parameter of the called function is passed by reference, then the argument in the function call should be something that can be on the left-hand side of an assignment. This means the argument should have a column associated with it. The column corresponding to the parameter should be documented as a reference to the column specified by the argument.
There are four possible cases:
x
is passed-by-value to parameter y
.
void f(int y) {} void g(int x) { f(x); }
x
as an expression; the parameter y
starts with the value of the expressionx
is passed-by-reference to parameter y
.
void f(int &y) {} void g(int x) { f(x); }
x
on its own. The column of parameter y
references the column of x
.x
is passed-by-value to parameter y
.
void f(int y) {} void g(int &x) { f(x); }
x
as an expression; the value of the expression becomes the value of parameter y
.x
is passed-by-reference to parameter y
.
void f(int &y) {} void g(int &x) { f(x); }
x
on its own. The column referenced by x
becomes the column referenced by y
.When a pass-by-value parameter is referenced, the value of the parameter is retrieved in the right-most column that is labeled by the name of the parameter.
When a pass-by-reference parameter is referenced, the value of the column that is referenced by the parameter is retrieved.
When a function returns, all parameters are deallocated along with the return
or ret line #
columns.
In C/C++, arrays can only be passed by reference. Furthermore, an array passed as a parameter only knows where to find the first column corresponding to the array. Observe the following example:
A | |
---|---|
1 | int sumArray(int a[], int n) { |
2 | int sum; |
3 | int i; |
4 | i=0; |
5 | sum=0; |
6 | while (i<n) { |
7 | sum=sum+a[i]; |
8 | i=i+1; |
9 | } |
10 | return sum; |
11 | } |
12 | int main() { |
13 | int x; |
14 | int b[5]; |
15 | b[0]=4; |
16 | b[1]=2; |
17 | b[2]=6; |
18 | b[3]=1; |
19 | b[4]=8; |
20 | x=sumArray(b,3); |
21 | return 0; |
22 | } |
A few lines are worth noting:
n
does not match the actual number of elements in array b
The trace corresponding to the above code is as follows:
A | B | C | D | E | F | G | H | I | J | K | L | M | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | Comments | line# | |||||||||||
2 | pre | ||||||||||||
3 | 12 | x | b[0] | b[1] | b[2] | b[3] | b[4] | ||||||
4 | ? | ? | ? | ? | ? | ? | |||||||
5 | 15 | 4 | |||||||||||
6 | 16 | 2 | |||||||||||
7 | 17 | 6 | |||||||||||
8 | 18 | 1 | |||||||||||
9 | 19 | 8 | |||||||||||
10 | 20 | a | n | return | |||||||||
11 | ref col D | 3 | 20: x=?; | ||||||||||
12 | 1 | sum | i | ||||||||||
13 | ? | ? | |||||||||||
14 | 4 | 0 | |||||||||||
15 | 5 | 0 | |||||||||||
16 | i<n is T | 6 | |||||||||||
17 | 7 | 4 | |||||||||||
18 | 8 | 1 | |||||||||||
19 | i<n is T | 6 | |||||||||||
20 | 7 | 6 | |||||||||||
21 | 8 | 2 | |||||||||||
22 | i<n is T | 6 | |||||||||||
23 | 7 | 12 | |||||||||||
24 | 8 | 3 | |||||||||||
25 | i<n is F | 6 | |||||||||||
26 | 10 | 20: x=12; | |||||||||||
27 | |||||||||||||
28 | 20: x=12; | 12 | |||||||||||
29 | 21 | ||||||||||||
30 | post |
The most important part of this trace is what line 7 does, specifically the evaluation of a[i]
. a
is a parameter; it is easy to locate it as the right-most column labeled a
. However, because it is used as an array (hinted by the use of the brackets []
), the parameter as a reference to column D is where the referenced array starts. For example, when variable i
has a value of 2, the idea is to figure out where element 2 should be at if the beginning of the array starts at column D. The calculation is as follows:
a[0]
a[1]
a[2]