CIT020 Index > Lecture Notes - References

References

What’s a Reference?

As the book describes, a reference is a way to provide another name for a variable. When you use a reference in the same scope as an ordinary variable, you end up with something that is a good example of an example, but fundamentally useless.

int main( )
{
    double price = 0.0;
    double& priceReference = price;
    
    priceReference = 5.00;
    cout << "The price is $" << price << endl;    // prints 5
}

Passing by Value

To find out where references are useful, we first have to revisit passing parameters by value. As we have seen, when you pass a parameter by value, you get a copy of the original. That means a function can never change the value of the original:

void tryChanging( int n );

int main( )
{
	int n = 0;
	tryChanging( n );
	cout << n << endl; // still prints zero
}

void tryChanging( int n )
{
	n = 1066;	// changes the copy to 1066
}

The situation looks like this:

diagram showing copy of variable being modified

Again, this is almost always a good thing. You want a function to be able to do its work without having to worry about whether it will mystically change one of your variables. That’s the whole point of modularizing your code.

Passing by Reference

Sometimes, though, you do want a function to be able to change a variable. This happens most often if you want a function to give back two results. As an example, let’s say that we need to simulate a falling object and must calculate its speed and the distance fallen in a given amount of time. We could use two functions:

double calculateSpeed( double time );
double calculateDistance( double time );

...but since these are so closely related, it’s more logical to have a single function calcSpeedAndDistance(). This function cannot return two values, so what we will do is pass the variables to be changed by reference

void calcSpeedAndDistance( double time, double& velocity, double& distance );

int main( )
{
    double time = 2.5;
    double speed = 0.0;
    double distance = 0.0;
    
    calcSpeedAndDistance( time, speed, distance );
    cout << "Speed is " << speed
        << " meters/sec and distance is "
        << distance << " meters." << endl;
    return 0;
}

void calcSpeedAndDistance( double time, double& velocity, double& distance )
{
    double ACCELERATION = 9.8;  // gravity in meters per second
    velocity = ACCELERATION * time;
    distance = ACCELERATION * time * time / 2.0;
}

Here’s what the situation looks like when the function is invoked. The function’s variable time is a copy of main()’s variable time. That’s good; our function doesn’t need to change it. (This is the same way we’ve done it to this point.)

The function’s variable velocity becomes an alias for main()’s variable speed, and the function’s variable distance becomes an alias for main()’s variable distance. Anything that we do to those variables in the function will directly affect the originals back in main. That’s because they aren’t local variables. Instead, they are “direct lines” back to the originals.

diagram showing time by value, other parameters by reference

Thus, when the program sets velocity in the statement velocity = ACCELERATION * time;, the result goes directly into the speed variable.

In this example, I have deliberately named one of the parameters differently from its argument, and named the other parameter the same as its argument. The fact that the names are the same does not magically link them together. The fact that they are in the same position in the argument and parameter lists is what connects them.

Passing Arrays

If you wish to pass a fundamental built-in type (also called a primitive) by reference, you must use the & in the function header and prototype.

When you pass an array, it is always passed by reference. You never, ever use the ampersand. When you pass an array, you use an empty pair of square brackets instead. Never put a number in the square brackets. You must also pass the number of items in the array to your function. Unlike a vector or string, which “knows” how long it is, a function has no way to determine an array’s length unless you tell it via a parameter.

The following program calls a function that determines the maximum value in an array of doubles. Notice that the numberOfItems parameter is called by value, not by reference–the function does not need to change it.

double findMaximum( double data[], int numberOfItems );

int main( )
{
    const int DATA_SIZE = 6;
    double data[DATA_SIZE] = { 3.5, 4.2, 1.6, 8.9, 2.2, 5.7 };
    double biggest = 0.0;
    
    biggest = findMaximum( data, DATA_SIZE );
    cout << "The largest value is " << biggest << endl;
    return 0;
}

double findMaximum( double data[], int numberOfItems )
{
    double maxValue = 0.0;
    
    if (numberOfItems > 0)
    {
        maxValue = data[0];
        for (int i = 0; i < numberOfItems; i++)
        {
            if (data[i] > maxValue)
            {
                maxValue = data[i];
            }
        }
    }
    return maxValue;
}