C++ Tutorial for noobs - Part 5: Functions
Motivation
Let's say we want have an algorithm that increase a variable by one, and then multiplies it with two, then divides it by three, then subtracts four from it.
We want to do try this algorithms for the numbers 42, 43, 44, 45, 46 and 47.
Since we already know C++ Variables, we could do it pretty easily like this:
int a = 42;
a = a + 1;
a = a * 2;
a = a / 3;
a = a - 4;
int b = 43;
b = b + 1;
b = b * 2;
b = b / 3;
b = b - 4;
int c = 44;
c = c + 1;
c = c * 2;
c = c / 3;
c = c - 4;
int d = 45;
d = d + 1;
d = d * 2;
d = d / 3;
d = d - 4;
int e = 46;
e = e + 1;
e = e * 2;
e = e / 3;
e = e - 4;
int f = 47;
f = f + 1;
f = f * 2;
f = f / 3;
f = f - 4;
Reminder: to see what value a variable has, we can use std::cout<<a; any time.
Now that's a lot of work for doing the same thing over and over again...
We could make our life much easier if we would put the algorithm into a function:
int my_algorithm(int n)
{
n = n + 1;
n = n * 2;
n = n / 3;
n = n - 4;
return n;
}
a = my_algorithm(42);
b = my_algorithm(43);
c = my_algorithm(44);
d = my_algorithm(45);
e = my_algorithm(46);
f = my_algorithm(47);
Here is what happens:
- We create a function with the name 'my_algorithm' that takes any kind of int variable, we called it n
- Then it does our weird computation
- Then it returns the result
- Afterwards we 'call' our function to calculate the results for 42, 43, 44, 45, 46 and 47
- Hence n becomes 42
- Our function does our weird computation with it
- The result is returned
- The function call's result is stored in the variable a
- Then the same thing happens with the 43, 44, 45, 46 and 47
Theory
Each C++ function hs the same structure:
.
------------------------ function type (like int)
|
| ----------------- function name (like Abc_123)
| |
| | -------- the parameters (many or none)
| | |
int increase(int n)
{ -|
return n + 1; |--- function body ( {...} )
} -|
There are a few things to know about functions:
- They always have some kind of name
- Which can be followed by several parameter variables (here n)
- The stuff inside the function is surrounded by { and }
- We can use return to make the function give something back, so we can store the function's result in a variable later
Examples
Here are a few examples of all kinds of different functions:
// a function that adds two numbers
int add(int n, int m)
{
return n + m;
}
// usage:
int a = 1;
int b = 2;
int c = add(a, b); // c is 3
int x = add(1, 2); // x is 3
// a function that just returns 24
int twentyfour()
{
return 1 * 2 * 3 * 4;
}
// usage:
int a = twentyfour(); // a is 24
twentyfour(); // calculates 24 but doesn't store it
// a function that simply increases a number
int increase(int n)
{
return n + 1;
}
// usage:
a = increase(0); // a is 1
b = increase(increase(0)); // b is 2
About Scope
Let's take a look at our increase function again:
int increase(int n)
{
return n + 1;
}
There is one more thing to know about this: the variable n only exists within the function, or in other words, we can only use n between { and }.
So this does not work:
int a = increase(0);
int b = a + n; // n is only known inside of increase
Call-by-reference & Call-by-value
Foreword
Please don't get scared by the explanation of the two concepts, in the end they are kinda optional, but it's good to have read about them once.
Generally speaking, there are two types of functions:
- Functions that take something, then return something new
- Functions that take something, and then modify it
Call-by-Value
For example, our increase function above takes something and then returns whatever it took, increased by one:
int increase(int n)
{
return n + 1;
}
The important part is how we use it:
int a = 0;
int b = increase(a);
In the above example, a is passed as a parameter into the increase function, but it is never modified. In the end, a is 0 and b is 1.
What happens behind the scenes is this:
- a is set to 0
- increase is called, a is copied into the parameter n
- n is being increased by one
- the result is returned
- the result is stored in b
Here is the way that our a travels:
As we can see, a never goes inside of increase, instead it's copied into n.
Call-by-value is just that. It means that when calling a function, the parameters become copies of whatever we passed into it.
Call-by-Reference
The counter-part is this:
void increase(int &n)
{
n = n + 1;
}
Again, the important part is how we use it:
int a = 0;
increase(a);
In the above example, a is passed as a parameter into the increase function directly, without a being copied. We did this by naming our variable &n instead of n. & means it's not copied.
Here is what happens behind the scenes:
- a is set to 0
- increase is called, n is now a (we just give it a different name for a while)
- n (which is a) is increased by one
- the function ends without returning anything (hence the none-type void)
- since a was increased by one, a is now 1
Here is the way that our a travels:
As we can see, a goes all the way through increase, and even though we named it n for a while, we still work with a. All this happens simply because we put a & sign in front of our parameter.
Summary
The whole call-by-value and call-by-reference thing can be confusing.
Here is a final overview:
- Call by value
- it's the default where parameters are always copies
- it leads to clean and easily understandable code
- Call by reference
- it's the & thing
- it's really good for high-performance stuff
- it can lead to really complicated code
If you love simplicity then stick with call-by-value until you fully understand C++.
Good news: now that we know Data-Types, Variables and Functions, we have a solid knowledge of the C++ fundamentals and we can already write some simple programs!