Functions

Location
  1. Courses

    /

  2. Complete C++ Course

    /

  3. The basics

    /

  4. Functions

What is a function?

In C/C++, a function is a named group of instructions that can take parameters and return a value. A function can be called so the instructions inside it are executed.

Defining a function

To define a function, we write the type of value it returns (void if it returns nothing), then its name followed by the parameters it takes (If it takes parameters) inside parentheses. Finally, the instructions of the function are written inside braces. Here we define (create) a simple function named func:

1
2
3
4
5
6
#include <iostream> void func() { std::cout << "Hello" << std::endl; }

Now, we can call the function and the instructions inside it will be executed where the function is called:

1
2
3
4
5
6
int main() { func(); // "Hello" is written in the console. return 0; }

Functions returning a value

A function can return a value. To do so, we need to specify what type of value it will return. The void in the function we defined earlier meant that the function returns nothing. Let us define a function that returns a variable of type int:

1
2
3
4
5
6
#include <iostream> int func2() { return 5; }

The keyword return has the effect of ending the execution of the function and returning the value following it.

We can retrieve the value returned like that:

1
2
3
4
5
6
7
8
9
10
int main() { int var; var = func2(); // The variable var is assigned with the value 5. std::cout << var << std::endl; return 0; }

Functions with parameters

A function can take parameters (Also called “arguments”). When a function that requires arguments is called, it copies the values it is given as parameters and execute its instructions using those copies. We define arguments inside a function by writing the type of the argument followed by its the name, for each parameter, inside the parentheses following the function name. If there are many arguments, they are separated by commas. Here is a function that takes two values of type int as arguments:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream> void func3(int arg1, int arg2) { std::cout << arg1 << " " << arg2 << std::endl; } int main() { int num = 5; func3(num, 9); // Prints "5 9" into the console. return 0; }

References as arguments

By default, when you call a function with an argument, the function will create a new variable and assign the value given as argument to it. So in the following example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream> void func(int arg) { arg = 5; } int main() { int var = 8; std::cout << var << std::endl; func(var); std::cout << var << std::endl; return 0; }

The variable var still equal 8, not 5. The reason is that arg is only a copy of var. So the function func has actually no effect.

We define an argument as a reference by putting, in its definition, an ampersand & before its name. If we define the argument arg as a reference, like that:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream> void func(int &arg) { arg = 5; } int main() { int var = 8; std::cout << var << std::endl; func(var); std::cout << var << std::endl; return 0; }

Then, after func is called, var equals 5. The effect of the ampersand & between the argument type (int) and the variable name (arg) is to define it as what is called a reference. A reference, instead of being a copy of the variable that is given as argument, act as if it was the actual variable. A reference is simply used to refer to the variable given as argument.

Unlike normal arguments, references can logically not receive values as parameters, they must receive variables. So if the above definition of func is used, the following would cause a compilation error:

func(4);

Pointers as arguments

Pointer arguments are similar to references. The real difference is in the syntax. Here is an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream> void func(int * ptr) { *ptr = 5; } int main() { int var1, var2; int *ptr = &var1; func(ptr); func(&var2); std::cout << var1 << std::endl; std::cout << var2 << std::endl; return 0; }

At the end of the example above, both var1 and var2 equal 5. If the function takes a pointer as argument, we can directly give it the address of the variable, because, after all, a pointer is an address.

Unlike non-constant references, constant references can receive values as argument:

Note that references are a feature a C++. They therefore do not exist in C. The only advantage of using references over pointer arguments is that they are more convenient to use because we do not have to use asterisks to access the variable and that we can directly give the variables as arguments instead of their address.

Functions returning references

Usually, when a function returns a variable, it does not return the actual variable, but rather a copy of the variable. The same way functions can take references as arguments, they can return a reference. It is done by adding, in the function definition, an ampersand & after the name of the return type.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream> // Adds 5 to the variable given in argument and returns a reference to it. int& plus5(int& v) { v += 5; return v; } int main() { int v = 5; plus5(v); std::cout << v << std::endl; // Prints "10" to the console. // Assigns 0 to the reference to the variable, returned. plus5(v) = 0; std::cout << v << std::endl; // Prints "0" to the console. return 0; }

A function that returns a reference must return a variable, it can not return a value.

The following definition would cause an error:

int& func() { return 10; // Error: A reference to a value is not possible. }

Also, we must not return references to variables that have been defined in the function, nor arguments that are not references or pointers. Doing so may not cause a compilation error, but rather a warning. However, that is likely to make the program either crash or behave unsuspectingly. The reason is that after the execution of the function is finished, those variables reach the end of their life scope and are therefore removed, so if we return a reference to one of them, a reference to a variable that do no exist anymore is returned.

Here is two function definitions returning faulty references:

1
2
3
4
5
6
7
8
9
10
int& func() { int var = 5; return var; // Error: The variable exists only within the function. } int& func2(int arg) { return arg; // Error: The copy of the argument (Not a reference) only exists in the function. }

Functions returning references

Functions may also return pointers. Its is done by adding, in the function definition, an asterisk * after the name of the return type.

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
#include <iostream> // Returns the address (pointer) of the reference given in argument. int* pointerOf(int& v) { return &v; } int main() { int v = 0; // Retrieves the pointer (address) returned. int *ptr = pointerOf(v); // Assigns the value 5 to variable pointed by ptr (v). *ptr = 5; // Prints the value of 'v' (5) to the console. std::cout << v << std::endl; // Assigns the value 67 to variable at the address returned by the function. *pointerOf(v) = 67; // Prints the value of 'v' (67) to the console. std::cout << v << std::endl; return 0; }

Like with references, returned pointers must point to variables that are not local to the function.

Here is two function definitions returning faulty pointers:

1
2
3
4
5
6
7
8
9
10
int* func() { int var = 5; return &var; // Error: The variable exists only within the function. } int* func2(int arg) { return &arg; // Error: The copy of the argument (Not a reference) only exists in the function. }

Giving the result of function calls or operations as arguments

It is possible to execute an operation or call a function inside a function call to give the returned value as argument. When we call functions or execute operations inside a function call, we must not end those with semicolons ;.

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
#include <iostream> int mult(int a, int b) { return a * b; } int add(int a, int b) { return a + b; } int main() { // Prints 63 to the console. std::cout << mult(7, 9) << std::endl; /* Prints 100 into the console. The steps: 1. The function call add(2, 8) is executed and returns 10. 2. The operation 9+1 is executed and returns 10. 3. The function call mult(10, 10) is executed and returns 100. 4. std::cout receives the number 100 as right operand. 5. std::cout receives std::endl as right operand. */ std::cout << mult(add(2, 8), 9+1) << std::endl; return 0; }

Function header

The code above the parentheses of a function definition is called the header of a function and the parentheses and what is inside is called the body of the function.

Look at the following function definition:

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

The function header is:

int add(int a, int b)

And the function body is:

{ return a+b; }

Naming convention

In this course, functions are named in camelCase.

The main function

The main function is, in a way, the program. When the program starts, the operating system prepares the environment for the program to run (Example: load its code into the memory) and then it calls the main function:

int errorCode = main();

Once that function ends, the operating system retrieves the value returned (And may react to it) and then the program closes.