Call-by-Reference Parameters

Other than call-by-value, C++ has another mechanism for passing data between the calling function and the called function. This second mechanism is known as call-by-reference.

  1. The formal arguments used in a call-by-reference are referred to as reference arguments. These formal arguments must be identified by putting the symbol & following the type of the argument in the parameter list in both the function prototype and the header of the function definition. However, the actual arguments must not have the & symbol, nor any data type specification.

  2. A function can use any combination of value and reference arguments.

    For example

    void do_stuff(int par1_value, int& par2_ref);

  3. In the call-by-reference method, the compiler passes the memory addresses (not their values) of the actual arguments in the called function's data area so that the actual arguments and their corresponding formal parameter both share the same memory location. This is how the formal parameters get their values during a function call.

  4. The actual arguments used in the function call must be variables since their addresses are passed to the function. Literals and expressions cannot be used as actual arguments since they do not have an address associated with them.

  5. You can think of the actual arguments and their formal parameters as the same variables.

  6. Changes in the values of the formal parameters within the body of the function directly affect the values of the corresponding actual arguments. Therefore results computed by the function can be returned to the calling function without using the return statement, and more than one result can be returned.

  7. The call-by-reference method is much more versatile compared with the call-by-value method in that multiple values can be returned.

  8. The fact that only the addresses and not the data values are passed during a function call, the call-by-reference method is also more efficient, especially when the function arguments involve complex data types.

  9. However the call-by-reference method is also more prone to errors if it is not used carefully.

  10. When a function is called, since only the address of an actual argument is copied to its formal argument, and not its value, the actual variable (which must have been declared in the calling function) does not have to have a value. The function can assign a value to its formal parameter, and as a consequence the actual variable will acquire a value. In this case the formal argument behaves as an output argument.

  11. Even if the actual reference argument has a value and therefore its corresponding formal parameter also has a value when the function is called, the function can change the value of the formal parameter. As a result the value of the actual argument is also changed. This formal parameter behaves both as an input and output (or inout) argument.

  12. //Program to demonstrate call-by-reference parameters.
    //A function is used to ask the user to enter 2 integers.
    //The values stored in those 2 integers are then
    //exchanged using another function.
    //The result is then displayed using yet another function.
    #include <iostream>
    using namespace std;

    void get_numbers(int& input1, int& input2);
    //Reads two integers from the keyboard.

    void swap_values(int& variable1, int& variable2);
    //Interchanges the values of variable1 and variable2.

    void show_results(int output1, int output2);
    //Shows the values of variable1 and variable2, in that order.

    int main( )
    {
          int first_num, second_num;

          get_numbers(first_num, second_num);
          swap_values(first_num, second_num);
          show_results(first_num, second_num);
          return 0;
    }

    //Uses iostream:
    void get_numbers(int& input1, int& input2)
    {
          cout << "Enter two integers: ";
          cin >> input1 >> input2;
    }

    void swap_values(int& variable1, int& variable2)
    {
          int temp;

          temp = variable1;
          variable1 = variable2;
          variable2 = temp;
    }

    //Uses iostream:
    void show_results(int output1, int output2)
    {
          cout << "In reverse order the numbers are: "
                << output1 << " " << output2 << endl;
    }

  13. //Illustrates the difference between a call-by-value
    //parameter and a call-by-reference parameter.
    #include <iostream>
    using namespace std;

    void do_stuff(int par1_value, int& par2_ref);
    //par1_value is a call-by-value formal parameter and
    //par2_ref is a call-by-reference formal parameter.

    int main( )
    {
          int n1, n2;

          n1 = 1;
          n2 = 2;
          do_stuff(n1, n2);
          cout << "n1 after function call = " << n1 << endl;
          cout << "n2 after function call = " << n2 << endl;
          return 0;
    }

    void do_stuff(int par1_value, int& par2_ref)
    {
          par1_value = 111;
          cout << "par1_value inside the function = "
                << par1_value << endl;
          par2_ref = 222;
          cout << "par2_ref inside the function = "
                << par2_ref << endl;
    }

    This program will generate the following screen output:

    par1_value inside the function = 111
    par2_value inside the function = 222
    n1 after function call = 1
    n2 after function call = 222