Functions in C++
Functions consist of instructions that take inputs, perform specific calculations, and produce outputs.
Instead of writing the same code over and over for different inputs, certain commonly performed or repeated tasks can be grouped and called via a function.
Function declarations provide information about the name, return type, and parameters of a function. Function definitions provide information about the actual function body.
Syntax
return_type function_name( parameter list ) { // function body }
Function definitions in C++ have two parts: a header and a body.
- The return_type of a function indicates the type of value that the function returned. Some functions perform operations without returning a value, in which case the return_type would be the keyword void.
- The function name and the parameter list together form the signature of the function.
- Parameters: Parameters are similar to placeholders. When a function is invoked, a value is passed to the parameter. This value is referred to as an actual parameter or argument. In a function, a list of parameters determines the type, order, and number of parameters. Parameters are optional, meaning that a function may not have any parameters.
- A function body is composed of instructions that describe what the function does.
Declaration of a function
int max(int, int);
The names of the parameters are not important in the declaration of the function, only their types are.
Definition of a function
int max(int x, int y) { if (x > y) return x; else return y; }
Call a function
Calling a function is as simple as passing the parameters along with the name of the function. If the function returns a value, you can store it in the variable.
int main() { int a = 4, b = 7; int c = max(a, b); cout << "max(a, b)" << c << endl; return 0; }
Passing parameters
Parameters passed to a function are referred to as actual parameters. For example, in the program above, the parameters a and b (4 and 7) are actual parameters.
Formal parameters are those that the function receives as input. For example, in the above program, x and y are formal parameters.
In calling a function, you can pass arguments in three different ways:
- Pass by Value
- Pass by Address
- Pass by Reference
Pass by Value
This method involves copying the values of the actual parameters into the formal parameters of a function, and storing both types of parameters in different locations in memory. In this manner, any modifications made to the parameters within the function will not affect the caller's actual parameters.
The default method of passing arguments in C++ is pass by value, which means that the code within a function cannot modify the arguments that are passed to the function when it is called.
Example
#include <iostream> using namespace std; void swap(int x, int y); int main() { int a = 4, b = 7; swap(a, b); cout << "a = " << a << " - b = " << b << endl; return 0; } void swap(int x, int y) { int c = x; x = y; y = c; }
Output
a = 4 - b = 7
In fact, as you can see in the example above, the values of a and b do not change following the swap operation. During pass by value, the function receives copies of the actual parameters, so any modification made to the formal parameters inside the function does not affect the original variables in the calling code.
Pass by Address
When a parameter is passed by address (or pointer), the address of the argument is copied into its formal parameter. In the function, the address is used to access the actual argument. This means that modifications to the parameter affect the argument passed.
We pass a value by address by declaring the parameters as pointers and calling the function with the addresses of the arguments.
Example
#include <iostream> using namespace std; void swap(int *x, int *y); int main() { int a = 4, b = 7; swap(&a, &b); cout << "a = " << a << " - b = " << b << endl; return 0; } void swap(int *x, int *y) { int c = *x; *x = *y; *y = c; }
Output
a = 7 - b = 4
Pass by Reference
In passing by reference, the reference of an argument is copied into the formal parameter within the function. Within the function, the reference is used to access the actual argument used in the call, so any modifications to the parameter will affect the passed argument.
When passing an argument by reference, the argument's reference can be passed to functions as any other value would be. As a result, you need to declare the function parameters as references, as in the following function swap(), which swaps the values of the two integer variables referred to by its arguments.
Example
#include <iostream> using namespace std; void swap(int &x, int &y); int main() { int a = 4, b = 7; swap(a, b); cout << "a = " << a << " - b = " << b << endl; return 0; } void swap(int &x, int &y) { int c = x; x = y; y = c; }
Output
a = 7 - b = 4
Passage by address VS Passage by reference
It is possible to pass parameters to a C++ function either by address (using pointers) or by reference. Both approaches yield the same result, so the inevitable question arises: when should one be preferred over the other? What are the reasons for choosing one over the other?
In general, references are implemented using pointers. A reference refers to the same object, but with a different name.
The following considerations should be taken into account:
- In contrast, a pointer can be reassigned, whereas a reference cannot and must only be assigned at the time of initialization.
- In contrast to a reference, a pointer can be directly assigned to NULL.
- A pointer can traverse an array; we can use ++ to move to the next element pointed to by a pointer.
- A pointer is a variable containing a memory address. A reference has the same memory address as the element it refers to.
- To access the members of a class/structure, a pointer uses "->", whereas a reference uses ".".
- A pointer must be dereferenced with * to access the pointed-to memory location, whereas a reference can be directly accessed.
- There is generally a preference for references over pointers when reseating is not required.
To summarize, use references whenever possible, and pointers whenever necessary.