Skip to main content
caution

Note, this article is not finished! You can help by editing this doc page.

Functions

In this lesson you will learn how to teach a program to perform actions, with the ability to reuse them.

Motivation

One of the advantages of using functions is the reduction of duplicates in the code. See example below, the version without and with functions. At this point you do not need to understand the notation of the example with the function - we will explain it later in this lesson.

#include <iostream>
#include <vector>

int main()
{
std::vector<int> numbers = {1, 4, 13, 15};

for (int i : numbers) {
std::cout << i << ' ';
}
std::cout << '\n';

numbers.push_back(13);

for (int i : numbers) {
std::cout << i << ' ';
}
std::cout << '\n';

numbers.push_front(3);

for (int i : numbers) {
std::cout << i << ' ';
}
std::cout << '\n';
}

In the example above, we create an array of numbers and modify it, displaying the contents each time. The difference between the two versions is that the first one contains a piece of code that we have copy-pasted several times. In the second, more correct version, we teach our program once how to display an array of numbers and then use it repeatedly when we need it.

Functions have many other uses and we will show some of them in this lesson. But for now we need to go back to the basics.

Introduction

Definition

A function is a separate piece of code that we can reuse many times.

From the very beginning of our study, we included a special function in our programs, which is main.

int main() {
// program code
}

A computer running a program finds the function main and then executes it, passing each statement inside, line by line.

Creating functions

We will start with the simplest features, gradually moving to more and more advanced features.

Without parameters

Scheme of the simplest function

As we can see above, when defining our own function, we have to take care of its name and body, sticking to the syntax. After the word void we write function name, then we put empty parentheses (we'll talk about that later in this lesson), then without a semicolon we place below block of code, which we call the function body.

Naming

When naming a function, follow the same rules as for variable names.

Now we already have our function defined. This means that whenever we want to, we can call it. We do it this way:

Calling the print function
print();
caution

Note that we put a semicolon after the function call, because it's also the end of the statement.

Let's write an example function that displays 10 even numbers and use it a few times:

#include <iostream>

// Function definition
void print_10_even_numbers()
{
for (int i = 0; i < 10; i++)
std::cout << (i * 2) << ' ';
std::cout << '\n';
}

int main()
{
// Calling the function
print_10_even_numbers();
print_10_even_numbers();
print_10_even_numbers();
}
Result (console)
0 2 4 6 8 10 12 14 16 18
0 2 4 6 8 10 12 14 16 18
0 2 4 6 8 10 12 14 16 18

With parameters

Scheme of a function with parameters

The behavior of the function can depend on parameters. If you want the function to display any number of even numbers, we can create a parameter in the function, that will control it. A parameter is a variable inside the function, which we create inside the parentheses

#include <iostream>

void print_even_numbers(int how_many)
{
for (int i = 0; i < how_many; i++)
std::cout << (i * 2) << ' ';
std::cout << '\n';
}

int main()
{
print_even_numbers(10);
print_even_numbers(5);
print_even_numbers(3);
}

The above notation

print_even_numbers(10);

means that when called, the how_many parameter inside this function will be assigned the value 10. We can pass any number of parameters to the function. Separate them by commas:

Print the bigger of two numbers
#include <iostream>

void print_bigger_number(int a, int b)
{
if (a > b)
std::cout << a << '\n';
else
std::cout << b << '\n';
}

int main() {
print_bigger_number(3, 5);
print_bigger_number(5, 3);
print_bigger_number(3, 10);
}
Common mistake

Notice that we place the function parameters after a comma, each time specifying its type. A common mistake among beginners is omitting the type in the following parameters.

void print_bigger_number(int a, b)

Return statement

We can tell the program to return from a function earlier, using a statement:

return;

Upon encountering it, the program stops executing further instructions in the function and returns to the place from which it was called. Let's recall the function we created earlier - print_even_numbers

void print_even_numbers(int how_many)
{
for (int i = 0; i < how_many; i++)
std::cout << (i * 2) << ' ';
std::cout << '\n';
}

What happens if we pass a negative number to how_many?

print_even_numbers(-10);

Executing a function with such a parameter value makes no sense, so we can detect this at the very beginning and use the return:

void print_even_numbers(int how_many)
{
if (how_many <= 0)
return;

for (int i = 0; i < how_many; i++)
std::cout << (i * 2) << ' ';
std::cout << '\n';
}

Now if we pass a value less than or equal to zero to a function parameter, the function will be terminated at the beginning.

Return value

Schema of a function with parameters and return value

Functions can produce a result after their execution. It will be easier to understand this if we use an analogy to real life. Father sends his child to the store to buy 10 eggs. When the child returns, he will want to know, whether the child managed to buy as many as he asked for or not. In the same way, we, performing some functions in code, we want to know the result, the return value.

Return value type

It is required to specify what type the return value is. We specify it before the function name, example:

We return an integer
int sum(int from, int to)
No return value is produced
void print(int number)

Notice that we have introduced a new type: void. If we write it in place of the return type, it means that the function does not return a value, i.e. we do not need to know its result. Note that we used void in the previous sections of this lesson for this very reason.

Void as a variable type

The void type cannot be used to create a variable:

❌ Illegal use
void variable;

A variable inherently stores a value, which would be impossible if it were of type void.

Usage

Let's implement the function from the diagram above. It is to count the sum of all numbers in the range from to to inclusive.

int sum(int from, int to)
{
int result = 0;
for (int i = from; i <= to; i++)
result += i;
return result;
}

We can use the returned value, for example, by writing it to a variable:

Saving the result to a variable
int s = sum(10, 100);

... or use in an expression (for example, as a function parameter):

Using a result
std::cout << "Sum of the numbers in range [10; 100] equals: " << sum(10, 100);

Requirements

Returning a value is mandatory

A function that returns some value (anything other than a `void' type), must at the very end of its execution return some value.

❌ Error: No value returned
int sum(int from, int to)
{
int result = 0;
for (int i = from; i <= to; i++)
result += i;
// ❌ No return statement!
}

An exception is the main function, which, despite returning an int type, performs an automatic return of a value 0 when return is omitted:

✔ Acceptable
int main() {
// No "return" statement
}

We will say more about the main function in the future.

Declaration and definition

In order to use the above sum function, we need to make sure that it is before this use, for example:

#include <iostream>

int main()
{
// Error: used before the definition
std::cout << "Sum of the numbers in range [10; 100] equals: " << sum(10, 100);
}

int sum(int from, int to)
{
int result = 0;
for (int i = from; i <= to; i++)
result += i;
return result;
}

Making sure that the order always matches is troublesome and sometimes even impossible. To fix the error in the above example, we have to use so called function declaration.

So far, when creating functions we used function definition which besides declaration, also contains its entire implementation (body). Declaring a function looks like defining it, without providing its body. We also need to take care to put a semicolon after the declaration.

🔵 Definition
int sum(int from, int to)
{
int result = 0;
for (int i = from; i <= to; i++)
result += i;
return result;
}
🟣 Declaration
int sum(int from, int to);

The rule is that in order to use a function, it must be declared beforehand. The definition must appear, but it does not matter if it is before or after the use. Here are two examples:

#include <iostream>

// 🟣 Declaration
int sum(int from, int to);

int main()
{
std::cout << "Sum of the numbers in range [10; 100] equals: " << sum(10, 100);
}

// 🔵 Definition
int sum(int from, int to)
{
int result = 0;
for (int i = from; i <= to; i++)
result += i;
return result;
}
The One Definition Rule (ODR)

The definition must appear in the code only once (there can be multiple declarations).

Summary

  • We use functions to group code into named blocks.
  • Functions can be called (invoked) to execute the code inside them.
  • Functions can return a value.
  • Functions can accept parameters.
  • Functions can be declared and defined separately.
caution

Note, this article is not finished! You can help by editing this doc page.

Functions

In this lesson you will learn how to teach a program to perform actions, with the ability to reuse them.

Motivation

One of the advantages of using functions is the reduction of duplicates in the code. See example below, the version without and with functions. At this point you do not need to understand the notation of the example with the function - we will explain it later in this lesson.

#include <iostream>
#include <vector>

int main()
{
std::vector<int> numbers = {1, 4, 13, 15};

for (int i : numbers) {
std::cout << i << ' ';
}
std::cout << '\n';

numbers.push_back(13);

for (int i : numbers) {
std::cout << i << ' ';
}
std::cout << '\n';

numbers.push_front(3);

for (int i : numbers) {
std::cout << i << ' ';
}
std::cout << '\n';
}

In the example above, we create an array of numbers and modify it, displaying the contents each time. The difference between the two versions is that the first one contains a piece of code that we have copy-pasted several times. In the second, more correct version, we teach our program once how to display an array of numbers and then use it repeatedly when we need it.

Functions have many other uses and we will show some of them in this lesson. But for now we need to go back to the basics.

Introduction

Definition

A function is a separate piece of code that we can reuse many times.

From the very beginning of our study, we included a special function in our programs, which is main.

int main() {
// program code
}

A computer running a program finds the function main and then executes it, passing each statement inside, line by line.

Creating functions

We will start with the simplest features, gradually moving to more and more advanced features.

Without parameters

Scheme of the simplest function

As we can see above, when defining our own function, we have to take care of its name and body, sticking to the syntax. After the word void we write function name, then we put empty parentheses (we'll talk about that later in this lesson), then without a semicolon we place below block of code, which we call the function body.

Naming

When naming a function, follow the same rules as for variable names.

Now we already have our function defined. This means that whenever we want to, we can call it. We do it this way:

Calling the print function
print();
caution

Note that we put a semicolon after the function call, because it's also the end of the statement.

Let's write an example function that displays 10 even numbers and use it a few times:

#include <iostream>

// Function definition
void print_10_even_numbers()
{
for (int i = 0; i < 10; i++)
std::cout << (i * 2) << ' ';
std::cout << '\n';
}

int main()
{
// Calling the function
print_10_even_numbers();
print_10_even_numbers();
print_10_even_numbers();
}
Result (console)
0 2 4 6 8 10 12 14 16 18
0 2 4 6 8 10 12 14 16 18
0 2 4 6 8 10 12 14 16 18

With parameters

Scheme of a function with parameters

The behavior of the function can depend on parameters. If you want the function to display any number of even numbers, we can create a parameter in the function, that will control it. A parameter is a variable inside the function, which we create inside the parentheses

#include <iostream>

void print_even_numbers(int how_many)
{
for (int i = 0; i < how_many; i++)
std::cout << (i * 2) << ' ';
std::cout << '\n';
}

int main()
{
print_even_numbers(10);
print_even_numbers(5);
print_even_numbers(3);
}

The above notation

print_even_numbers(10);

means that when called, the how_many parameter inside this function will be assigned the value 10. We can pass any number of parameters to the function. Separate them by commas:

Print the bigger of two numbers
#include <iostream>

void print_bigger_number(int a, int b)
{
if (a > b)
std::cout << a << '\n';
else
std::cout << b << '\n';
}

int main() {
print_bigger_number(3, 5);
print_bigger_number(5, 3);
print_bigger_number(3, 10);
}
Common mistake

Notice that we place the function parameters after a comma, each time specifying its type. A common mistake among beginners is omitting the type in the following parameters.

void print_bigger_number(int a, b)

Return statement

We can tell the program to return from a function earlier, using a statement:

return;

Upon encountering it, the program stops executing further instructions in the function and returns to the place from which it was called. Let's recall the function we created earlier - print_even_numbers

void print_even_numbers(int how_many)
{
for (int i = 0; i < how_many; i++)
std::cout << (i * 2) << ' ';
std::cout << '\n';
}

What happens if we pass a negative number to how_many?

print_even_numbers(-10);

Executing a function with such a parameter value makes no sense, so we can detect this at the very beginning and use the return:

void print_even_numbers(int how_many)
{
if (how_many <= 0)
return;

for (int i = 0; i < how_many; i++)
std::cout << (i * 2) << ' ';
std::cout << '\n';
}

Now if we pass a value less than or equal to zero to a function parameter, the function will be terminated at the beginning.

Return value

Schema of a function with parameters and return value

Functions can produce a result after their execution. It will be easier to understand this if we use an analogy to real life. Father sends his child to the store to buy 10 eggs. When the child returns, he will want to know, whether the child managed to buy as many as he asked for or not. In the same way, we, performing some functions in code, we want to know the result, the return value.

Return value type

It is required to specify what type the return value is. We specify it before the function name, example:

We return an integer
int sum(int from, int to)
No return value is produced
void print(int number)

Notice that we have introduced a new type: void. If we write it in place of the return type, it means that the function does not return a value, i.e. we do not need to know its result. Note that we used void in the previous sections of this lesson for this very reason.

Void as a variable type

The void type cannot be used to create a variable:

❌ Illegal use
void variable;

A variable inherently stores a value, which would be impossible if it were of type void.

Usage

Let's implement the function from the diagram above. It is to count the sum of all numbers in the range from to to inclusive.

int sum(int from, int to)
{
int result = 0;
for (int i = from; i <= to; i++)
result += i;
return result;
}

We can use the returned value, for example, by writing it to a variable:

Saving the result to a variable
int s = sum(10, 100);

... or use in an expression (for example, as a function parameter):

Using a result
std::cout << "Sum of the numbers in range [10; 100] equals: " << sum(10, 100);

Requirements

Returning a value is mandatory

A function that returns some value (anything other than a `void' type), must at the very end of its execution return some value.

❌ Error: No value returned
int sum(int from, int to)
{
int result = 0;
for (int i = from; i <= to; i++)
result += i;
// ❌ No return statement!
}

An exception is the main function, which, despite returning an int type, performs an automatic return of a value 0 when return is omitted:

✔ Acceptable
int main() {
// No "return" statement
}

We will say more about the main function in the future.

Declaration and definition

In order to use the above sum function, we need to make sure that it is before this use, for example:

#include <iostream>

int main()
{
// Error: used before the definition
std::cout << "Sum of the numbers in range [10; 100] equals: " << sum(10, 100);
}

int sum(int from, int to)
{
int result = 0;
for (int i = from; i <= to; i++)
result += i;
return result;
}

Making sure that the order always matches is troublesome and sometimes even impossible. To fix the error in the above example, we have to use so called function declaration.

So far, when creating functions we used function definition which besides declaration, also contains its entire implementation (body). Declaring a function looks like defining it, without providing its body. We also need to take care to put a semicolon after the declaration.

🔵 Definition
int sum(int from, int to)
{
int result = 0;
for (int i = from; i <= to; i++)
result += i;
return result;
}
🟣 Declaration
int sum(int from, int to);

The rule is that in order to use a function, it must be declared beforehand. The definition must appear, but it does not matter if it is before or after the use. Here are two examples:

#include <iostream>

// 🟣 Declaration
int sum(int from, int to);

int main()
{
std::cout << "Sum of the numbers in range [10; 100] equals: " << sum(10, 100);
}

// 🔵 Definition
int sum(int from, int to)
{
int result = 0;
for (int i = from; i <= to; i++)
result += i;
return result;
}
The One Definition Rule (ODR)

The definition must appear in the code only once (there can be multiple declarations).

Summary

  • We use functions to group code into named blocks.
  • Functions can be called (invoked) to execute the code inside them.
  • Functions can return a value.
  • Functions can accept parameters.
  • Functions can be declared and defined separately.