Using Function Return Values

 < Day Day Up > 



Functions can return values which can then be used by the function or program that called the function. Up to this point, all the example functions, except main(), have been declared to return void, which means they do not return a value. Functions can return objects of fundamental data types such as int, float, char, etc., or objects of user-defined types. User-defined types are discussed in chapters 10 and 11. Functions can also return pointers and references to these types as well as pointers to other functions. The important thing to remember about functions is that they can be used anywhere in your program where their return type and value can be used. For example, a function that returns an integer object can be used anywhere you could otherwise use an integer object. Let us first take a look at functions that return objects.

Returning Objects

Specify the type of object you want a function to return in its declaration. Check out the following examples:

int returnInt(); float calculatePay( int hours_worked, float hourly_rate); double getStarCount(); bool engineIsOn();

Once you have specified the type of object the function will return you have to return an object of that type when you define your function. The following example gives the function definition for the returnInt() function declared above:

Listing 9.29: returnint.cpp

start example
1  #include "returnint.h" 2 3  int returnInt(){ 4     return 2; 5  }
end example

This function returns the integer value 2 via the return statement on line 4. The integer value could have also been a local integer variable, or perhaps the result of a calculation. For instance, line 4 could have been written like so:

return 1 + 1;

The following main() function shows the returnInt() function in use:

Listing 9.30: main.cpp

start example
1  #include <iostream> 2  #include "returnint.h" 3  using namespace std; 4 5 6  int main(){ 7     cout<<returnInt()<<endl; 8     return 0; 9  }
end example

Notice here how the returnInt() function was used as an input to the cout object. Since returnInt() returns an integer object, it can be used anywhere an integer can be used.

The return Keyword: Mantra on Proper Usage

The return statement should be the last line of code in the function. I’d like to say that one more time. The return statement should be the last line of code in the function. And there should only be one return statement in a function. I repeat. There should only be one return statement in a function. Now, having said that I will add that there are good reasons to violate this mantra.

Return keyword Mantra Ancillary

If you can keep the multiple return statements close together so you can see intuitively where they are in relation to the function’s code, then you should be safe.

Another Example

Let us take a look at another relatively simple example, but this time the value returned will depend on the value of the argument used when the function is called. The following code gives the declaration for a function called square():

Listing 9.31: square.h

start example
1  #ifndef SQUARE_H 2  #define SQUARE_H 3 4  double square(float value = 1); 5 6  #endif
end example

The square function is declared to take a float argument whose parameter name is value and has a default argument value of 1.

Default Argument Values

Setting a parameter to a default value enables the function to be called in two different ways: 1) with an argument, and 2) without an argument. In the first case, the parameter will be set to whatever the argument’s value happens to be. In the second case, the parameter value will be set to 1. The following example shows the function definition for the square function:

Listing 9.32: square.cpp

start example
1  #include "square.h" 2 3  double square(float value){ 4     return (value * value); 5  }
end example

Nothing surprising going on here. The function simply returns the result of the parameter value multiplied by itself. Now, examine the main() function showing the square() function in use:

Listing 9.33: main.cpp

start example
1  #include <iostream>  2  #include <stdlib.h>  3  #include "square.h"  4  5  using namespace std;   6  7  int main(){  8      bool keep_going = true;  9      char input[25]; 10 11      while(keep_going){ 12      cout<<"Please enter a value to square: "; 13      cin>>input; 14      cout<<endl<<"The squared value is: "<<square(atof(input))<<endl; 15      cout<<"Continue? Y or N: "; 16      cin>>input[0]; 17      switch(input[0]){ 18         case 'y': 19         case 'Y': break; 20         case 'n': 21         case 'N': keep_going = false; 22                   break; 23         default: break; 24         } 25      } 26     return 0; 27  }
end example

The square() function makes its appearance on line 14 above. After the user’s input is read into the 25 character array named input, the array is used as an argument to a C Standard Library function named atof(). (ASCII to float) As its name implies, the atof() function converts an ASCII character string to a floating point value. Notice how the atof() function appears as an argument to the square() function. This example brings together pretty much everything you have learned about functions up to this point. The rest of the main() function just provides a simple user interface and program control.

Returning Pointers

A function can return the address of an object. Just like the case of a function returning an object, a function that returns a pointer can be used wherever a pointer of that type is required. To illustrate this concept let us take a look at an example program that dynamically creates pointers to integer objects and stores the addresses in an array. The following code declares a function named getNewIntAddress() that will perform the dynamic memory allocation and return a pointer to the integer object created:

Listing 9.34: getnewintaddress.h

start example
1  #ifndef GET_NEW_INT_ADDRESS_H 2  #define GET_NEW_INT_ADDRESS_H 3 4  int* getNewIntAddress(); 5 6  #endif
end example

Notice the return type declared on line 4 is of type pointer to int. Example code 9.35 gives the function definition:

Listing 9.35: getnewintaddress.cpp

start example
1  #include "getnewintaddress.h" 2 3  int* getNewIntAddress(){ 4     return (new int); 5  }
end example

All getNewIntAddress() does is create a new integer object in the heap and return its address. Example 9.36 gives a main() function showing the getNewIntAddress() function in action.

Listing 9.36: main.cpp

start example
1  #include <iostream>  2  #include "getnewintaddress.h"  3  using namespace std;   4  5  int main(){  6       int* ip_array[10];  7  8       for(int i = 0; i < 10; i++)  9            *(ip_array[i] = getNewIntAddress()) = (i+1); 10 11       for(int i = 0; i < 10; i++) 12            cout<<*ip_array[i]<<" "; 13 14       cout<<endl; 15 16       for(int i = 0; i < 10; i++) 17            *ip_array[i] += 2; 18 19       for(int i = 0; i < 10; i++) 20            cout<<*ip_array[i]<<" "; 21 22       for(int i = 0; i < 10; i++) 23            delete ip_array[i]; 24 25       return 0; 26  }
end example

The getNewIntAddress() function is called in the body of the first for statement on line 9. When getNewIntAddress() is called the resulting address is assigned to ip_array[i]. The assignment is enclosed in parentheses and dereferenced using the * operator. The resulting integer object is then assigned the value (i+1). The next for statement on line 11 prints the contents of the newly-filled array. The for statement on line 16 simply modifies the integer values, followed by the for statement on line 19 which prints the contents of ip_array to the screen again. The for statement on line 22 iterates over ip_array and deletes each pointer to free up memory. Failure to release the memory using delete would result in a memory leak.

How Not To Return a Pointer From A Function: Avoiding the Dangling Reference

Do not do this:

int* badFunction(){    int i;    //...do something with i here    //...and then later...    return &i; }

What is happening here is a local function variable, in this case an integer object named i, is declared and used inside the function body, and its address is returned. The problem is that since i is a local variable there is no telling what will happen to the memory in which i resided when badFunction() returns. On the other hand, i could be declared to be static, and therefore exist across calls to badFunction(), but I still do not recommend the practice because it violates loose coupling. Returning pointers in this manner creates what is referred to as a dangling reference. Avoid dangling references!

Returning References

A function can return a reference. This can be real handy, especially when you start writing class member functions that return references to instance objects. Unfortunately, that material isn’t discussed until chapter 11! To tide you over, I will show you a short example of reference returning in action so you get a feel for the mechanics involved.

The following example program will use a function named getLargestInteger() to compare two integer objects and return a reference to the largest one. With this reference, the original integer object can be manipulated. Let us start with the function declaration:

Listing 9.37: getlargestinteger.h

start example
1  #ifndef GET_LARGEST_INTEGER_H 2  #define GET_LARGEST_INTEGER_H 3 4  int& getLargestInteger(int& a, int& b); 5 6  #endif
end example

The getLargestInteger() function takes two integer references as an argument and returns a reference to the object with the largest positive value. Here is the function definition:

Listing 9.38: getlargestinteger.cpp

start example
1  #include "getlargestinteger.h" 2 3  int& getLargestInteger(int& a, int& b){ 4     if(a >= b) return a; 5        else return b;  6  }
end example

The two integer reference parameters a and b are compared to each other on line 4 and the corresponding return statement is executed based on the results of the comparison. In this example, multiple return statements make sense and comply with the return statement mantra ancillary. The following main() function shows getLargestInteger() in use:

Listing 9.39: main.cpp

start example
1  #include <iostream>  2  #include "getlargestinteger.h"  3  using namespace std;  4  5  int main(){  6      int ival1 = 0, ival2 = 1;  7  8      cout<<"The largest number is: "<<getLargestInteger(ival1, ival2)<<endl;  9 10      int& largest_int = getLargestInteger(ival1, ival2); 11 12      largest_int = -8; 13 14      cout<<"The largest number is: "<<getLargestInteger(ival1, ival2)<<endl; 15 16      return 0; 17  }
end example

In this example, two integer objects, ival1, and ival2, are declared and initialized on line 6. getLargestInteger() is first called on line 8. The result of the function call then becomes the argument to the insertion operator for the cout object. On line 10, the reference returned by getLargestInteger() is used to initialize the integer reference largest_int. largest_int is then used to manipulate the object it references, which, in this case, is ival2. With ival2’s value now -8, getLargestInteger() is called again in another cout statement on line 14.

Quick Review

Functions can return objects, pointers to objects, or references to objects. The objects can be fundamental data types, user-defined types, or functions. (You will begin learning about user-defined data types in chapter 10) Declare the return type in the function declaration and use the return keyword to return an object of the specified type from the body of the function declaration. Try to avoid multiple return points from a function. In cases where you have to break this rule keep the multiple return statements as close together as possible for clarity.



 < Day Day Up > 



C++ for Artists. The Art, Philosophy, and Science of Object-Oriented Programming
C++ For Artists: The Art, Philosophy, And Science Of Object-Oriented Programming
ISBN: 1932504028
EAN: 2147483647
Year: 2003
Pages: 340
Authors: Rick Miller

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net