Functions
int array[] = {1, 2, 3};
for (int i = 0; i < 3; i++)
{
array[i] += 2;
}
The example illustrates the last thing you learned in the previous lecture. Every single element in the array is increased by 2. Now imagine we had two arrays and we wanted to do the same process on both of them – increase each element by two. If the arrays had the same number of elements, this would be a piece cake:
int array[] = {1, 2, 3};
int second_array[] = {3, 4, 5};
for (int i = 0; i < 3; i++)
{
array[i] += 2;
second_array[i] += 2;
}
Now the problems begin if we add a third array whose elements also need to be increased by two, but the array has more than 3 elements. We can overcome this problem by adding a second loop:
int array[] = {1, 2, 3};
int second_array[] = {3, 4, 5};
int third_array[] = {5, 6, 7, 8};
for (int i = 0; i < 3; i++)
{
array[i] += 2;
second_array[i] += 2;
}
for (int i = 0; i < 4; i++)
{
third_array[i] += 2;
}
- The function’s signature or prototype (consists of the function’s name, return value and its parameters) – imagine it like the shape of the black box. We know what is the name of the function, what are the inputs and what is the output
- The function’s body or definition (consists of the function’s code block) – imagine it like the inside of the black box. This is where all of the logic of the function is stored (the same way a loop has a body)
<return_type> function_name(<param_type> arg1, <param_type> arg2, ...)//function's prototype
{
//function's definition
some_instructions;
return some_value; //value must be of the type <return_type>
}
//function_name is the name of the function
//<return_type> is the return value of the function (or the output)
/*"arg1" and "arg2" are the parameters of the function. A function may have as many parameters as
you like*/
//<param_type> can be any mentioned data type or user defined type (more about this later)
//"some_instructions;" is some code the function may have
/*"return some_value" tells us that the return (or output) of the function will be whatever is
stored in the variable "some_value"*/
int add(int a, int b)
{
int c = a + b;
return c; //c must be the same type as <return type>. int in this case
}
- the int keyword at the start means that the function will return an integer
- add is the name of the function
- in the brackets we say what should the user give to the function when he wants to call it (arguments of the function)
- in this example, there are two integer arguments named a and b
- The body of the function contains two instructions
- A new integer variable “c” is defined as the sum of the arguments
- return c is called, which means the function outputs the value of c and finishes
#include <iostream>
using namespace std;
int add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int x = 3;
int y = 4;
int sum = add(x,y); //calling function "add" and putting its return value into "sum"
int another_sum = add(1, 2); /* You can also supply the function with just the type values
instead of first storing them inside a variable*/
cout << "sum = " << sum << endl;
cout << "another_sum = " << another_sum << endl;
return 0;
}
Output:
sum = 7
another_sum = 3
- Go through each element
- Increment each element by some number
- The input should be some information about the array and the type of manipulation we want to do on each element:
- The actual array
- its size
- The incrementing value
- The output isn’t specified – void
void increment_elements(int array[], int number_of_elements, int increment)
{
for(int i = 0; i < number_of_elements; i++)
{
array[i] += increment;
}
}
Before going any further, we would like to address a subtly detail about functions. We mentioned that a function has a declaration and a definition. The question now is: Can they be separated? The answer is yes. Let’s say we wanted to rewrite the first example using a function, but still had no idea how to write the function’s body at the moment. Can we use the function in the main program and write the implementation for the function later? You guessed it! If a function needs to be used before it’s defined, the only thing that needs to be written before calling the function is the function’s prototype (declaration).
#include <iostream>
using namespace std;
void increment_element(int array[], int number_of_elements, int increment);
int main()
{
int array[] = {1, 2, 3};
int second_array[] = {3, 4, 5};
int third_array[] = {5, 6, 7, 8};
increment_elements(array, 3, 2);
increment_elements(second_array, 3, 2);
increment_elements(third_array, 4, 2);
return 0;
}
This can also be written in a more compact way! If a function before it’s use is just declared, you can remove the name of the parameters and just keep the data types of the parameters:
//just the prototype
void increment_element(int [], int, int);
- We want to rewrite our code so that instead of writing individual loops for our arrays, we want to call a function
- We will write just the function’s prototype (declaration) and use it in our main program where it’s needed
- Additionally, we will not use parameter’s names in the function’s prototype (declaration)
- After we are done with the main program we will define our function
#include <iostream>
using namespace std;
//function declaration
void increment_elements(int [], int, int);
int main()
{
int array[] = {1, 2, 3};
int second_array[] = {3, 4, 5};
int third_array[] = {5, 6, 7, 8};
increment_elements(array, 3, 2);
increment_elements(second_array, 3, 2);
increment_elements(third_array, 4, 2);
return 0;
}
//function definition
void increment_elements(int array[], int number_of_elements, int increment)
{
for(int i = 0; i < number_of_elements; i++)
{
array[i] += increment;
}
}
Every element of the arrays will be incremented with the given value of “increment”.
Parameters by value and by reference
#include <iostream>
using namespace std;
void increment(int a, int b)
{
a++;
b++;
}
int main()
{
int x = 3;
int y = 4;
increment(x,y);
cout << x << endl;
cout << y << endl;
return 0;
}
Output:
3
4
- Called the main function
- Defined variables x and y with their appropriate values
- Called the function “increment”
- Declared the variables a and b automatically and assigned them with the values from x and y
- Incremented the variables a and b
- Returned from the increment function
- Returned from the main function
#include <iostream>
using namespace std;
void increment(int *a, int *b)
{
(*a)++;
(*b)++;
}
int main()
{
int x = 3;
int y = 4;
increment(&x, &y);
cout << x << endl;
cout << y << endl;
return 0;
}
Output:
4
5
- The parameters are now references to integers
- We don’t need to increment the values pointed to by the arguments, but the arguments themselves
- We don’t need to call the function with the addresses of the variables, but the variables themselves
#include <iostream>
using namespace std;
void increment(int &a, int &b)
{
a++;
b++;
}
int main()
{
int x = 3;
int y = 4;
increment(x, y);
cout << x << endl;
cout << y << endl;
return 0;
}
This type of parameters are called parameters by reference, because the variables are parsed to the function by reference – not only is the value of the variables visible in the function’s body, but also the variables themselves. Any change you make to the arguments in the function are automatically transferred to the variables supplied.
Table of contents
- Classes and Objects
- Operator Overloading
- Class Inheritance
- Exceptions
- Namespaces
- Templates
- Standard Library
- Additional Problems