Parameter Passing by Reference


If you are not familiar with functions and parameter passing in general, you may find it helpful to review the web pages entitled Functions and Parameter Passing and Parameter Passing in C++. This document first discusses concepts from Chapter 6 in our textbook about functions and parameter passing, and then describes practices related to Chapter 9 about pointers. If you have not yet reached Chapter 9 in out textbook, you can skip the last section about pointers and indirection.

Before studying "parameter passing by reference", a student should develop a clear understanding of the simpler technique of "parameter passing by value". So we start with this concept below.

Single Parameter Passing - by Value

The C++ Language allows any function to return a single value through its function name, provided that the identifier was declared with a data type appropriate to the value being returned. For example, if we wanted a function that would acquire a person's age from the keyboard and return it to the parent process, we might write the source code as follows:

   int ReadAge ()   /* Function Header */

      {
         int A;  /* Define (allocate) a local variable to temporarily store an age */
         cout << "Enter your age: ";  /* Prompt for Age  */
         cin >> A;  /* Read keyboard input buffer for a decimal integer */
         return A;   /* Send A back to the parent via the function label */
      }      /* Local variable A is abandoned here */

Based on the function header, the function identifier ReadAge is declared as an integer, meaning that it can store a whole number (to be used by its parent function - main). Notice that the ReadAge function has an empty formal parameter list, meaning that the function receives no data from its parent when called. The return statement causes the contents of local variable A to be assigned into the function label ReadAge which is typically a global identifier known by main (and other functions). The function above could be called by any program that included it and had an integer variable declared to receive the returned value. If we wrote a program with an integer variable named AGE, we could call the function above with the statement:

   AGE = ReadAge ();

The statement above calls the function ReadAge to request and return input that was read from the keyboard. The calling function (main) does not pass any data into this function when it starts, so the "actual parameter list" (following the function label in parentheses) is empty. Because the function ReadAge returns a value, it is handled like a value and assigned into a variable.

When a parameter is passed from one function to another by copying the value itself into an identifier known by the receiving function, we refer to that passage as "passing by value". This is the easiest way to pass a parameter. But it is not always possible. For example, when we want a function to return more than one value to it's parent, the method described above is not suitable. A function has only one label, so we cannot use that label to return more than one value. Another method for parameter passing is needed that does not require the use of the function name. For this situation we pass parameters by reference. This technique uses either reference variables or pointers to pass information about the addresses of the intended receiving variables into a function, which then uses that information (rather than the funcutions's single identifier) to return as many parameters as need to the parent function.


Parameter Passing Techniques Compared

The rest of this document illustrates three different techniques for passing parameters into a child function and then returning a value back from that function to the parent function that called it. The child function in each complete program code example accomplishes the same objective: to receive a floating point number, passed-in from the main function, and then to divide the number by 4 and return the result to the calling function (main), replacing the original number with one quarter its original value. The name of the function ("quarter") will be the same in each sample program, but the techniques used for the passing of the parameters will be quite different. In each of the code examples below, pay attention to both: the statements defining the function quarter, and the statement in the main function that calls (executes) the quarter function.


Example of C++ Code to Pass Parameters by Value

// param_pass_value.cpp
// Demonstrating: "passage by value"

#include <iostream>
using namespace std;

// CHILD FUNCTION (Must be declared ahead of its calling statement)

float Quarter (float N)
/* Formal parameter N receives a float value from main's variable Num because of
   its use in main as the actual parameter in the calling statement for Quarter */
{
    float R;    // Local variable to hold the result of a calculation
    R = N/4;    // Divide N by 4 and assign result to local variable R
    return R;   // Terminate function and pass R into identifier Quarter    
/*  Note: the three statements above could be written more simply as just:
    return N/4;
    elminating the need to allocate and use a local variable, R.
    The function identifier Quarter is involved in the return of the value,
    so it is declared as data type "float". */
}

// PARENT FUNCTION

int main()
{
    float Num;  // A number entered by the user and quartered
    cout << "Enter a number to be quartered: ";
    cin >> Num;
    Num = Quarter (Num); // Send Num and assigned returned value back into it
    cout << "One quarter of that value is " << Num << endl;
    return 0;   // Terminate function and pass 0 into identifier main
}


Example of C++ Code to Pass Parameters Reference - Using Reference Variables

A reference variable is an identifier being used as an alias for another variable (typically outside of the current function's scope). The use of a reference variable as a formal parameter allows any change to it to alter the value in its related actual parameter, unlike normal parameters which normally receive copies of the data from actual parameters, but do not allow changes to be sent back to them. The passage of data into a function via a reference variable is referred to as passage by reference. A reference variable is declared in the formal parameter list of a function by placing the symbol & (ampersand) immediately after the data type indicator (as in: int &). The blank space is optional. The data type indicated for the reference variable must match the data type of its related actual parameter, which must be a variable, not any type of constant. For example, the declaration for a reference variable named N in the code example below as an alias for an actual parameter of type float is:

   float &N
In the declaration above, the identifier N acts as a "reference to a float". Although the ampersand (&) touches the identifier, it is not part of it. Note that the identifier is just N, not &N.

Example of C++ Code to Pass Parameters Reference - Using Reference Variables

// param_pass_refvar.cpp
// Demonstrating: "passage by reference" using a "reference variable"

#include <iostream>
using namespace std;

// CHILD FUNCTION (Must be declared ahead of its calling statement)

void Quarter (float &N)
/* Formal parameter N is declared as a "reference variable" as indicated by the
   ampersand (&) following the data type indicator (float in this example).
   It relates to main's variable Num because of its use in the main function
   as the actual parameter in the calling statement for Quarter */
{
    N = N/4;  // Divide N (which is Num) by 4 and reassign it back to N (Num)
    return;   // Empty return optional, but not used for data passage    
/*  Because N is an alias for Num (the actual argument in the parent,
    any change to N is also a change to Num.
    The function identifier Quarter is not involved in the return of the value,
    so it is declared as data type "void". */
}

// PARENT FUNCTION

int main()
{
    float Num;  // A number entered by the user and quartered
    cout << "Enter a number to be quartered: ";
    cin >> Num;
    Quarter (Num); // Send Num which is altered by Quarter
    cout << "One quarter of that value is " << Num << endl;
    return 0;   // Terminate function and pass 0 into identifier main
}

Everything beyond this point in this document relates to Chapter 9 about pointers. If you have not yet reached Chapter 9 in out textbook, you can skip the rest of this content.

Example of C++ Code to Pass Parameters Reference - Using a Pointer and Indirection

// param_pass_refptr.cpp
// Demonstrating: "passage by reference" using a "pointer variable"

#include <iostream>
using namespace std;

// CHILD FUNCTION (Must be declared ahead of its calling statement)

void Quarter (float *N)
/* Formal parameter N is declared as a "pointer". N receives the address of main's
   variable Num because it was accessed using the unary & ("address of") operator
   in main as the actual parameter in the calling statement for Quarter */
{
    *N = *N/4;  // Dereference N (which points at Num) to alter its value.
    return;   // Empty return optional, but not used for data passage    
/*  N is a pointer that contains the address of Num (the actual argument in the
    parent function (main). The prefix use of the unary dereferencing operator *
    allows us to refer to the actual argument Num without using its identifier
    Num (which is not within the scope of the function Quarter).
    The function identifier Quarter is not involved in the return of the value,
    so it is declared as data type "void". */
}

// PARENT FUNCTION

int main()
{
    float Num;  // A number entered by the user and quartered
    cout << "Enter a number to be quartered: ";
    cin >> Num;
    Quarter (&Num); // Send the ADDRESS OF Num (altered thru indirection).
    cout << "One quarter of that value is " << Num << endl;
    return 0;   // Terminate function and pass 0 into identifier main
}

Multiple Parameter Passing - by Reference - Using a Pointer and Indirection

Consider the following situation that would involve passing more than one (two in this case) parameters from a child function back to its parent. If we wanted a function that would acquire both a person's height in feet (floating point data) and weight in whole pounds from the keyboard and return both of them to the parent process, we could write the source code as follows:

   void ReadHandW (float *HPTR, int *WPTR)   // Function Header

      {
         float H;  // Height in feet
         int W;    // Weight in pounds
         cout << "Enter your height in feet (decimals OK): ";
         cin >> H;  // Read keyboard input buffer for a float
         cout << "Enter your weight in pounds (whole number): ";
         cin >> W;  // Read keyboard input buffer for a float
         *HPTR = H;  // Return H by using a pointer to a variable in the parent
         *WPTR = W;  // Return W by using a pointer to a variable in the parent
      }  // All local variables and parameters are abandoned here

Based on the function header, the function name ReadHandW is declared as void, meaning that it can store no data. However, the ReadHandW function has a formal parameter list that is defined to receive pointers (references to addresses of variables in the parent). The last two statements at the end of the function use indirection (assignment using the pointers) to return the two parameters to the parent function. The function label is not involved in returning the parameters and no return statement is used.

This function could be called by any program that included it and had both float and integer variables declared to receive the returned values. If we wrote a program with a float variable named HEIGHT and an integer variable named WEIGHT, we could call the function above with the statement:

   ReadHandW (&HEIGHT, &WEIGHT);  // Call a function, passing pointers to intended target variables

The statement above calls the function ReadHandW to acquire and return two items of input to be read from the keyboard. The calling function (main) passes the addresses of the target variables into this function when it starts. Notice the use of the ampersand operators on the actual parameter labels. The function ReadHandW returns its parameters indirectly to the variables using the addresses it was passed. Because it does not use its name to hold any of the values being returned, there is no assignment shown in the calling statement.

PATH: Instructional Server> COP 2000> Examples>