Chapter 6
Chapter 6
Functions
6. What is a function?
A function provides a convenient way of packaging a computational recipe, so that it can
be used as often as required.
Therefore, a function is a block of code designed to tackle a specific problem.
6.1. Function Basics
One of the best ways to tackle a problem is to start with the overall goal, then divide this
goal into several smaller tasks. You should never lose sight of the overall goal, but think
also of how individual pieces can fit together to accomplish such a goal.
If your program does a lot, break it into several functions. Each function should do only
one primary task.
6.2. Summarized function basics.
C++ functions generally adhere to the following rules.
2. Function names are made up and assigned by the programmer following the
same rules that apply to naming variables. They can contain up to 32 characters,
they must begin with a letter, and they can consist of letters, numbers, and the
underscore (_) character.
3. All function names have one set of parenthesis immediately following them.
This helps you (and C++ compiler) differentiate them from variables.
The interface of a function (also called its prototype) specifies how it may be used. It consists of
three entities:
The function return type. This specifies the type of value the function returns. A function
which returns nothing should have a return type void.
The function name. this is simply a unique identifier
The function parameters (also called its signature). This is a set of zero or more typed
identifiers used for passing values to and from the function.
6.3.2. Defining a function:
A function definition consists of two parts: interface (prototype) & body. The brace of a
function contains the computational steps (statements) that computerize the function.
The definition consists of a line called the decelerator.
If function definition is done before the main function, then there is no need to put the
prototype, otherwise the prototype should be scripted before the main function starts.
6.3.3. Calling the function:
Using a function involves ‘calling’ it.
Calling a function means making the instruction of the function to be executed.
A function call consists of the function name followed by the call operator brackets ‘()’,
inside which zero or more comma-separated arguments appear. The number and type of
arguments should match the number of function parameters. Each argument is an
expression whose type should match the type of the corresponding parameter in the
function interface.
When a function call is executed, the arguments are first evaluated and their resulting
values are assigned to the corresponding parameters. The function body is then
executed. Finally the return value (if any) is passed to the caller.
A function call in C++ is like a detour on a highway. Imagine that you are traveling along the
“road” of the primary function called main(). When you run into a function-calling statement,
you must temporarily leave the main() function and execute the function that was called. After
that function finishes (its return statement is reached), program control returns to main(). In
other words, when you finish a detour, you return to the “main” route and continue the trip.
Control continues as main() calls other functions.
Given the next program, which function is the calling function and which is the called function?
#include<iostream.h>
#include<conio.h>
void nextMsg()
int main()
{
cout<< “Hello!\n”;
nextMsg();
return 0;
}
void nextMsg()
{
cout<< “GoodBye!\n”;
return;
}
6.4. Function Parameters and arguments
The parameters of a function are list of variables used by the function to perform its task
and the arguments passed to the function during calling of a function are values sent to
the function.
The arguments of function calling can be using either of the two supported styles in C++:
passing by value or passing by reference.
6.4.1. Passing by value:
A value parameter receives a copy of only the value of the argument passed to it. As a
result, if the function makes any changes to the parameters, this will not affect the
argument. For instance:
#.....
void Foo(int num)
{
Num = 0;
cout<< “num = ” << num << “ \n”;
}
int main(void)
{
int x = 10;
Foo(x);
cout<< “x = ”<<x<< “\n”;
getch();
return 0;
}
The single parameter of Foo is a value parameter. As far as this function is concerned,
num behaves just like a local variable inside the function. When the function is called and
x passed to it, num receives a copy of the value of x. As a result, although num is set to 0
by the function, this does not affect x. the program produces the following output:
Num = 0
x = 10
Passing arguments in this way, where the function creates copies of the arguments
passed to it is called passing by value.
6.4.2. Passing by Reference:
A reference parameter, on the other hand, receives the argument passed to it and works
on it directly. Any change made by the function to a reference parameter is in effect
directly applied to the argument.
Passing parameters in this way is called pass-by-reference.
Taking the same example above:
#.....
#.....
void Foo(int & num)
{
num = 0;
cout<< “num = ” << num << “ \n”;
}
int main(void)
{
int x = 10;
Foo(x);
cout<< “x = ”<<x<< “\n”;
getch();
return 0;
}
The parameter of Foo is a reference parameter. Num will correspond to x for this specific
program as it x is sent by its reference and not its value. Any change made on num will be
effected to x. Thus, the program produces the following output:
num = 0
x=0
Suppose you have pairs of numbers in your program and you want to be sure that the
smaller one always precedes the larger one. To do this, you call a function, order(), which
checks two numbers passed to it by reference and swaps the originals if the first is larger
than the second.
#.......
#.......
void order(int &, int &);
int main()
{
int n1 = 99, n2=11;
int n3 = 22, n4=88;
order(n1,n2);
order(n3,n4);
cout<< “n1=”<<n1<<endl;
cout<< “n2=”<<n2<<endl;
cout<< “n3=”<<n3<<endl;
cout<< “n4=”<<n4<<endl;
return 0;
}
void order(int & num1,int & num2)
{
if(num1 > num2)
{
int temp=num1;
num1 = num2;
num2 = temp;
}
}
In main() there are two pairs of numbers-the first pair is not ordered and the second pair
is ordered. The order() function is called once for each pair, and then all the numbers are
printed out. The output revels that the first pair has been swapped while the second pair
has not. Here it is:
N1 = 11
N2 = 99
N3 = 22
N4 = 88
In the order() function the first variable is called num1 and the second is num2. If num1 is
greater than num2, the function stores num1 in temp, puts num2 in num1, and finally
puts temp back in num2.
Using reference arguments in this way is a sort of remote control operation. The calling
program tells the function what variables in the calling program to operate on, and the
function modifies these variables without ever knowing their real names.
6.5. Global versus local variables
Everything defined at the program scope level (outside functions) is said to have a global
scope, meaning that the entire program knows each variable and has the capability to
change any of them.
Eg.
� Each block in a program defines a local scope. Thus the body of a function represents a local
scope. The parameters of a function have the same scope as the function body.
� Variables defined within a local scope are visible to that scope only. Hence, a variable need
only be unique within its own scope. Local scopes may be nested, in which case the inner scope
overrides the outer scopes. Eg:
int num1;
void fun1(int num1)
{
//…
}
The global num1 is inaccessible inside fun1(), because it is overridden by the local num1
parameter.
This problem is overcome using the scope operator ‘::’ which takes a global entity as
argument.
int num1 = 2;
void fun1(int num1)
{
//…
num1=33;
cout<<num1; // the out put will be 33
cout<<::num1; //the out put will be 2 which is the global
if(::num1 != 0)//refers to global num1
//…
}
6.7. Automatic versus static variables
The terms automatic and static describe what happens to local variables when a function
returns to the calling procedure. By default, all local variables are automatic, meaning
that they are erased when their function ends. You can designate a variable as automatic
by prefixing its definition with the term auto.
Eg. The two statements after main()’s opening brace declared automatic local variables:
main()
{
int i;
auto float x;
…
}
The opposite of an automatic is a static variable. All global variables are static and, as
mentioned, all static variables retain their values. Therefore, if a local variable is static, it
too retains its value when its function ends-in case this function is called a second time.
To declare a variable as static, place the static keyword in front of the variable when you
define it. The following code section defines three variables i, j, k. the variable i is
automatic, but j and k are static.
Static variables can be declared and initialized within the function, but the initialization
will be executed only once during the first call.
If static variables are not declared explicitly, they will be declared to 0 automatically.
(n > 0 ? n : -n)
However, instead of replicating this expression in many places in the program, it is better
to define it as a function:
int Abs(int n)
{
return n > 0 ? n : -n;
}
The function version has a number of advantages.
It leads to a more readable program.
It is reusable.
The disadvantage of the function version, however is that
Its frequent use can lead to considerable performance penalty due to
overheads associated with calling a function.
The overhead can be avoided by defining Abs as an inline function.
Therefore, to request that pr_msg() display the line ‘Turn printer on’, you call it this way:
As you write more of the program, you begin to realize that you are displaying one
message-for instance, the ‘Turn printer on’ msg-more often than any other message.
Instead of calling the function over and over, typing the same message each time, you
can set up the prototype for pr_msg() so that it defaults to the ‘turn printer on’ message
in this way:
#include…..
void Add_Display(int x=10, int y=20, int z=30)
{
cout<< (x+y+z);
}
void Mult_Dispaly (int x, int y=70)
{
cout<< (x*y);
}
void main()
{
int a=40, b=50, c=60;
Add_Display(a,b,c); //will print 150 (ie 40+50+60)
Add_Display(a,b); //will print 120 (ie 40+50+30)
Add_Display(a); //will print 90 (ie 40+20+30)
Add_Display(); //will print 60 (ie 10+20+30)
Mult_Display(a,b) //will print 2000 (40*50)
Mult_Display(a) //will print 2800 (40*70)
//Mult_Display() //is invalid as there is no default for x
getch();
}
//the following function definition is invalid as z is
//a parameter without a default and written after y
//parameters with default should always be at the
//right side of function declaration
void Mult_Dispaly (int x, int y=70, int z)
{
cout<< (x*y*z);
}
//thus the following function definition will be correct
void Mult_Dispaly (int x, int z, int y=70)
{
cout<< (x*y*z);
}
6.9.2. Overloaded Functions
Unlike C, C++ lets you have more than one function with the same name. In other words,
you can have three functions called abs() in the same program.
Functions with the same name are called overloaded functions. C++ requires that each
overloaded functions differ in its argument list. Overloaded functions enable you to have
similar functions that work on different types of data.
Suppose that you wrote a function that returned the absolute value of what ever number
you passed to it:
int iabs(int i)
{ if(i<0)
Return (i*-1);
else
Return (i);
}
float fabs(float x)
{ if(x<0.0)
Return (x * -1.0);
else
Return (x);
}
Without using overloading, you have to call the function as:
- factorial of 0 is 1
- factorial of a positive number n is n time the factorial of n-1.
The second line clearly indicates that factorial is defined in terms of itself and hence can
be expressed as a recursive function.
The stack frames for these calls appear sequentially on the runtime stack, one after the
other.
A recursive function must have at least one termination condition which can be satisfied.
Otherwise, the function will call itself indefinitely until the runtime stack overflows.
The three necessary components in a recursive method are:
int sum(int N)
{
if(N==1)
return 1;
else
return N+sum(N);
}
The last method computes the exponentiation An where A is a real number and N is a
positive integer. This time, we have to pass two arguments. A and N. the value of A will
not change in the calls, but the value of N is decremented after each recursive call.
0,1,1,2,3,5,8,13,21,…
Fibonacci (0) =0
Fibonacci (1) =1
Fibonacci (n) =Fibonacci (n-1) +Fibonacci (n-2);