next up previous contents
Next: Structs Up: Getting Started in C++ Previous: Loops   Contents

Subsections

Functions

Now we come to one of the most important topics of this tutorial: functions. A function is a way to group some code and give it a name; so all the code can later be executed just using its name. Inside a function you can execute (``call'') other functions, or even the function itself (in which case the function is called a recursive function).

If a function takes arguments, this means that it is possible to pass it one or more objects (the arguments) and that the function will then be able to do things with those arguments. For example, there might be a function called send to send emails taking the destination and the text of the mail as arguments. Or a function power taking the base and the exponent as arguments, and so on. Notice that not all functions have arguments, and that it is not possible to pass arguments to a function which doesn't take any or not to pass any to one which does; when you write the function, you decide if and what kind of arguments it takes, and after that you have to use it that way.

A function may also have a return value, through which it can pass one object back to the caller (the ``caller'' is the code which called the function). This might be used, for example, in the function power described above to give the value of the power back to the caller.

A function consist of two parts: a declaration, which explains what the function is called, what types arguments it takes (if any) and what type of return value it has (if any); and the body, which is the block of statements executed whenever the function is called. Here an example program:

#include <iostream>
using namespace std;

int square(int n) {
    return n * n;
}

int main() {
    int num;
    do {
        cout << "What do you want to know the square "
             << "of (enter 0 to quit): "; 
        cin >> num;
        cout << "The square of " << num << " is " 
             << square(num) << ".\n"; 
    } while (num != 0);
}
Does this square stuff not look suspiciously like the int main() stuff you had to write in each and every program until now without knowing why? Right. But more on that later.

The Declaration

In the above program, the declaration of the function square is

int square(int n)
What does this mean? Notice that it is divided into three parts. The first part (the int) is the return type. In this case it means: this function returns an int. The second part (square) is the name. It can be anything you like, with the same limitations as for object names (see 3.2.1). The third part ((int n)) is the argument list, specifying the type and name of each argument. In this case it means: this function takes one argument of type int (which will be called n inside the function). Notice that the name of an argument (like ``n'') has absolutely no influence of how the caller sees it. That n could have been called x or frodo; for the caller it would not make any difference.

To declare a function with no arguments, just leave the parentheses empty.

// A silly function which always returns 3
int three() {
    return 3;
}
And if you need more than one argument separate them by commas, like here:
// Calculates the average of 2 numbers
double average(double n1, double n2) {
    return (n1 + n2) / 2;
}

// Returns the string s n times
// For example mult_string("hello", 3) would return
// "hellohellohello".
string mult_string(string s, int n) {
     string total;
     for (int i = 0; i < n; ++i)
         total = total + s;

     return total;
}

The Body

Now, to the second part: the body. It is little more than a normal block of code. One of the differences is that it has access to the arguments, if there are any. For example, in the square function described above the first (and only) statement accesses the argument n. Of course, if you renamed n to x or frodo, you'd also have to adapt that statement.

return

You surely have noticed the return statement. It is used -- as you probably guessed -- to return a value to the caller. That value has of course to be of the same type as the one specified in the declaration; as we declared a function returning an int, and as the product of two ints is another int, our function works fine.

But how does the return statement really work? Very simply. As soon as it is executed, the function exits and execution goes on after the function call. The function returns the value passed to the return statement.

Every function with a return value -- in other words all functions except the ones described in 6.4 -- must return a value. Otherwise the compiler wouldn't know what to return to the caller.

Calling a Function

The function call is inside the body of the main function, and looks like this:

square(num)
But what does this do? It calls the function square, passing it the value of num. As the function returns the square of n, it behaves like some kind of variable; we could have obtained the same effect writing
int sq = square(num);
cout << sq;

There is one thing to think of, though. Whenever we call the function square the code in its body is executed; thus

cout << square(num);
cout << square(num);
and
int sq = square(num);
cout << sq;
cout << sq;
are not the same thing. In the first case the function is called twice and its return value is send to standard output; in the second case the function is called once, its return value stored in sq and then sent to standard output twice. In this case the output is the same, but only because the function square depends only on its argument. If we used -- for example -- a random number function returning a different number each time it would not be the same thing.

There are also functions which do not take any arguments at all, like the function three shown above. You must use the parentheses all the same, like this:

cout << three();
Only writing three instead of three() will not call the function; it does something completely different which I'll explain later. It is thus possible that your code compiles anyway, but your program will likely not do what you intended.


void Functions

There are also functions with no return value. They are declared just as any other function, but with return type void, like this:

void display_help() {
    cout << "This program is used to bla bla bla...";
}
Of course, you cannot return any value from a void function, but you can use the return statement anyway, just with no arguments. It is used to exit the function. It is not compulsory that you use return though, as it is in the non-void functions; if you don't, the function exits when it reaches the end of the body.


Scope

Remember what we said about scope referring to the for loop (4.4)? Now, with functions, scope becomes even more important, and it is essential that you perfectly understand how it works.

As usual, this is best explained with an example. The program

#include <iostream>
using namespace std;

// M is a global variable
int m;

int f(int n) {
    // Here a *copy* of the argument is modified, *not*
    // the object which was passed
    n = n + 1;
    return n;
}

int g() {
    // Here the global variable m is increased
    m = m + 1;
    return m;
}

int main() {
    // This n is local to this function, and *not* the
    // same thing as the n in the function f.
    int n = 5;
    cout << "n = " << n << "\n";
    cout << "f(n) = " << f(n) << "\n";
    cout << "n = " << n << "\n";
    
    // This is the global m declared at the beginning
    // of the program. It is the same m which is
    // modified in the function g.
    m = 5;
    cout << "m = " << m << "\n";
    cout << "g() = " << g() << "\n";
    cout << "m = " << m << "\n";
}
gives the output
n = 5
f(n) = 6
n = 5
m = 5
g() = 6
m = 6
; as you can see, the global variable m can be modified by all the functions, while the two local variables n are completely independent and can be modified only inside the function they are declared in.

int main()

You have surely noticed that int main() is nothing but a function. It is different from other functions, though.

main is never called by your code. It is called automatically when the program starts. It is illegal to call it manually. (Something is said to be illegal if it is not allowed by the Standard, or, in other words, if it is an error.)

It is not necessary to put a return statement into main. In fact, there are only two values you should return from main: either EXIT\_SUCCESS or EXIT\_FAILURE. You return EXIT\_SUCCESS if your program terminated successfully, or EXIT\_FAILURE if it didn't. (For example, if you write a program to count the words in a text file, it might return EXIT\_FAILURE if it cannot open the file.) If you do not return anything, the compiler returns EXIT\_SUCCESS for you. You are also allowed to return 0 instead of EXIT\_SUCCESS. If you want to use EXIT\_SUCCESS and EXIT\_FAILURE you must include <cstdlib>.


Pass-by-Value

In C++ arguments are passed by value. This means that if you pass a function an argument you do not pass it the object itself, only a copy of it. This means that a function cannot modify an argument you gave it. For example, this program

#include <iostream>
using namespace std;

void f(int n) {
    n = 4;
}

int main() {
    int m = 1;
    cout << m << "\n";
    f(m);
    cout << m << "\n";
}
will print
1
1
. You have already seen this behavior in the program presented in 6.5; there, n was not modified in the function f.

Recursive Functions

It is possible to call a function from itself; in this case the function is recursive. For example, the following function is recursive:

void f() {
    f();
}
Of course, that function would never exit once it started, but continue running until the computer runs out of memory or something else bad happens. A recursive function should thus always have some condition to terminate. Look at the following program which uses a recursive function to print a sequence of numbers:
#include <iostream>
using namespace std;

void recursive_function(int start, int end) {
    if (start < end) {
        cout << start << " ";
        recursive_function(start + 1, end);
    }
}

int main() {
    recursive_function(1, 10);
}
It output is
1 2 3 4 5 6 7 8 9 

But how does it work? First, it checks whether start < end. If this is true, it prints out start and then calls itself with the same end but with start increased by one. This means that the following happens:

  1. The function is called with start == 1 and end == 10.

  2. It checks whether start < end. As start is 1 and end is 10, this is true.

  3. It prints out start, thus 1.

  4. It calls itself with start + 1 and end as arguments. In other words the function returns to step 1, but this time start is 2. And then 3. And 4. And so on, until start is 10. Then, the check in step 2 fails, and thus the number is not printed out and the function is not called again, and everything finishes.

This should be quite simple. It starts getting more complicated if we add one line to the function, as follows:

#include <iostream>
using namespace std;

void recursive_function(int start, int end) {
    if (start < end) {
        cout << start << " ";
        recursive_function(start + 1, end);
        cout << start << " ";
    }
}

int main() {
    recursive_function(1, 10);
}
Now the output is -- hold your breath -- this one:
1 2 3 4 5 6 7 8 9 9 8 7 6 5 4 3 2 1 

You probably expected something along the lines of 1 1 2 2 3 3 ..., didn't you? If you knew what'd happen, congratulations. Otherwise, read this explanation.

In a recursive function, at some time there is more than one instance of the same function. Each of these instances has its own local variables, which do not affect the variables of the other instances. The call recursive\_function(start + 1, end) inside the function returns only when it has finished executing; thus something along the lines of the following happens:

recursive_function(1, 10) is called
cout << 1;
  recursive_function(2, 10) is called
  cout << 2;
    recursive_function(3, 10) is called
    cout << 3;
      recursive_function(4, 10) is called
      cout << 4;
        ...
          recursive_function(10, 10) is called
          The condition is false, thus this does NOTHING
        ...
      cout << 4;
      recursive_function(4, 10) exits
    cout << 3;
    recursive_function(3, 10) exits
  cout << 2;
  recursive_function(2, 10) exits
cout << 1;
recursive_function(1, 10) exits

Although recursive functions are not too widely used because they are generally error-prone and not very efficient, it is good to know that they exist because some problems can be solved much easier with them than without, especially if speed and stability is not so important.

Examples

Functions are used by the dozens, hundreds or even thousands in every ``real'' program; it is thus easy to come up with examples. They are both used to store repeated code and to split functions which would otherwise be too long to understand and maintain.


#include <iostream>
using namespace std;

// Print a line of '-' to divide one average from the
// other.
void delimiter() {
    for (int i = 0; i < 79; ++i)
        cout << "-";

    cout << "\n";
}

// Ask for n numbers and calculate their average.
void average(int n) {
    double sum = 0;

    for (int i = 1; i <= n; ++i) {
        // Ask for a number
        cout << "Enter number " << i << " of " << n
             << ": ";
        double num;
        cin >> num;
        
        // Add the number to the sum
        sum = sum + num;
    }

    // Print the average
    cout << "The average is: " << sum / n << ".\n";
}

int main() {
    // A for(;;) loop repeats for ever. We use 'return'
    // to jump out of the function directly
    for (;;) {
        cout << "How many numbers do you want to "
             <<"calculate the average of (0 to exit): ";
        int num;
        cin >> num;

        // Jump out of the function if the user entered
        // zero
        if (num == 0)
            return 0;

        // Do the average and display a delimiter (line)
        average(num);
        delimiter();
    }
}

Exercises

  1. Write a function called area_of_circle taking the radius of a circle as argument and returning its area. Both the radius and the area should be doubles. (The area of a circle is $\pi r^2$.) Also write a program to test the function.

  2. Write at least two other functions like area_of_circle from exercise 1 to calculate other things (area of a square, a triangle, volume of a cube, whatever you like best). Then write a program displaying a menu, asking the user what he wants to calculate, asking for the appropriate data and doing the right calculation.

  3. Take the program from exercise 2 and put the menu in a separate function called display_menu which displays the menu, asks the user for his choice and returns an int with the user's choice.

  4. Modify the function from exercise 3 in a way that it will continue asking until the user inputs a valid selection. (Hint: use a do...while loop.)


next up previous contents
Next: Structs Up: Getting Started in C++ Previous: Loops   Contents
Aaron Isotton <aaron@isotton.com>
2003-02-24