Programs Using Reference Variables

Learn about reference variables in C++ and their applications.

Let‘s look at an example of how we can use references to solve the problem of getting multiple values from a function.

Division of two numbers

We have a function named divide (as shown in the animation below) that takes four arguments: the “numerator,” “denominator,” “quotient,” and “remainder.”

We are obviously interested in finding the quotient and the remainder when we divide two numbers. Here, instead of returning the quotient and the remainder, we’ll be updating q and r from within the divide() function using reference variables.

Let’s look at the animation.

Inside the Task.cpp file

  • We declare the four variables n, d, q, and r, where n is initialized with 99 and d is initialized with 12.

  • We’re then call the divide() function with the return-type void. As soon as we call the function, the control goes inside the function definition block where we can see its working (with 99, 12, q, and r being passed as arguments).

  • Lastly, the quotient and remainder are printed on the console after the computation of q and r.

Inside the Watches window, the values of variables are updated after each line of code gets executed. At first, q and r hold garbage values, while &q and &r display their memory addresses, respectively.

Inside the divide() function

  • In this function, two variables (dvd and dvsr) are passed by value, which represent the dividend and divisor, whereas quo and rem are passed by reference so that the updated value of the quotient and remainder, after their computation inside the function, can be accessed outside.

    • Inside the “Watches” block that displays the local variables of the function, we can see the parameters being updated as soon as the arguments are passed into the function. That is, dvd and dvsr are updated with 99 and 12. The &quo and &rem are updated with the addresses of q and r, respectively.
  • Then the statements rem = dvd % dvsr; and quo = dvd / dvsr; are executed sequentially. As a result, rem becomes 3 and quo becomes 8.

The changes inside the divide() function are reflected outside the function as well (q and r get updated).

Now let’s run the code for this example in the editor below.

Don’t forget to check the values of &q and &r one by one in the “Expressions” section inside the GDB when running the program below to see for yourself what each represents. Click the “Start” button and then add &q or &r and press “Enter” to see its address.

#include <iostream>
using namespace std;

// function declaration with dvd and dvsr passed by value and
// rem and quo passed by reference
void divide(int dvd, int dvsr, int& quo, int& rem);

int main()
{
    int n, d, q, r;
    cout << "The dividend and divisor:";
    cin >> n
        >> d;
    // calling the function   
    divide(n, d, q, r);
    cout << "The quotient is " << q
         << " and remainder is " << r << endl;
    return 0;
}

// function definition with dvdnd and dvsr passed by value and
// rem and quo passed by reference
void divide(int dvd, int dvsr, int& quo, int& rem)
{
    rem = dvd % dvsr;
    quo = dvd / dvsr;
}


Dividing two numbers

Sometimes, if a function doesn’t return any data, it can return an integer, the value of which tells the calling function if the execution was error-free or not. In that case, the returned integer corresponds to the type of error.

To demonstrate the above point, we have tweaked the above program so that if the user enters 0 as the divisor, the program should display an error message.

Instruction: Look at the code below and execute the program by entering 10 as the dividend and 0 as the divisor. Also, look at the highlighted lines of the code to see the changes we’ve made.

#include <iostream>
using namespace std;

// changed the return-type of divide() to bool 
bool divideError(int dvd, int dvsr, int& quo, int& rem);

int main()
{
    int n, d, q, r;
    cout << "The dividend and divisor:";
    cin >> n
        >> d;
   	// calling the function and storing the result inside a bool variable  
    bool check = divideError(n, d, q, r);
   	// display the quotient and remainder if the function returns false/0
    if(check == false)
    {
    cout << "The quotient is " << q
         << " and remainder is " << r << endl;
    }
   	// otherwise, display the error message 
    else
    {
        cout << "Error: Cannot divide by zero. ";
    }

    return 0;
}

// changed the return-type of divide() to bool
bool divideError(int dvd, int dvsr, int& quo, int& rem)
{
   	// if the divisor is equal to 0, exit, return true/1
    if(dvsr == 0)
    {
        return true;   
    } 
   	// otherwise, calculate the remainder and quotient, and return false/0
    rem = dvd % dvsr;
    quo = dvd / dvsr;
    return false;
}

Dividing two numbers and handling the division by zero error

The above program illustrates the concept of returning an integer value to indicate the success or failure of the divideError() function.

This program uses a bool return type to indicate the status of the divide() function. The divideError() function now returns false or 0 and has a new check to ensure that the divisor is not zero. If the divisor is zero, the function returns true or 1. If the divisor is not zero, the function calculates the quotient and remainder as before and returns false. In the main() function, the return value is checked and a message is displayed, indicating whether the operation was successful or if there was an error.

This is a common technique used in C++, where a function can return a special value or enumerator to indicate success or failure, rather than relying on the return value or output parameters to convey this information.

Simplifying a fraction

Now let’s look at another example in which we create and use reference variables.

In this example, given a fraction, we want to find the simplest form of the fraction. Say the fraction is 13/26. Then the simplest form of this fraction would be 1/2.

The logic is to find the greatest common divisor (GCD) of the numerator and denominator. Then divide both the numerator and the denominator by GCD.

#include <iostream>
using namespace std;

void reduceFraction(int&n,int&d);
int GCD(int n1,int n2);

int main()
{
    int numerator, denominator;
    //this character is for saving the sign
    char ch;
    cout << "Enter a equation i.e 3/6: ";
    cin >> numerator
        >> ch
        >> denominator;

    reduceFraction(numerator,denominator);

    cout<<"The reduced fraction is : "<<numerator
        <<"/"<<denominator<<endl;
    
    return 0;
}

// function that converts the fraction in the simplest form
void reduceFraction(int&n,int&d)
{
    int gcd = 0;
    gcd = GCD(n,d);
    // numerator updated
    n = n / gcd;
    // denominator updated
    d = d / gcd;
}

// GCD function
int GCD(int n1, int n2)
{    
   while (n1 % n2 != 0)
   {
      int rem = n1 % n2;
      n1 = n2; 
      n2 = rem; 
   }    
   return n2;
}






Simplifying a fraction

You can see on line 17 how— for reducing the fraction, both the numerator and denominator are passed by reference—both variables need to be updated. In the reduceFraction() function, when both n and d are divided with gcd, the memory locations of the numerator and denominator (which are in the main() scope) get updated.

We have also shown below the step-by-step execution of the above code: