4.3 Programmer-Defined Functions

A custom-tailored suit always fits better than one off the rack.

MY UNCLE, The Tailor

In the previous section we told you how to use predefined functions. In this section we tell you how to define your own functions.

Function Definitions

You can define your own functions, either in the same file as the main part of your program or in a separate file so that the functions can be used by several different programs. The definition is the same in either case, but for now, we will assume that the function definition will be in the same file as the main part of your program.

Display 4.3 contains a sample function definition in a complete program that demonstrates a call to the function. The function is called totalCost. The function takes two arguments—the price for one item and number of items for a purchase. The function returns the total cost, including sales tax, for that many items at the specified price. The function is called in the same way a predefined function is called. The description of the function, which the programmer must write, is a bit more complicated.

Display 4.3 A Function Definition

An illustration shows a code segment of a “Function” definition.

Sample Dialogue

Enter the number of items purchased: 2
Enter the price per item: $10.10
2 items at $10.10 each.
Final bill, including tax, is $21.21

The description of the function is given in two parts that are called the function declaration and the function definition. The function declaration (also known as the function prototype) describes how the function is called. C++ requires that either the complete function definition or the function declaration appears in the code before the function is called. The function declaration for the function totalCost is in color at the top of Display 4.3 and is reproduced here:

double totalCost(int numberPar, double pricePar);

The function declaration tells you everything you need to know in order to write a call to the function. It tells you the name of the function, in this case totalCost. It tells you how many arguments the function needs and what type the arguments should be; in this case, the function totalCost takes two arguments, the first one of type int and the second one of type double. The identifiers numberPar and pricePar are called formal parameters. A formal parameter is used as a kind of blank, or place holder, to stand in for the argument. When you write a function declaration, you do not know what the arguments will be, so you use the formal parameters in place of the arguments. The names of the formal parameters can be any valid identifiers, but for a while we will end our formal parameter names with Par so that it will be easier for us to distinguish them from other items in a program. Notice that a function declaration ends with a semicolon.

The first word in a function declaration specifies the type of the value returned by the function. Thus, for the function totalCost, the type of the value returned is double.

As you can see, the function call in Display 4.3 satisfies all the requirements given by its function declaration. Let’s take a look. The function call is in the following line:

bill = totalCost(number, price);

The function call is the expression on the right-hand side of the equal sign. The function name is totalCost, and there are two arguments: The first argument is of type int, the second argument is of type double, and since the variable bill is of type double, it looks like the function returns a value of type double (which it does). All that detail is determined by the function declaration.

The compiler does not care whether there’s a comment along with the function declaration, but you should always include a comment that explains what value is returned by the function.

In Display 4.3 the function definition is in color at the bottom of the display. A function definition describes how the function computes the value it returns. If you think of a function as a small program within your program, then the function definition is like the code for this small program. In fact, the syntax for the definition of a function is very much like the syntax for the main part of a program. A function definition consists of a function header followed by a function body. The function header is written the same way as the function declaration, except that the header does not have a semicolon at the end. This makes the header a bit repetitious, but that’s OK.

Although the function declaration tells you all you need to know to write a function call, it does not tell you what value will be returned. The value returned is determined by the statements in the function body. The function body follows the function header and completes the function definition. The function body consists of declarations and executable statements enclosed within a pair of braces. Thus, the function body is just like the body of the main part of a program. When the function is called, the argument values are plugged in for the formal parameters and then the statements in the body are executed. The value returned by the function is determined when the function executes a return statement. (The details of this “plugging in” will be discussed in a later section.)

A return statement consists of the keyword return followed by an expression. The function definition in Display 4.3 contains the following return statement:

return (subtotal + subtotal * TAX_RATE);

When this return statement is executed, the value of the following expression is returned as the value of the function call:

(subtotal + subtotal * TAX_RATE)

The parentheses are not needed. The program will run exactly the same if the return statement is written as follows:

return subtotal + subtotal * TAX_RATE;

However, on larger expressions, the parentheses make the return statement easier to read. For consistency, some programmers advocate using these parentheses even on simple expressions. In the function definition in Display 4.3, there are no statements after the return statement, but if there were, they would not be executed. When a return statement is executed, the function call ends.

Let’s see exactly what happens when the following function call is executed in the program shown in Display 4.3:

bill = totalCost(number, price);

First, the values of the arguments number and price are plugged in for the formal parameters; that is, the values of the arguments number and price are substituted in for numberPar and pricePar. In the Sample Dialogue, number receives the value 2 and price receives the value 10.10. So 2 and 10.10 are substituted for numberPar and pricePar, respectively. This substitution process is known as the call-by-value mechanism, and the formal parameters are often referred to as call-by-value formal parameters, or simply as call-by-value parameters. There are three things that you should note about this substitution process:

  1. It is the values of the arguments that are plugged in for the formal parameters. If the arguments are variables, the values of the variables, not the variables themselves, are plugged in.

  2. The first argument is plugged in for the first formal parameter in the parameter list, the second argument is plugged in for the second formal parameter in the list, and so forth.

  3. When an argument is plugged in for a formal parameter (for instance, when 2 is plugged in for numberPar), the argument is plugged in for all instances of the formal parameter that occur in the function body (for instance, 2 is plugged in for numberPar each time it appears in the function body).

The entire process involved in the function call shown in Display 4.3 is described in detail in Display 4.4.

Display 4.4 Details of a Function Call

An illustration shows a code segment with the details of a “Function Call.”

Functions That Return a Boolean Value

A function may return a bool value. A function that returns a Boolean is called a predicate. Such a function can be used in a Boolean expression to control an if-else statement or to control a loop statement, or it can be used anywhere else that a Boolean expression is allowed. The returned type for such a function should be the type bool.

A call to a function that returns a Boolean value of true or false can be used anywhere that a Boolean expression is allowed. This can often make a program easier to read. By means of a function declaration, you can associate a complex Boolean expression with a meaningful name and use the name as a Boolean expression in an if-else statement or anywhere else that a Boolean expression is allowed. For example, the statement

if (((rate >= 10) && (rate < 20)) || (rate == 0))
{
    ...
}

can be made to read

if (appropriate(rate))
{
    ...
}

provided that the following function has been defined:

bool appropriate(int rate)
{     return (((rate >= 10) && (rate < 20)) || (rate == 0));
}

Alternate Form for Function Declarations

You are not required to list formal parameter names in a function declaration. The following two function declarations are equivalent:

double totalCost(int numberPar, double pricePar);

and

double totalCost(int, double);

We will always use the first form so that we can refer to the formal parameters in the comment that accompanies the function declaration. However, you will often see the second form in manuals that describe functions.2

This alternate form applies only to function declarations. Function headers must always list the formal parameter names.

Function Definition–Syntax Summary

Function declarations are normally placed before the main part of your program and function definitions are normally placed after the main part of your program (or, as we will see later in this book, in a separate file). Display 4.6 gives a summary of the syntax for a function declaration and definition. There is actually a bit more freedom than that display indicates. The declarations and executable statements in the function definition can be intermixed, as long as each variable is declared before it is used. The rules about intermixing declarations and executable statements in a function definition are the same as they are for the main part of a program. However, unless you have reason to do otherwise, it is best to place the declarations first, as indicated in Display 4.6.

Display 4.6 Syntax for a Function That Returns a Value

An illustration shows a code segment with the syntax of a “Function” that returns a value.

Since a function does not return a value until it executes a return statement, a function must contain one or more return statements in the body of the function. A function definition may contain more than one return statement. For example, the body of the code might contain an if-else statement, and each branch of the if-else statement might contain a different return statement, as illustrated in Display 4.5.

Any reasonable pattern of spaces and line breaks in a function definition will be accepted by the compiler. However, you should use the same rules for indenting and laying out a function definition as you use for the main part of a program. In particular, notice the placement of braces {} in our function definitions and in Display 4.6. The opening and closing braces that mark the ends of the function body are each placed on a line by themselves. This sets off the function body.

More About Placement of Function Definitions

We have discussed where function definitions and function declarations are normally placed. Under normal circumstances these are the best locations for the function declarations and function definitions. However, the compiler will accept programs with the function definitions and function declarations in certain other locations. A more precise statement of the rules is as follows: Each function call must be preceded by either a function declaration for that function or the definition of the function. For example, if you place all of your function definitions before the main part of the program, then you need not include any function declarations. Knowing this more general rule will help you to understand C++ programs you see in some other books, but you should follow the example of the programs in this book. The style we are using sets the stage for learning how to build your own libraries of functions, which is the style that most C++ programmers use.

Programming Tip Use Function Calls in Branching Statements

The switch statement and the multiway if-else statement allow you to place several different statements in each branch. However, doing so can make the switch statement or if-else statement difficult to read. Look at the switch statement in Display 3.7. Each of the branches for choices 1, 2, and 3 could be a single function call. This makes the layout of the switch statement and the overall structure of the program clear. If we had instead placed all the code for each branch in the switch statement, instead of in the function definitions, then the switch statement would be an incomprehensible sea of C++ statements. In fact, the switch statement would not even fit on one screen.

Self-Test Exercises

  1. What is the output produced by the following program?

    #include <iostream>
     using namespace std;
     char mystery(int firstPar, int secondPar);
     int main()
    {
        cout << mystery(10, 9) << "ow\n";
         return 0;
    } char mystery(int firstPar, int secondPar)
    {
        if (firstPar >= secondPar)
             return 'W';
         else
             return 'H';
    }

  2. Write a function declaration and a function definition for a function that takes three arguments, all of type int, and that returns the sum of its three arguments.

  3. Write a function declaration and a function definition for a function that takes one argument of type int and one argument of type double, and that returns a value of type double that is the average of the two arguments.

  4. Write a function declaration and a function definition for a function that takes one argument of type double. The function returns the character value 'P' if its argument is positive and returns 'N' if its argument is zero or negative.

  5. Carefully describe the call-by-value parameter mechanism.

  6. List the similarities and differences between use of a predefined (that is, library) function and a user-defined function.

  7. Write a function definition for a function called inOrder that takes three arguments of type int. The function returns true if the three arguments are in ascending order; otherwise, it returns false. For example, inOrder (1, 2, 3) and inOrder(1, 2, 2) both return true, while inOrder(1, 3, 2) returns false.

  8. Write a function definition for a function called even that takes one argument of type int and returns a bool value. The function returns true if its one argument is an even number; otherwise, it returns false.

  9. Write a function definition for a function isDigit that takes one argument of type char and returns a bool value. The function returns true if the argument is a decimal digit; otherwise, it returns false.

  10. Write a function definition for a function isRootOf that takes two arguments of type int and returns a bool value. The function returns true if the first argument is the square root of the second; otherwise, it returns false.