Unit 16: Call by Reference
Learning Objectives
After completing this unit, students should:
- understand the differences between call-by-value and call-by-reference
- understand the mechanism we can perform call-by-reference in C using stack and pointers
- know the situations where call-by-reference is useful
- be able to read and write code that uses call-by-references
- know how to write Doxygen documentation to document the parameters of a function.
Call By Reference
In Unit 14, we have seen how an array is being passed by reference. When we pass an array a
into a function, due to array decay, we are passing in the pointer to the first element of the array (&a[0]
). So, what gets copied onto the call stack is the pointer to the array, not the actual array itself. Now, with this pointer, we can modify the elements in the array directly.
Passing Non-Array Variables by References
We mentioned that for all other non-array variables when we pass in a variable, the value of the variable gets copied onto the stack. This mechanism is called call-by-value.
The call-by-value mechanism has its limitation. Sometimes, it is useful for a function to return more than one result. You have seen an example before in your Assignment 2, where, for the collatz
problem, you are supposed to find both the largest stopping time and the value with the largest stopping time.
C functions, however, can only return at most one value. One way to get around this limitation is to use call-by-reference, the other is to use struct
. We will leave the discussion of struct
for another day, so let's see use call-by-reference on non-array variables.
We use call-by-reference by passing in the a pointer to a variable into a function, instead of the value of variable. Here is an example taken from the collatz
problem.
Example: Collatz
1 2 3 4 5 6 7 8 9 10 11 |
|
The method find_max_steps
takes in two pointers. Inside the function, we use the deference operator *
to modify the variable pointed to by the pointers (Lines 2, 3, 7, and 8).
To use this function, we have:
1 2 3 4 5 6 7 8 9 |
|
In Line 4 above, we pass in the address of max_n
and max_num_steps
into find_max_steps
. find_max_steps
updates both variables for us.
Example: Swapping Two Variables
Another example of call-by-reference is a function that swaps two variables. Here is one that swaps two long
variables.
1 2 3 4 5 |
|
To see swap
in action, consider:
1 2 3 |
|
After calling swap
, the value for a
becomes -4, b
becomes 10.
Documenting Call-by-Reference Parameters
A parameter passed as a pointer could be used in three different ways:
- The parameter could be a read-only input, and the main purpose of passing in the value is so that the function has access to the value of the pointer.
- The parameter could be used as a vessel for the function to pass a value to the caller, similar to the parameters
max_n
andmax_num_steps
in the functionfind_max_steps
above. In this case, the value contained in the variable pointed to by the pointer does not matter. - The parameter could be used as both input and output. The value contained in the parameter is read inside the function, and the value is updated from inside the function. For example, the parameters passed to
swap
above.
In CS1010, we will be using the Doxygen
format to document our functions. There are three types of parameters, corresponding to the three situations above: @param[in]
is used to document a read-only parameter (note that this applies to all read-only parameters, not just pointers). @param[out]
is used to document an output-only parameter, and @param[in,out]
is used to document a parameter that is both input and output.
Problem Set
Problem 16.1
Consider the program below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
What would be printed?