Functions in C++
Introduction
While writing large programs, main() function will become quite complex to maintain and soon you will lose track of what is happening. This is where functions will aid programmers.
Functions allows the programmer to divide a large program into logical chunks. Each function is a self contained block that does a non-trivial task.
The main() function will call other functions which in turn solves the problem. This model of programming using functions is known as modular programming or structured programming.
Consider the following program which calculates the area and perimeter of a circle using functions:
#include<iostream> double area(double); double peri(double); const double PI = 3.1415; using namespace std; int main() { double radius; cout<<"Enter radius of cricle: "; cin>>radius; cout<<"Area of the circle is: "<<area(radius)<<endl; cout<<"Perimeter of the circle is: "<<peri(radius)<<endl; return 0; } double area(double r) { return PI*r*r; } double peri(double r) { return 2*PI*r; } Input and output of the above program is as follows: Enter radius of cricle: 5 Area of the circle is: 78.5375 Perimeter of the circle is: 31.415
In the above program, following two lines are known as function prototypes:
double area(double);
double peri(double);
A function prototype tells the compiler that there is a function with the specified name, with the specified type and parameters.
Following two lines are function calls to respective functions:
area(radius)
peri(radius)
Following two code segments are called function definitions of respective functions:
//Function definition of function area double area(double r) { return PI*r*r; } //Function definition of function peri double peri(double r) { return 2*PI*r; }
Function Prototype
A function prototype tells the compiler what is the function name, how many parameters a function accepts and the types of those parameters and the type of value that a function returns to its caller. General syntax of function prototype (declaration) is as follows:
return-type function-name(type, type, …, type);
In the above syntax, parameters are optional. When the function does not return any value, the return type must be specified as void.
Function Definition
The body or implementation of a function is known as function definition. A function definition always consists of a block made up of braces. General syntax of a function definition is as follows:
return-type function-name(type var1, type var2, ..., type varN) { //Statements to execute ... ... [return value / expression;] }
If the return type of the function is void, there is no need to write the return statement. Remember that a function can return only one value using the return statement.
Function Call
Invoking or calling a function is known as a function call. General syntax of a function call is as follows:
function-name(arg1, arg2, …, argN);
A function call starts the execution of corresponding function definition. The arguments in the function call are known as actual parameters and the parameters in the function definition are known as formal parameters.
Function parameters (in general) are like local variables. Their scope is within the function block. Each time a function executes, memory is allocated for parameters and when execution goes back to the caller, memory is deallocated and they are no longer accessible.
Function Parameters with Default Values
The parameters in a function declaration can be assigned a default value as shown below:
double area(double radius, double Pi = 3.14);
We can declare multiple parameters with default values. But, all suck kind of parameters must be at the last of the parameters list. We can assign our custom value for the parameter as shown below:
area(2.5, 3.1415);
For the above function call, Pi value will be taken as 3.1415 instead of the default value 3.14.
Following program demonstrates parameters with default values:
#include<iostream> double area(double radius, double Pi = 3.14); using namespace std; int main() { double radius; cout<<"Enter radius of cricle: "; cin>>radius; cout<<"Area of the circle is: "<<area(radius)<<endl; cout<<"Area of the circle is: "<<area(radius, 3.1415)<<endl; return 0; } double area(double r, double Pi) { return Pi*r*r; } Input and output for the above program is as follows: Enter radius of cricle: 2.5 Area of the circle is: 19.625 Area of the circle is: 19.6344
Recursion
A function invoking itself is known as recursion. Recursion is an alternative to iteration. Recursion is very close to mathematical way of solving a given problem.
Advantages of recursion are, it is straight forward and easy. Disadvantage of recursion is, it occupies more memory on the stack when compared to iteration.
Note: Remember to write an exit condition while using recursion. If there is no exit condition, then the function will call itself infinitely.
Consider the following program which calculates the factorial of a number using recursion:
#include<iostream> using namespace std; int fact(int n) { if(n==0 || n==1) return 1; else return n*fact(n-1); } int main() { int num; cout<<"Enter a number: "; cin>>num; cout<<"Factorial of "<<num<<" is: "<<fact(num)<<endl; return 0; } Input and output for the above program is as follows: Enter a number: 5 Factorial of 5 is: 120
In the above program the exit condition is if(n==0 || n==1) return 1;
The recursive call is fact(n-1).
Note: In the above program there is no function declaration (prototype) for the function fact(). If the function definition is written before main(), there is no need of writing function declaration.
Passing an Array as a Parameter
Like we are able to pass variables, we can also pass arrays as arguments to a function. A function prototype which accepts an array and its size as parameters is as follows:
void PrintArray(int nums[ ], int size);
Consider the following program which contains a function that takes an array and its size as arguments and calculates the largest element in the array:
#include<iostream> using namespace std; int largest(int nums[], int size) { int max = nums[0]; for(int i=1; i<size; i++) { if(max<nums[i]) { max = nums[i]; } } return max; } int main() { int nums[5] = {1,2,5,3,4}; cout<<"Largest element in the array is: "<<largest(nums, 5)<<endl; return 0; } Output of the above program is as follows: Largest element in the array is: 5
Note that in the above program there is no need to write square brackets in the function call largest(nums, 5).
Parameter Passing Techniques
In C++ we have three ways for passing arguments to a function. They are: pass-by-value, pass-by-reference, and pass-by-address.
Pass-by-value
Generally used way to pass arguments is pass-by-value. In this method, the arguments passed in the function call are copied to formal parameters in the function definition.
So, any changes made to the formal parameters are not reflected on the actual parameters. Consider the following swap function which demonstrates pass-by-value:
void swap(int x, int y) { int temp = x; x = y; y = temp; }
Let’s assume that in the main() function we are writing the following code:
int a = 10, b = 20;
swap(a, b);
Although the values of x and y are being interchanged, since they are copies of a and b, the values of a and b remains the same i.e., 10 and 20 respectively.
Pass-by-reference
To make the changes on formal parameters reflect on actual parameters, we can use pass-by-reference. In pass-by-reference method we pass reference to argument instead of a copy. So, both actual and formal parameters refer to the same memory location. Using this method, our swap function will be as follows:
void swap(int &x, int &y) { int temp = x; x = y; y = temp; }
Remember to precede the formal parameters with &.
Pass-by-address
In pass-by-address, we pass address of the argument to formal parameters. Both pass-by-reference and pass-by-address are semantically same. The only difference is, in pass-by-reference, the formal parameters are guaranteed to alias valid memory locations. Whereas in pass-by-address, the formal parameters are pointers and can even point to null.
Our swap function using pass-by-address will look as follows:
void swap(int *x, int *y) { int temp = *x; *x = *y; *y = temp; }
and the code for calling our swap function will be as follows:
int a=10, b=20;
swap(&a, &b);
The complete program which demonstrates all the three methods to pass arguments is as follows:
#include<iostream> using namespace std; int swapval(int x, int y) { int temp = x; x = y; y = temp; } int swapref(int &x, int &y) { int temp = x; x = y; y = temp; } int swapadd(int *x, int *y) { int temp = *x; *x = *y; *y = temp; } int main() { int a=10, b=20; swapval(a,b); cout<<"After swap (call by value): a="<<a<<",b="<<b<<endl; swapref(a,b); cout<<"After swap (call by reference): a="<<a<<",b="<<b<<endl; swapadd(&a,&b); cout<<"After swap (call by address): a="<<a<<",b="<<b<<endl; return 0; } Output for the above program is as follows: After swap (call by value): a=10,b=20 After swap (call by reference): a=20,b=10 After swap (call by address): a=10,b=20
Inline Functions
A normal function call would involve stack operations and processor to shift to the first instruction in the function definition which might take significant time. For small functions with one or two lines this time is unnecessary. Such functions can be declared as inline functions using the keyword inline.
In general, inline functions are faster than normal functions. When the compiler comes across a call to a inline function, it directly substitutes the function definition in the place of function which might increase the size of code.
So, the use of inline keyword in programs should be minimal. Consider the following inline function that demonstrates the use of inline keyword:
inline int square(int x) { return x*x; }
Rules for declaring a function as inline are as follows:
- Function should not use recursion.
- Function should not use static variables.
- Function should not return a value.
- Function should not contain any go to, switch, or iterative statements.
Function Overloading
Two or more functions with the same name but different set of parameters or different number of parameters are said to be overloaded and this concept is known as function overloading.
It is common to create functions which does the same thing but on different parameters. For example, we might have to create functions to add integers as well as floating-point numbers. In C, to do this, we have to create two functions with different names. But in C++ we can use the same function name to create multiple functions.
Consider the following program which demonstrates the use of function overloading:
#include<iostream> using namespace std; int sum(int x, int y) { return x+y; } double sum(double x, double y) { return x+y; } int main() { cout<<"Sum of 3 and 5 is: "<<sum(3,5)<<endl; cout<<"Sum of 2.55 and 6.5 is: "<<sum(2.55,6.5)<<endl; return 0; } Output of the above program is as follows: Sum of 3 and 5 is: 8 Sum of 2.55 and 6.5 is: 9.05
No comments