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.
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;
}
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.
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.
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.
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.
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.
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>.
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.
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:
start == 1 and end == 10.
start < end. As start is 1 and end is 10, this
is true.
start, thus 1.
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.
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();
}
}
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
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.
display_menu which displays the menu, asks the user
for his choice and returns an int with the user's choice.
do...while loop.)