There are three ways in C++ to pass arguments to a function:
pass-by-value
pass-by-reference with a reference argument
pass-by-reference with a pointer argument.
Chapter 6 compared and contrasted the first two. Here, we explain pass-by-reference with a pointer argument.
Chapter 6 showed that return
can return one value from a called function or simply return control. You also learned that arguments can be passed to a function using reference parameters, which enable the called function to modify the original values of the arguments in the caller. Reference parameters also enable programs to pass large data objects to a function without the overhead of pass-by-value which, of course, copies the object. Pointers, like references, also can be used to modify variables in the caller or to pass large data objects by reference to avoid the overhead of copying the objects.
You can use pointers and the indirection operator (*
) to accomplish pass-by-reference (exactly as pass-by-reference is done in C programs—C does not have references). When calling a function with a variable that should be modified, the address of the variable is passed. This is normally accomplished by applying the address operator (&
) to the name of the variable whose value will be modified.
Figures 8.6 and 8.7 present two versions of a function that cubes an integer. Figure 8.6 passes variable number
by value (line 12) to function cubeByValue
(lines 17–19), which cubes its argument and passes the result back to main
using a return
statement (line 18). The new value is assigned to number
(line 12) in main
. The calling function has the opportunity to examine the function call’s result before modifying variable number
’s value. For example, we could have stored the result of cubeByValue
in another variable, examined its value and assigned the result to number
only after determining that the returned value was reasonable.
Figure 8.7 passes the variable number
to function cubeByReference
using pass-by-reference with a pointer argument (line 13)—the address of number
is passed to the function. Function cubeByReference
(lines 18–20) specifies parameter nPtr
(a pointer to int
) to receive its argument. The function uses the dereferenced pointer—*nPtr
, an alias for number
in main
—to cube the value to which nPtr
points (line 19). This directly changes the value of number
in main
(line 10). Line 19 can be made clearer with redundant parentheses:
*nPtr = (*nPtr) * (*nPtr) * (*nPtr); // cube *nPtr
A function receiving an address as an argument must define a pointer parameter to receive the address. For example, the header for function cubeByReference
(line 18) specifies that cubeByReference
receives the address of an int
variable (i.e., a pointer to an int
) as an argument, stores the address in nPtr
and does not return a value.
Function cubeByReference
’s prototype (line 7) contains int*
in parentheses. As with other types, it isn’t necessary to include the names of pointer parameters in prototypes— parameter names included for documentation purposes are ignored by the compiler.
Passing a variable by reference with a pointer does not actually pass anything by reference— a pointer to that variable is passed by value and is copied into the function’s corresponding pointer parameter. The called function can then access that variable in the caller simply by dereferencing the pointer, thus accomplishing pass-by-reference.
Figures 8.8–8.9 analyze graphically the execution of Fig. 8.6 and Fig. 8.7, respectively. In the diagrams, the values in rectangles above a given expression or variable represent the value of that expression or variable. Each diagram’s right column shows functions cubeBy-Value
(Fig. 8.6) and cubeByReference
(Fig. 8.7) only when they’re executing.