15. Functions
A C++ program is not normally written with all its executable code in main() (i.e., the “main” function). Program functionality is instead divided into simple, well-defined tasks (modules) during design with each module implemented as an individual piece of the overall program. These “pieces” are called functions in C++. When a C++ program runs, each function is called upon to carry out its task at the appropriate time.
C++ functions have three parts: function definitions (often just called functions), function calls, and function declarations (also called prototypes). Function definitions correspond to a design’s module definitions and function calls to module calls. Function declarations do not exist in design. A flowchart’s module symbols become function calls in C++ code. Each of the three parts is discussed below. Before we get started, however, here are a few phrases and terms you should know:
- Calling Function – a function which initiates the execution of another function.
- Function Called – the function initiated by the calling function.
- Pass – to send a value to a function for it to use during its execution.
- Return – to send a value back from the function called to the calling function for its use.
Function Definitions
When a program’s functionality is divided into tasks, each task will be carried out by the steps placed in the program’s function definitions.
General Form
The general form of a function definition is as follows:
return-type function-name([parameter(s)])
{
function-body
[return statement]
}
Some important points:
- A function must be given a name. Follow the same guidelines from the Variables section when selecting a name for a function.
- The statements to execute to carry out the task for which the function is responsible should be placed within the braces indicating the function body.
- A
returnstatement is actually part of a function body. It is singled out to emphasize its role as part of a function definition. - The parentheses and braces are required.
The first line in a function definition is called a function definition header or function definition heading.
Do not put a semicolon after the closing parenthesis in the function definition header. If a semicolon is placed there accidentally, the program will not compile.
The statements in the function body should be indented and left aligned to visually emphasize they are in the function definition.
Receiving Data Passed to a Function
One or more values must often be passed to a function so that it can carry out its task. Function definitions, therefore, need something capable of receiving the data sent. This is the purpose of parameters.
A parameter receives a value passed to a function by a calling function. Parameters look like variable declarations in that they have a data type and a name. Parameter names should follow the guidelines from the Variables section.
A function definition follows with a single parameter, number. The parameter will receive an integer value passed to the function when it is called:
double find_half(int number)
{
double half;
half = number * .5;
return half;
}
One parameter must exist for each value passed. Multiple parameters appear as a comma separated list within the parentheses. Every parameter must have its own data type and name.
If a function does not need to be passed any data, it does not need any parameters (as indicated by the optional parameters in the general form). The parentheses can be left empty or the keyword void placed within them.
Returning a Value from a Function
A function can also have a value it needs to return to its calling function. For example, perhaps a function performs a calculation and needs to return the result. Two parts of a function are involved when returning a value: the return type and the return statement.
The return type is the data type placed prior to the function’s name in the function definition header. It indicates the data type of the value being returned by the function. In the previous example, a double will be returned, so the function’s return type is double. A return type does not, however, actually perform any action.
A return statement returns a value to the calling function:
return [expression];
Some important points:
- The word
returnis a keyword. - A
returnstatement can return only a single value. - The expression reflects the value to return to the calling function and may be a literal, the value of a variable, or a calculation whose result will be returned.
- The data type of the value returned should match the function’s return type.
- The semicolon is required.
Most of the time the value returned will be the value of a variable. For example, the return statement in the previous example returns the value of the variable half.
Once a return statement is executed, execution of a function ends and program control is passed back to the calling function. For this reason, no executable statements should be placed after a return statement.
If a function does not need to return a value, use void for the function’s return type. Do not omit the return type thinking its absence will mean the function does not return a value. In C++, if a function does not have a return type, it is assumed the function returns an integer and the program will have trouble compiling.
A return statement is optional when a function does not return a value. Whether or not the statement is included is a programmer’s choice. Either approach is fine. If a return statement is included, it will consist solely of the keyword return and a semicolon (i.e., the general form’s optional part will be omitted).
Additional Points
- A C++ program consists of one or more functions. Most functions will come from your design choices, but there will always be a function named
main(). Execution of a C++ program always begins at the first executable statement inmain(). - When organizing your functions in a source code file, it is best to place
main()as the first function in the file. As this is where execution starts, anyone looking at your code will most likely look formain()first. - All of a program’s executable code must be placed within its function(s). If an executable statement is placed between functions, the program will not compile.
- Only pass data to a function or return data from a function when needed.
- Do not declare parameters in a function. If attempted, the program will not compile.
Function Calls
Function definitions contain the code executed to perform a program’s tasks, but they will not execute without being told to do so. Function calls are used to initiate a function’s execution and should be placed at the point at which execution of a function should occur.
General Form
The general form of a function call is as follows:
[variable =] function-name([arguments(s)]);
Some important points:
- The function name must exactly match the name in the definition (including case).
- The parentheses and semicolon are required.
Passing Data to a Function
If a function definition needs one or more values to complete its task, its function call is responsible for sending the needed data.
An argument is a value passed to a function. Most of the time a value passed to a function will be the value of a variable. Here is a function call corresponding to the find_half() function defined previously:
half = find_half(number);
The value of the variable number will be passed to the function find_half() and stored in the function’s parameter (also named number).
One argument must be present for each of a function’s parameters. If a function call has more than one argument, the arguments appear in a comma separated list within the parentheses. When the function is called, the first argument’s value will be saved in the function’s first parameter, the second argument’s value saved in the second parameter, etc.
Arguments do not have data types. Their data types are known by the data types of the values passed to the function. If int is placed prior to number within the parentheses in the call above, the program will not compile.
If a function does not need to be sent any data, the function call will not have any arguments and the parentheses left empty (as indicated by the optional arguments in the general form). Do not place void within the parentheses as the program will not compile.
Receiving a Value Returned from a Function
If a function returns a value, the value returned must be saved by placing the function call within an assignment statement. The function call is placed on the right of the assignment operator and the variable to store the value returned placed on the left of the assignment operator. The assignment statement in the example above saves the value returned by find_half() into the variable half.
If a function which returns a value is not called in an assignment statement, the function will still work correctly, but the value returned is lost and the calling function therefore unable to use it.
If a function does not return a value, the function call will not be placed in an assignment statement. Do not place void prior to the function call as the program will not compile.
Additional Points
- A function can be called as many times as needed.
- A function call can be placed in a function other than
main(). Note, however, thatmain()should control the overall execution of a program. The executable code inmain()should not consist of a single function call.
Function Declarations
Function definitions and function calls include all the code needed for functions to work when a program executes. C++, however, also requires the use of function declarations (prototypes) at compile time.
General Form
A function declaration consists of a function definition header followed by a semicolon. The general form is as follows:
return-type function-name(parameters);
With main() as the first function in a source code file, a function declaration is required for every function other than main(). If a function declaration is forgotten, the program will not compile.
Function declarations should be placed above main() but below any symbolic constant definitions.
Function Declaration Use
The compiler uses function declarations to verify that function calls and function definitions match. If, for example, a function is defined with three parameters and its function call has only two arguments, the program will not compile. Here is the declaration for the find_half() function defined previously:
double find_half(int number);
Summary
The tables that follow summarize options for passing data to, and returning data from, functions. Keep in mind that the data type of values passed and returned can be any data type discussed in the Variables section.
| Nothing Passed and Nothing Returned | Integer Passed and Nothing Returned | Nothing Passed and Integer Returned | Integer Passed and Integer Returned | Multiple Values Passed and Integer Returned | |
|---|---|---|---|---|---|
| Function Prototype | | | | | |
| Function Call | | | | | |
| Function Definition | | | | | |
A Complete Program
The following example provides a complete program with three functions in addition to main(). One function is the find_half() function discussed above. Step through the program.
A few final points:
- Variables declared inside a function are sometimes called local variables and can only be used by the function in which they are declared.
- Parameters can only be used by the function in which they are defined.
- Do not declare a variable with the same name as the function in which it is used. There will usually be problems compiling the program.
There is no connection between the local variables and parameters in a program’s functions. Each has its own memory allocated for it. As a result:
- Local variables in different functions can have the same names. The same is true for parameters.
- The names of variables used as arguments and the names of parameters do not have to match, but they can.
A Complete Program with Functions
#include <iostream>
int get_number();
double find_half(int number);
void display_results(int number, double half);
int main()
{
int number; // stores the number entered by the user
double half; // stores the calculated value
number = get_number();
half = find_half(number);
display_results(number, half);
return 0;
}
// Reads the number the user wants to see divided by 2
int get_number()
{
int number; // stores the number entered by the user
std::cout << "What is your number? ";
std::cin >> number;
return number;
}
// Calculates 50% of the user's number
double find_half(int number)
{
double half; // stores the result of the calculation
half = number * 0.5;
return half;
}
// Displays the original number and its calculated half
void display_results(int number, double half)
{
std::cout << "Half of " << number << " is "
<< half << std::endl;
}
Stub Programming
Suppose a program will have five functions in addition to main(). One approach is to write the code for the entire program and then compile it. This will usually result in many problems to identify and fix throughout the program.
A second approach, stub programming, involves writing the program one function at a time. Once a function is written, the program is tested until the function seems error free. Then the next function is written and tested. This process continues until the program is completed. The benefit of this approach is that, at any point in time, there should be fewer problems to deal with and they should be located in the newly written function making them easier to find.