In this section, we create a user-defined function called maximum
that returns the largest of its three int
arguments. When the application executes, the main
function (lines 9–17 of Fig. 6.3) reads three integers from the user. Then, the output statement (lines 15–16) calls maximum
, which in this example is defined after main
(lines 20–34)—we’ll discuss the order of this example’s function definitions momentarily. Function maximum
returns the largest value to line 16, which displays the result. The sample outputs show that maximum
determines the largest value regardless of whether it’s the first, second or third argument.
maximum
Function maximum
first assumes that parameter x
has the largest value, so line 21 declares local variable maximumValue
and initializes it to parameter x
’s value. Of course, it’s possible that parameter y
or z
contains the actual largest value, so we must compare each of these with maximumValue
. The if
statement in lines 24–26 determines whether y
is greater than maximumValue
and, if so, assigns y
to maximumValue
. The if
statement in lines 29–31 determines whether z
is greater and, if so, assigns z
to maximumValue
. At this point the largest value is in maximumValue
, so line 33 returns that value to the call in line 16.
maximum
In preceding chapters, we created classes Account
, Student
and DollarAmount
, each with various member functions. We defined each class in a header (.h
) and included it before main
in a program’s source-code file. Doing this ensures that the class (and thus its member functions) is defined before main
creates and manipulates objects of that class. The compiler then can ensure that we call each class’s constructors and member functions correcly—for example, passing each the correct number and types of arguments.
For a function that’s not defined in a class, you must either define the function before using it or you must declare that the function exists, as we do in line 7 of Fig. 6.3:
int maximum(int x, int y, int z); // function prototype
This is a function prototype, which describes the maximum
function without revealing its implementation. A function prototype is a declaration of a function that tells the compiler the function’s name, its return type and the types of its parameters. This function prototype indicates that the function returns an int
, has the name maximum
and requires three int
parameters to perform its task. Notice that the function prototype is the same as the first line of the corresponding function definition (line 20), but ends with a required semicolon.
Parameter names in function prototypes are optional (they’re ignored by the compiler), but many programmers use these names for documentation purposes. We used parameter names in Fig. 6.3’s function prototype for demonstration purposes, but generally we do not use them in this book’s subsequent examples.
When compiling the program, the compiler uses the prototype to
Ensure that maximum
’s first line (line 20) matches its prototype (line 7).
Check that the call to maximum
(line 16) contains the correct number and types of arguments, and that the types of the arguments are in the correct order (in this case, all the arguments are of the same type).
Ensure that the value returned by the function can be used correctly in the expression that called the function—for example, for a function that returns void
you cannot call the function on right side of an assignment.
Ensure that each argument is consistent with the type of the corresponding parameter—for example, a parameter of type double
can receive values like 7.35, 22 or –0.03456, but not a string like "hello"
. If the arguments passed to a function do not match the types specified in the function’s prototype, the compiler attempts to convert the arguments to those types. Section 6.5 discusses this conversion and what happens if the conversion is not allowed.
Declaring function parameters of the same type as int x, y
instead of int x, int y
is a syntax error—a type is required for each parameter in the parameter list.
Compilation errors occur if the function prototype, header and calls do not all agree in the number, type and order of arguments and parameters, and in the return type.
A function that has many parameters may be performing too many tasks. Consider dividing the function into smaller functions that perform the separate tasks. Limit the function header to one line if possible.
Multiple parameters are specified in both the function prototype and the function header as a comma-separated list, as are multiple arguments in a function call.
The commas used in line 16 of Fig. 6.3 to separate the arguments to function maximum
are not comma operators as discussed in Section 5.5. The comma operator guarantees that its operands are evaluated left to right. The order of evaluation of a function’s arguments, however, is not specified by the C++ standard. Thus, different compilers can evaluate function arguments in different orders.
Sometimes when a function’s arguments are expressions, such as those with calls to other functions, the order in which the compiler evaluates the arguments could affect the values of one or more of the arguments. If the evaluation order changes between compilers, the argument values passed to the function could vary, causing subtle logic errors.
If you have doubts about the order of evaluation of a function’s arguments and whether the order would affect the values passed to the function, evaluate the arguments in separate assignment statements before the function call, assign the result of each expression to a local variable, then pass those variables as arguments to the function.
Previously, you’ve seen that when a program calls a function, the function performs its task, then returns control (and possibly a value) to the point where the function was called. In a function that does not return a result (i.e., it has a void
return type), we showed that control returns when the program reaches the function-ending right brace. You also can explicitly return control to the caller by executing the statement
return;