References and Functions II (Pass by Reference)
Learn about reference variables and their applications in functions when parameters are received as references.
In general, functions are used in programming to perform specific tasks and only return one value (if necessary) after processing any input arguments. It’s important to note that the memory allocated to a function will be released once the function has completed its task and returned any necessary value.
But what if we need more than one value from a particular function? Before discussing this, let’s first become familiar with the concept of reference variables.
Reference variable
To understand reference variables in C++, it’s important to understand the behavior of the ampersand (&
) operator first. We can use this &
operator to obtain the memory address of a variable.
Let’s look at an example.
#include <iostream>using namespace std;int main(){int a = 5;float c = 2.5;cout<< "Address of integer variable `a` is: " << &a<<'\n';cout<< "Address of float variable `c` is: " << &c<<'\n';return 0;}
In C++, a reference variable is a way to create an alias for an existing variable. The syntax for creating a reference variable involves using the &
operator followed by the name of the variable we want to reference.
For example, consider a variable named a
of the type int
. To create a reference to a
, we can use the following syntax:
int &aRef = a;
Here, aRef
is a reference variable that refers to a
. Note that the &
operator is used to specify that aRef
is a reference variable rather than a regular variable. The animation below can help illustrate how a reference variable acts as a new identifier for the same memory location.
It’s important to note that reference variables share the same memory address as the original variable. This means that any modifications made to the reference variable will also impact the original variable, and vice versa.
To understand this, consider the following code:
#include <iostream>using namespace std;int main(){int a = 5;int &aRef = a;cout << &a << " --- "<< &aRef <<'\n';cout << "Before incrementing\n";cout <<"Value of a : "<< a << " --- Value of aRef "<< aRef<<'\n';aRef++;cout <<"Value of a : " <<a << " --- Value of aRef "<< aRef<<'\n';return 0;}
Next, let’s look at an example in which we need to return two values.
Swapping values
We’re given two variables—alpha
and beta
—and we want to swap their values. For that, we shouldn’t do the following:
#include <iostream>using namespace std;int main(){int alpha = 5, beta = 4;alpha = beta; // alpha will become 4 and beta will be 4 too, and previous value of alpha is lostbeta = alpha; // This will be a logical error now as it will assign beta = 4cout << "alpha: "<< alpha << endl<< "beta: "<< beta <<endl;return 0;}
Line 6: We declare two integer variables,
alpha
andbeta
, and initializes them with the values5
and4
, respectively.Line 7: We assign the value of
beta
toalpha
using the assignment operator=
. After this line executes, bothalpha
andbeta
hold the value4
.Line 8: We assign the value of
alpha
tobeta
using the assignment operator=
. After this line executes, bothalpha
andbeta
hold the value4
.
As a result, the values of alpha
and beta
have effectively been swapped, but not in the way that we intended. This is because the second assignment overwrites the value of beta
with the incorrect value of alpha
(which is now equal to the original value of beta
).
Fixing the logical error
To fix this error, we need to create the temporary variable temp
. The following illustration clearly describes the process of swapping.
Now that we understand the process, let’s write down the code for swapping.
#include <iostream>using namespace std;int main(){int alpha = 5;int beta = 4;cout<<"Before Swap"<<'\n';cout << "alpha : " <<alpha<<'\n';cout << "beta : " <<beta<<'\n';int temp = alpha;alpha = beta;beta = temp;cout<<"\nAfter Swap"<<'\n';cout << "alpha : " <<alpha<<'\n';cout << "beta : " <<beta<<'\n';return 0;}
Lines 6–7: We define the variables
alpha
andbeta
with valid states.Lines 11–13: We swap the values of variable
alpha
andbeta
using the temporary variabletemp
.
Swapping values using functions
When we have to swap the values of two variables multiple times in our code, it can be tedious to repeat the same three lines of code because it can result in repetition. How can we avoid this?
One way to reduce this redundancy is to use a function to perform the swap operation.
Writing swap
passed by value (a logical error)
The following code has a function called swap
. We call this function erroneous because the parameters are passed by copy, which means that a new copy of each parameter is created in memory when the function is called. When the function returns, any changes made to these copies are lost, and the original variables remain unchanged.
Even if we create variables in the function with the same names as the calling position, the function will still operate on the copies rather than the original variables. This means that any changes made to the variables inside the function will not affect the variables in the calling position, rendering the function erroneous.
#include <iostream>using namespace std;void swap(int a, int b){int temp = a;a = b;b = temp;}int main(){int alpha = 5;int beta = 4;cout<<"Before Swap"<<'\n';cout << "alpha : " <<alpha<<'\n';cout << "beta : " <<beta<<'\n';swap(alpha, beta);cout<<"After Swap"<<'\n';cout << "alpha : " <<alpha<<'\n';cout << "beta : " <<beta<<'\n';return 0;}
Writing swap
passed by reference (a correct solution)
To solve this problem, we can modify the function signature to include the &
operator before the parameter names, which indicates that the parameters are passed by reference. Let’s take a look at the following code to see the correct implementation and how it executes.
#include <iostream>using namespace std;void swap(int &a, int &b){int temp = a;a = b;b = temp;}int main(){int alpha = 5;int beta = 4;cout << "Before Swap" << '\n';cout << "alpha : " << alpha <<'\n';cout << "beta : " << beta <<'\n';swap(alpha, beta);cout << "After Swap" <<'\n';cout << "alpha : " << alpha <<'\n';cout << "beta : " << beta <<'\n';return 0;}
This code defines a function called swap
that takes two integer parameters by reference. The function swaps the values of the two parameters using a temporary variable.
Lines 11–12: We define two integer variables
alpha
andbeta
with initial values of5
and4
, respectively.Lines 13–15: We print the initial values of
alpha
andbeta
to the console.Line 16: We call the
swap
function withalpha
andbeta
as parameters. This will swap the values ofalpha
andbeta
in the calling postion as well.Lines 17–19: After the swap, the new values of
alpha
andbeta
are printed to the console.
Let’s look at the following animation and see how the correct swap function works.
To gain more practice with passing by reference, we will now solve another nontrivial problem. In particular, we will explore how to simulate the return of multiple values from a function using pass-by-reference arguments. Although returning multiple values directly from a function isn’t possible, we can achieve this functionality by passing arguments by reference.
Exercise: Reduced fraction
You are given a fraction with two values: numerator
and denominator
. Your task is to reduce the fraction by implementing the functionality of the greatest common divisor (GCD) first and then calculate the reduced values of numerator
and denominator
.
Remember to compute the reduced fraction; all you have to do is compute the GCD of the numerator and denominator and divide both with the computed GCD.
For example,
Remember: You are not required to write the main()
function. Just implement the two mentioned functions.
Note: You can't change the name of function and the number of parameters given in the prototypes of the
reduceFraction
function.
#include <iostream>using namespace std;int GCD(int numerator,int denominator){// Write GCD code herereturn 1;}void reduceFraction(int &numerator,int &denominator){//Write your code here}