Functions

What Is a Function?

A function is a block of code under a particular name. You can call this name to execute the block of code whenever needed.

A function in C++ is composed 4 main parts:

  1. Function name — The name that’s going to be used to call the function.
  2. The body of the function — The place where the code of the functions is written.
  3. The parameters — Values that are passed to the function when calling it. A function can have any number of parameters (possibly zero).
  4. The return type — Functions return a value to the position where it was called. The return type specifies the type of that returned value. If a function doesn’t return anything, its return type should be void.

Syntax

How to Write a Function

Functions are written globally (outside the main function) with the following syntax:

return_type function_name(parameter1, parameter2, ... , parameterN) {
    // body of the function (the block of code)
}
  • return_type: The type of the value the function is going to return (e.g int, long long, string, etc). If return_type is void then the function won’t return any value.
  • function_name: The name given to the function so we can call it by this name.
  • parameter1, parameter2, ... , parameterN: The parameters of the function

How to Call a Function

To call a function we’ll use the following syntax:

function_name(value1, value2, ... , valueN);

Example

Let’s assume that the function doesn’t return anything (i.e return_type is void), there are no parameters, and that it just prints a simple text. It could look like this:

#include<iostream>
using namespace std;
 
void f() { // a function named f which doesn't return anything (void) and doesn't take parameters
    cout << "Hello Function" << endl;
}
 
int main() { // program starts here
    f();
    cout << "Hello Main" << endl;
    f();
}

Here the output will be:

Hello Function
Hello Main
Hello Function

This program contains two functions: f() and main(). C++ only calls main(), and inside it, other functions are called. First, The function f() is called by main(), so the program starts executing it. The statement cout << "Hello Function" << endl gets executed. When the function f() finishes, the program returns to main() and continues with the next statement, executing cout << "Hello Main" << endl;. After that, function f() is called again and cout << "Hello Function" << endl is executed a second time.

Parameters

Defining a Function with Parameters

Parameters are similar to variables. They receive a value whenever the function is called and they’re defined in a similar way parameter_type parameter_name. For example:

void multiply(int x, int y) {
    cout << x * y << endl;
}

Here we defined a function multiply() that accepts two parameters (x and y) and prints its their product.

Passing Parameters

Now, to call function multiply() we need to provide the values of x and y. This will be done by putting the values of x and y respectively between the brackets when calling multiply(). Note that the order of values given when calling a function must match the order of the parameters when defining the function. For example if we want to print the multiplication of 5 and 3 we’ll call multiply() in the following format:

multiply(5, 3);

What happened here is that multiply got called with x = 5 and y = 3.

flowchart BT
    subgraph Call
        F["multiply(5, 3);"]
    end

    subgraph Function
        M["int multiply(int x, int y)"]
        X["x = 5"]
        Y["y = 3"]
    end

    F --> X
    F --> Y
    X --> M
    Y --> M

Passing Parameters by Reference

When we call a function and pass a variable, the parameter saves a copy of the passed variable’s value. This means if we change the value of the parameter, the value of the passed variable won’t be changed. This is called passing by value. However, there’s another way of passing variables called passing by reference where the parameter doesn’t copy the value of the passed variable. Instead it becomes the variable itself — so changes to the parameter in the function affect the passed variable’s value.

To write a function that passes a parameter by reference we add a & character before the parameters name. For example, we’ll write a function that takes one integer and adds 1 to it. Let’s see how the function will look if we pass by value:

void addOneByValue(int x) {
    x = x + 1;
}

And if we use passing by reference:

void addOneByReference(int &x) {
    x = x + 1;
}

Let’s write a code using both functions.

#include<iostream>
using namespace std;

void addOneByReference(int &x) {
    x = x + 1;
}

void addOneByValue(int x) {
    x = x + 1;
}

int main() {
    int n = 5;
    addOneByValue(n); // x will copy the value from n, and n won't change
    cout << n << endl;
    addOneByReference(n); // x will become n itself, so editing x will edit n
    cout << n << endl;
}

The output will be:

5
6

Note that calling the functions doesn’t change. when we called addOneByValue(n);, the value of n got copied into x and when we changed x, n didn’t change. However, when we called addOneByReference(n);, x became n so when we added one to x, the value of n changed as well.

Returns

When a function finishes, it can return a value to the position where it got called. To do this, we need to specify the type of the returned value before the function name. The function then uses the return statement to provide the value. For example:

#include<iostream>
using namespace std;

int add(int a, int b) {
    return a + b;
}

int main() {
    int result = add(5, 3); // result now holds 8
}
  • int (before add) tells that the function will return an integer.
  • return a + b tells to return the value of a + b to the position where add() got called.
  • int result = add(5, 3) tells that the returned value will be assigned to result.

Here is a diagram that shows what happened:

sequenceDiagram
    participant main()
    participant Add()

    main()->>Add(): call add(5, 3)
    Add()->>Add(): compute a + b
    Add()-->>main(): return 8
    main()->>main(): result = 8

Note

After calling return a + b; the function ends immediatelly. Any statement after the return statement won’t be executed.

Recursivity

Functions Calling Other Functions

We can call a function within another function. If that function finishes it returns to the function that called it. For example this code:

#include<bits/stdc++.h>
using namespace std;

void m() {
    cout << "third" << endl;
}

void f() {
    cout << "second" << endl;
    m();
    cout << "fourth" << endl;
}

int main() {
    cout << "first" << endl;
    f();
    cout << "fifth" << endl;
}

The output is going to be:

first
second
third
fourth
fifth

The program starts by executing the main() function, which runs the statement cout << "first" << endl;. After that, main() calls the function f(). Inside f(), the statement cout << "second" << endl; is executed, and then the function m() is called. Inside m(), the statement cout << "third" << endl; is executed. When m() finishes, control returns to f(), where the program continues with cout << "fourth" << endl;. After that, f() finishes and returns to main(), which then executes the final statement cout << "fifth" << endl;.

Here’s a sequence diagram of what happened:

sequenceDiagram
    participant main()
    participant f()
    participant m()

    main()->>main(): cout << "first" << endl;
    main()->>f(): call f()
    f()->>f(): cout << "second" << endl;;
    f()->>m(): call m();
    m()->>m(): cout << "third" << endl;;
    m()-->>f(): return 
    f()->>f(): cout << "fourth" << endl;;
    f()-->>main(): return 
    main()->>main(): cout << "fifth" << endl;

Functions Calling Themself

A functions that calls itself is called recursitive. An example of a problem that can be solved using recursive functions is calculating factorials. In math, the factorial of a number \(n\) is written as \(n!\) and it is computed as follows.

\(n! = 1 * 2 * 3 * \ldots * (n - 1) * n\)

So, the factorial of \(4\) will be:

\(4! = 1 * 2 * 3 * 4 = 24\)

A function that calculates \(n!\) will look as follows:

#include<bits/stdc++.h>
using namespace std;

int factorial(int x) {
    if (x <= 1) {
        return 1;
    }
    else {
        return factorial(x - 1) * x;
    }
}

int main() {
    int n;
    cin >> n;
    cout << factorial(n) << endl;
}

Here we made a function that calls itself. For example, if we give it 3 as an input, the main function will call factorial(3), and it will call factorial(2) that will call factorial(1). factorial(1) will return 1 to the position that called it (in factorial(2)) which will return factorial(1) * 2 = 1 * 2 = 2 to factorial(3). Finally, factorial(3) will return factorial(2) * 3 = 2 * 3 = 6 to main(), which will print 6 at the output.

Note

The condition at the beggining of the recursion, if (x <= 1), is very important. Without it the function would be calling itself indefinitely.

sequenceDiagram
    participant main()
    participant f(3)
    participant f(2)
    participant f(1)


    
    main()->>f(3): call f(3)
    f(3)->>f(2): call f(2)
    f(2)->>f(1): call f(1)
    f(1)-->>f(2): return 1
    f(2)-->>f(3): return 1 * 2
    f(3)-->>main(): return 2 * 3