The basics

Functions are important building blocks of programs. A function is a named sequence of statements performing a task like computing the summation $\sum_{i=1}^{n}{i}$, for a given positive integer $n > 0$. It’s common that functions have one or several inputs and return one result. For instance, a function to compute $\sum_{i=1}^{n}{i}$ has as input one integer, let us call it $n$. The result returned by the function is also an integer. The C++ function definition computing the summation of the first $n$ natural numbers is given below. Recall that $\sum_{i=1}^{n}{i} = \frac{n(n+1)}{2}$.

1
2
3
4
5
6
7
// Return the sum of integers from 1 to n
int sum(int n) 
{
    int result = (n * (n + 1)) / 2;

    return result;
}

The first line of the function’s definition (line $2$) gives the following information about the function:

  • The function’s name. Obviously, the name of the function (sum) should be related to the task the function accomplishes.
  • The formal arguments (also called formal parameters). The formal arguments indicate which input the function expects to be passed to it so that it can perform its task. For instance, function sum requires as input one integer value which is called n in the function.
  • The type of the result returned by the function. Function sum returns an int value.

Sum 1 to n.

Between the curly brackets ({ and }), there’s the function’s body (lines $3$ to $7$) which consist of one or several lines of code describing how the function’s result should be computed.

Return statements

Functions must have a return-statement (line $6$ of the function above) which state the value returned as output of the function. For instance, return result; states that the value stored in the variable result is returned as output of the function.

Note that the function above could also have been written as follows.

1
2
3
4
5
// Return the sum of integers from 1 to n
int sum(int n) 
{
    return (n * (n + 1)) / 2;
}

In this case, the function’s body consists solely of a return-statement (line $4$). This statement implies that the expression n * (n - 1)) / 2 is first computed and then its value is returned as output of the function. Note that the result of the expression n * (n - 1)) / 2 is of type int (i.e. the result type of the function).

Keep in mind that when a return-statement is executed the function ends (i.e. no statements within the function are executed after a return has been executed in the function). Consider the following definition of function sum.

1
2
3
4
5
6
7
8
9
// Return the sum of integers from 1 to n
int sum(int n) 
{
    int result = (n * (n + 1)) / 2;

    return result;
	
    std::cout << result; // unreachable code is a bad programming practice!!
}

Though the function above compiles and computes the correct result, the statement in line $8$ is never executed because a return-statement is executed before and execution of a return ends the execution of any code in the function. Most of the compilers do actually issue a warning message like “unreachable code”. Try to see what compiler warning you get with your compiler (if any). This type of warning should not be ignored and it must be fixed. Who reads the code of a function expects that all statements in its body are executed at some point. Otherwise, why would a programmer bother to write code that never executes?!

It’s a bad programming practice to have code in a function that is never executed.

A function may, however, have several return-statements. See the following function, named absolute_value which returns the absolute value of an input number x (double).

1
2
3
4
5
6
double absolute_value(double x) {
    if (x < 0) { // is x a negative number?
        return -x;
    } 
    return x;
}

The function starts by testing if x is a negative number. And, if that’s the case then the value of -x is returned (line $3$). Otherwise, the value of x is returned (line $5$). It’s important to realize that only one of the return-statements is executed (either the one in line $3$ or the one in line $5$), depending on whether x < 0.

Note that if a function is declared to return a value (like function absolute_value declares to return an value of type double) then it’s an error that the function ends without executing a return-statement where a double value (or a value that can be converted to a double) is sent out of the function as its result. Consider, for example, that someone wrote function absolute_value as follows.

double absolute_value(double x) {
    if (x < 0) {
        return -x;
    } else if (x > 0) {
        return x;
    }
	
    // Error: if x == 0 then no value is returned!!
}

Some compilers report this problem as a warning, not as a compilation error. This is definitely a warning that shouldn’t be ignored and must be fixed. In practice, if the compiled code is executed then the program has undefined-behavior, i.e. it may seem to give the correct result in some systems and it may not-work in other systems.

Flowing off the end of a function is equivalent to executing a return-statement with no value. This results in undefined behavior in a value-returning function.

Probably you have noticed that the main() of any C++-program is also a function and that it returns an int. However, this is a special function for which you don’t need to write any return-statement. The compiler automatically makes sure that the main returns the value 0, if the programmer does not provide a return-statement.

Function calls

We have so far examined how to define functions. In this section, we discuss how functions can be used in programs.

Consider again the function sum which computes the summation $\sum_{i=1}^{n}{i}$, for a given positive integer $n$.

Assume that we want to write a program that starts by reading a positive integer given by the user, let’s call it a. Then, the program displays the value of $\sum_{i=1}^{a}{i}$. Obviously, the function sum can be useful here. You can find below the program.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>

// Return the sum of integers 1 to n
int sum(int n) {
    int result = (n * (n + 1)) / 2;

    return result;
}

int main() {
    std::cout << "Enter a:\n";
    int a;
    std::cin >> a;
	
    if (a > 0) {
        std::cout << sum(a); // call function sum for argument a
    }
}

An important aspect to have in mind is that the execution of a C++-program starts always with the main.

Therefore, it does not matter how much code or how many functions one writes before the main, the execution of a C++ program always starts with the first statement in the main function.

In line $16$ of the main above there is a function call sum(a), or in other words, the main calls function sum. This means that the main requests that function sum is executed with the input a. The following steps are then automatically performed when a function is called.

  1. The formal argument n of function sum receives the value of variable a defined in the main.
  2. The statements in the body of function sum are executed (lines $5$ to $7$).
  3. When the function sum executes the return-statement (line $7$), the value of variable result is passed to the caller (the main).
  4. Execution of the program continues in the caller (line $16$), i.e. the result returned by function sum is written to std::cout.

So, as you can see, calling a function implies that the computer has to perform a rather complicated task with all the four steps described above. Fortunately, all the programmer needed to do was to write the simple code sum(a) to execute function sum with the input a.

It’s common that the function definitions are placed after the main (see below). This better reflects that the execution of a C++-program always starts with the statements in the main and it’s the main that describes the purpose of the whole program. However, in this case, a function declaration must always be placed before a function call. A function declaration consists only of the function’s header, int sum(int n);. We often prefer this way of writing C++-programs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

int sum(int n);  // function declaration

int main() {
    std::cout << "Enter a:\n";
    int a;
    std::cin >> a;
	
    if (a > 0) {
        std::cout << sum(a); // call function sum for argument a
    }
}

// function definition
// Return the sum of integers 1 to n
int sum(int n) {
    int result = (n * (n + 1)) / 2;

    return result;
}

Formal and actual arguments

Function sum has one input argument (an int) named n. The input arguments appearing in the function definition are technically called formal arguments (or formal parameters) of the function. For instance, function min (see below) has two formal arguments, named x and y, of type double.

The actual input expressions (or variables) passed to a function in a function call statement are designated as actual arguments (or actual parameters). For instance, line $11$ of the program above has a function call sum(a) and variable a is the actual argument passed to function sum.

Observe the code excerpt below. It contains the function call min(5.0, d). The constant 5.0 and variable d are the actual arguments passed to function min. Thus, the formal arguments of the function min, x and y, receive value $5.0$ and the value stored in variable d, respectively.

double d = 20.6;
std::cout << min(5.0, d);

min function.

Examples

The actual arguments in a function call f(exp1, exp2,...) can be any expression with the same type of the corresponding formal arguments of the function f.

Consider the example below.

double d = 20.6;
std::cout << min(d+5, 2*d);

Both expressions d+5 and 2*d evaluate to values of type double and are, therefore, compatible with the type of input expected by the function min.

The following code computes the smallest of three user given numbers.

double d1;
double d2;
double d3;
std::cin >> d1 >> d2 >> d3;

double d4 = min(d1,d2);
std::cout << min(d4, d3);

Note that the expression min(d1, d2) evaluates to a double and that the formal arguments of function min are also of type double (in other words,function min expects two input arguments of type double). We can, therefore, use min(min(d1, d2), d3) to compute the minimum of the three variables d1, d2, and d3.

double d1;
double d2;
double d3;
std::cin >> d1 >> d2 >> d3;

std::cout << min(min(d1,d2), d3);

The example above shows that function calls can also appear as actual arguments in other function calls. Another example can be, for instance, min(std::sqrt(d1), d2).

Next, two examples are presented with complete C++-programs. We strongly encourage you to attempt to write your own code. We stress that you won’t learn coding by just reading and understanding the code the others write for you.

Example $1$: The program below computes $\sum_{i=a}^{b}$, for two user given positive integers $a <= b$. Recall that $\sum_{i=a}^{b}{i} = \sum_{i=1}^{b}{i} - \sum_{i=1}^{a-1}{i}$. A new function is defined to compute $\sum_{i=a}^{b}{i}$ which in turn calls the function sum presented earlier.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>

// Return the sum of integers from 1 to n
int sum(int n);

// Return the sum of integers from a to b
int sum(int a, int b);

/* ****************** */

int main() {
    std::cout << "Enter two positive integers:\n";
    int a;
    int b;
    std::cin >> a >> b;
	
    if (a > 0 && b > 0 && a <= b) {
        std::cout << sum(a, b) << "\n";
    }
}

/* ****************** */

// Return the sum of integers from 1 to n
int sum(int n) {
    int result = (n * (n + 1)) / 2;

    return result;
}

// Return the sum of integers from x to y
int sum(int x, int y) {
    return (sum(y) - sum(x-1));
}

Perhaps, you noticed that there are two different functions with same name, sum: one of the functions has one argument, while the other function has two arguments. This is perfectly possible, and often used, in C++-programs. Technically speaking, we say that function sum is overloaded. You can read more about this concept in the section Overloading.


Example $2$: Assume that we want to write a program that computes the trigonometric function $\sin (\theta)$, for a given angle of $\theta \geq 0$ degrees. Though this function exists in the C++-standard library, the idea is that the program makes its own (approximate) computation of the $\sin$-function using a Taylor-series: $\sin (x) = x - \frac{x^3}{3!} + \frac{x^5}{5!} - \frac{x^7}{7!} + \frac{x^9}{9!} - \cdots$. Since the series has an infinite number of terms, one can stop the computation when a term becomes very small, i.e. when $\frac{x^i}{i!} <= \delta$ (e.g. $\delta$ is a small constant like $10^{-5}$). Note that $x$ is an angle given in radians, though the program should handle angles in degrees. Therefore, a function to convert angles in degrees to radians is defined in the program.

Recall also that $n!$, for an integer $n>=0$, is the well-known factorial function. A function to compute the factorial is also defined in the program and it returns a long long because the factorial grows very rapidly and can return very large integer results.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <iostream>
#include <iomanip>

// Return the factorial of n, n!
long long factorial(int n);

// Return x^i
long double power(double x, int i);

// Convert degrees to radians
double radians(double degrees);

// Return sin(x) computed by Taylor-series
long double compute_sin(double x);

/* ****************** */

int main() {
    std::cout << "Enter angle (degrees):\n";
    double angle;
    std::cin >> angle;
	
    if (angle >= 0) {
       std::cout << "sin(" << angle << ")= ";
       std::cout << std::fixed << std::setprecision(4) << compute_sin(radians(angle)) << "\n";
    }
}

/* ****************** */

// Return the factorial of n, n!
long long factorial(int n) {
    long long prod = 1;

    for (int i = 2; i <= n; ++i) {
        prod *= i;
    }
    return prod;
}

// Return x^i
long double power(double x, int i) {
    if (i == 0) {
        return 1.0;
    }

    long double res = x;
    for (int k = 1; k < i; ++k) {
        res *= x;
    }
	
    return res;
}

// Convert degrees to radians
double radians(double degrees) {
    double constexpr pi = 3.14159265358979323846;
    double radians = (pi / 180) * degrees;

    return radians;
}

// Return sin(x) computed by Taylor-series
long double compute_sin(double x) {
    constexpr double delta = 10e-5;
    long double result = x;

    // Compute first term of the series
    int i = 3;
    long double next_term = power(x, i) / factorial(i);

    int sign = -1;
    while (next_term > delta) {  // stop computation when next_term <= delta
        // add next_term to the result
        result += (sign * next_term);

        i += 2;
        sign *= -1;

        // compute next term of the series
        next_term = power(x, i) / factorial(i);
    }
	
    return result;
}

Modify the code above by adding a function that reads and validates the input angle entered by the user. This function should verify that the angle given by the user is non-negative. If the user enters a negative angle then an error message is displayed and the user is requested to enter another angle again. Finally, add to the main a call to the the validation function you have written.


Functions without arguments

It’s possible that some C++-functions perform a computation without requiring any input. In this case, the list of function arguments is empty, i.e. no arguments are given between the round brackets. An example is given below of a function that simulates the throw of a dice, called roll_dice.

int roll_dice() {
    int dice =  std::rand() % 6 + 1;
	
    return dice;
}

int main() {
    // Roll a dice 10 times
    for(int i = 1; i <= 10; ++i) {
	   std::cout << roll_dice() << " ";
	}
}

Functions that return no value

There are also functions that do not return any value. These functions only perform an action, like to display a menu of options, instead of computing a value and returning it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void display_menu(int n) {
    // Display a line of n consecutive characters '-'
    std::cout << std::setw(n) << std::setfill('-') << "\n";
    std::cout << "1. Calculate sin(x)\n";
    std::cout << "2. Calculate cos(x)\n";
    std::cout << "3. Calculate tan(x)\n";
    std::cout << "4. Exit\n";
    std::cout << std::setw(n) << "\n";  // fill character is '-'
    std::cout << "Your option? ";

    // reset the fill character to white-space
    std::cout << std::setfill(' ');

    return;  // not needed
}

The return type void is used to indicate that the function does not return any value (see line $1$). For this reason, a function that returns no value is often called a void-function.

The function ends with a return-statement (line $14$) without giving any value to be returned as result. Thus, the return-statement (as in line $14$) just indicates that the function ends its computation. Note that it’s not required to have a return-statement in a void-function. Thus, the return in line $14$ of the function above is optional. If the programmer does not write it then the compiler will add a return-statement in the end of the function’s body, automatically (but, this only happens for void-functions).