Programs Using Reference Variables
Learn about reference variables in C++ and their applications.
We'll cover the following
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
, andr
, wheren
is initialized with99
andd
is initialized with12
. -
We’re then call the
divide()
function with the return-typevoid
. As soon as we call the function, the control goes inside the function definition block where we can see its working (with99
,12
,q
, andr
being passed as arguments). -
Lastly, the quotient and remainder are printed on the console after the computation of
q
andr
.
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
anddvsr
) are passed by value, which represent the dividend and divisor, whereasquo
andrem
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
anddvsr
are updated with99
and12
. The&quo
and&rem
are updated with the addresses ofq
andr
, respectively.
- 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,
-
Then the statements
rem = dvd % dvsr;
andquo = dvd / dvsr;
are executed sequentially. As a result,rem
becomes3
andquo
becomes8
.
The changes inside the
divide()
function are reflected outside the function as well (q
andr
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; }
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; }
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; }
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: