Wrox Press C++ Tutorial
All the example functions that we have created have returned a single value. Is it possible to return anything other than a single value? Well, not directly, but as we said earlier, the single value returned needn't be a numeric value; it could also be an address, which provides the key to returning any amount of data. You simply use a pointer. Unfortunately, the pitfalls start here, so you need to keep your wits about you for the adventure ahead.
Returning a pointer value is very easy. A pointer value is just an address, so if you want to return the address of some variable value, you can just write the following:
return &value; // Returning an address
As long as the function header and function prototype indicate the return type appropriately, we have no problem - or at least no apparent problem. Assuming that the variable value is of type double, the prototype of a function called treble, which might contain the above return statement, could be as follows,
double* treble(double data);
with some arbitrary parameter list.
So let's look at a function that will return a pointer. It's only fair that I warn you in advance - this function doesn't work. Let's assume that we need a function which will return a pointer to three times its argument value. Our first attempt might look like this:
// Function to treble a value - mark 1
double* treble(double data)
{
double result = 0;
result = 3.0*data;
return &result;
}
We could create a little test program to see what happens (remember that the treble function won't work as expected):
//Ex4_09.cpp
#include <iostream>
using namespace std;
double* treble(double); // Function prototype
int main(void)
{
double num = 5.0; // Test value
double* ptr = 0; // Pointer to returned value
ptr = treble(num);
cout << endl
<< "Three times num = " << 3.0*num;
cout << endl
<< "Result = " << *ptr; // Display 3*num
cout << endl;
return 0;
}
// Function to treble a value - mark 1
double* treble(double data)
{
double result = 0;
result = 3.0*data;
return &result;
}
The function main() calls the function treble() and stores the address returned in the pointer ptr, which should point to a value which is three times the argument, num. We then display the result of computing three times num, followed by the value at the address returned from the function.
On my computer, I get this output:

Clearly, the second line doesn't reflect the correct value of 15, but where's the error? Well, it's not exactly a secret, since the compiler gives fair warning of the problem with the message Warning C4172: returning address of local variable or temporary.
The error arises because the variable result in the function treble() is created when the function begins execution, and is destroyed on exiting from the function - so the memory that the pointer is pointing to no longer contains the original variable value. The memory previously allocated to result becomes available for other purposes, and here it has evidently been used for something else.
There is an absolutely cast iron rule for returning addresses:
Never return the address of a local automatic variable from a function.
Now that we have a function that doesn't work, we need to think about what to do to rectify that. We could use a reference and modify the original variable, but that's not what we set out to do. We are trying to return a pointer to some useful data so that, ultimately, we can return more than a single item of data. One answer lies in dynamic memory allocation (we saw this in action in the last chapter). With the operator new, we can create a new variable in the free store, which will continue to exist until it is eventually destroyed by delete - or until the program ends. The function would then look like this:
// Function to treble a value - mark 2
double* treble(double data)
{
double* result = new double(0.0);
if(!result)
{
cout << "Memory allocation failed.";
exit(1);
}
*result = 3.0*data;
return result;
}
Rather than declaring result as of type double, we now declare it as double* and store in it the address returned by the operator new. We then have the necessary check that we received a valid address, and exit the program if anything is wrong.
Since the result is a pointer, the rest of the function is changed to reflect this, and the address contained in the result is finally returned to the calling program. You could test this by replacing the function in the last working example with this version.
You need to remember that, with dynamic memory allocation from within a function like this, more memory is allocated each time the function is called. The onus is on the calling program to delete the memory when it's no longer required. It's easy to forget to do this in practice, with the result that the free store is gradually eaten up until, at some point, it is exhausted and the program will fail. This sort of problem is often referred to as a memory leak.
Here you can see how the function would be used. The two changes that we needed to make to the original code, once the function has been replaced, are to include the standard library header file and to use delete to free the memory as soon as we finish using the returned pointer.
#include <iostream>
#include <cstdlib>
using namespace std;
double* treble(double); // Function prototype
int main(void)
{
double num = 5.0; // Test value
double* ptr=0; // Pointer to returned value
ptr = treble(num);
cout << endl
<< "Three times num = " << 3.0*num;
cout << endl
<< "Result = " << *ptr; // Display 3*num
delete ptr; // Don't forget to free the memory
cout << endl;
return 0;
}
// Function to treble a value - mark 2
double* treble(double data)
{
double* result = new double(0.0);
if(!result)
{
cout << "Memory allocation failed.";
exit(1);
}
*result = 3.0*data;
return result;
}
You can also return a reference from a function. This is just as fraught with potential errors as returning a pointer, so you need to take care with this too. Because a reference has no existence in its own right (it's always an alias for something else), you must ensure that the object it refers to still exists after the function completes execution. It's very easy to forget this when you use references in a function, because they appear to be just like ordinary variables.
References as return types are of primary significance in the context of object-oriented programming. As you will see later in the book, they will enable you to do things that would otherwise be impossible. (This particularly applies to 'operator overloading'.) The principal characteristic of a reference-type return value is that it is an lvalue. This means that you can use the result of a function on the left-hand side of an assignment statement.
Let's look at one example which illustrates the use of reference return types, and also demonstrates how a function can be used on the left of an assignment operation when it returns an lvalue. We will assume that we have an array containing a mixed set of values. Whenever we want to insert a new value into the array, we want to replace the lowest value.
// Ex4_10.cpp
// Returning a reference
#include <iostream>
#include <iomanip>
using namespace std;
double& lowest(double A[], int len); // Prototype of function
// returning a reference
int main(void)
{
double array[] = { 3.0, 10.0, 1.5, 15.0, 2.7, 23.0,
4.5, 12.0, 6.8, 13.5, 2.1, 14.0 };
// Initialize to number of elements
int len = sizeof array/sizeof array[0];
cout << endl;
for(int i = 0; i<len; i++)
cout << setw(6) << array[i];
lowest(array, len) = 6.9; // Change lowest to 6.9
lowest(array, len) = 7.9; // Change lowest to 7.9
cout << endl;
for(i = 0; i<len; i++)
cout << setw(6) << array[i];
cout << endl;
return 0;
}
double& lowest(double A[], int len)
{
int j=0; // Index of lowest element
for(int i=1; i<len; i++)
if(A[j]>A[i]) // Test for a lower value...
j = i; // ...if so update j
return A[j]; // Return reference to lowest element
}
Let's first take a look at how the function is implemented. The prototype for the function lowest() uses double& as the specification of the return type, which is therefore of type 'reference to double'. You write a reference-type return value in exactly the same way as we've already seen for variable declarations, appending the & to the data type. The function has two parameters specified: a one-dimensional array A of type double, and an int parameter len, which should specify the length of the array.
The body of the function has a straightforward for loop to determine which element of the array passed to it contains the lowest value. The index, j, of the array element with the lowest value is arbitrarily set to 0 at the outset, and then modified within the loop if the current element, A[i], is less than A[j]. Thus, on exit from the loop, j will contain the index value corresponding to the array element with the lowest value. The return statement is as follows:
return A[j]; // Return reference to lowest element
In spite of the fact that this looks identical to the statement which would return a value, because the return type was declared as a reference, this returns a reference to A[j] rather than the value that the element contains. The address of A[j] is used to initialize the reference to be returned. This reference is created by the compiler, because the return type was declared as a reference.
Don't confuse returning &A[j] with returning a reference. If you write &A[j] as the return value, you are specifying the address of A[j], which is a pointer. If you do this after having specified the return type as a reference, you will get an error message from the compiler.
The function main(), which tests our function lowest(), is very simple. An array of type double is declared and initialized with 12 arbitrary values, and an int variable len is initialized to the length of the array. The initial values in the array are output for comparison purposes.
Again, we've used the stream manipulator setw() to space the values uniformly, requiring the #include statement for iomanip
The function main() then calls the function lowest() on the left side of an assignment to change the lowest value in the array. This is done twice to show that it does actually work and is not an accident. The contents of the array are then output to the display again, with the same field width as before, so corresponding values line up. If you run this example, you should see the following output:

As you can see, with the first call to lowest(), the third element of the array, array[2], contained the lowest value, so the function returned a reference to it and its value was changed to 6.9. Similarly, on the second call, array[10] was changed to 7.9.
This demonstrates quite clearly that returning a reference allows the use of the function on the left side of an assignment statement. The effect is as if the variable specified in the return statement appeared on the left of the assignment.
Of course, if you want to, you can also use it on the right side of an assignment, or in any other suitable expression. If we had two arrays, X and Y, with lenX and lenY elements respectively, we could set the lowest element in the array X to twice the lowest element in the array Y with this statement:
lowest(X, lenX) = 2.0*lowest(Y, lenY);
This statement would call our function lowest() twice, once with arguments Y and lenY in the expression on the right side of the assignment, and once with arguments X and lenX to obtain the address where the result of the right-hand expression is to be stored.
A similar rule to the one concerning the return of a pointer from a function also applies to returning references:
Never return a reference to a local variable from a function.
We'll leave the topic of returning a reference from a function for now, but we haven't finished with it yet. We'll come back to it again in the context of user-defined types and object-oriented programming, when we shall unearth a few more magical things that we can do with references.
There are some things you can't do with automatic variables within a function. You can't count how many times a function is called, for example, because you can't accumulate a value from one call to the next. There's more than one way to get around this if you need to. For instance, you could use a reference parameter to update a count in the calling program, but this wouldn't help if the function was called from lots of different places within a program. You could use a global variable which you incremented from within the function, but globals are risky things to use as they can be accessed from anywhere in a program, which makes it very easy to change them accidentally.
For a general solution, you can declare a variable within a function as static. You use exactly the same form of declaration for a static variable that we saw in Chapter 1. For example, to declare a variable count as static you could use this statement:
static int count = 0;
This also initializes the variable to zero.
Initialization of a static variable within a function only occurs the first time that the function is called. In fact, on the first call of a function, the static variable is created and initialized. It then continues to exist for the duration of program execution, and whatever value it contains when the function is exited is available when the function is next called.
We can demonstrate how a static variable behaves in a function with the following simple example:
// Ex4_11.cpp
// Using a static variable within a function
#include <iostream>
using namespace std;
// Function prototype, no arguments or return value
void record(void);
int main(void)
{
record();
for(int i = 0; i<= 3; i++)
record();
cout << endl;
return 0;
}
// A function that records how often it is called
void record(void)
{
static int count = 0;
cout << endl
<< "This is the " << ++count;
if((count>3) && (count<21)) // All this....
cout <<"th";
else
switch(count%10) // is just to get...
{
case 1: cout << "st";
break;
case 2: cout << "nd";
break;
case 3: cout << "rd";
break;
default: cout << "th"; // the right ending for...
} // 1st, 2nd, 3rd, 4th, etc.
cout << " time I have been called";
return;
}
Our function here serves only to record the fact that it was called. If you build and execute it you will get this output:

The static variable count is initialized with 0, and is incremented in the first output statement in the function. Because the increment operation is prefix, the incremented value is displayed by the output statement. It will be 1 on the first call, 2 on the second and so on. Because the variable count is static, it continues to exist and retain its value from one call of the function to the next.
The remainder of the function is concerned with working out when 'st', 'nd', 'rd' or 'th' should be appended to the value of count that is displayed. It's surprisingly irregular. (I guess 101 should be 101st rather than 101th, shouldn't it?)
Note the return statement. Because the return type of the function is void, to include a value would cause a compiler error. You don't actually need to put a return statement in this particular case as running off the closing brace for the body of the function is equivalent to the return statement without a value. The program will compile and run without error either way.