Functions are building blocks of a C
Functions are building blocks of a C
Each function is developed separately and tested. Basically there are two types of
functions.
1. Built–in functions
2. User–defined functions
Built–in functions are those functions, which are provided by the C++ language and
are coded into machine language.
User–defined functions are those functions, which are written by the programmer for
its sake of convenience. It is the programmer who names each such function and
specifies the method of sending the data and getting the results from them.
Simple Functions
A function definition has a function header & a function body. The function header has
three parts:
- Function name
- A parameter list
- A return type
Each function is represented by its name. The function operates on its parameters
(arguments), if specified. If there are more than one parameter then they are separated
by a comma. The function’s parameter list is enclosed in parentheses. The result of a
function is reflected through its return value, referred as the function return type. The
return value is any valid C++ data types, either built-in or user-defined. If a function
does not return any value then it has a return type of void. The parameter list is
preceded by the function body, which is enclosed in braces. The function body is
sometimes referred to as the function block. This complete set of function return type,
name of the function, the parameter list and the function body is called to be the
function definition.
Here is the simple program that illustrates the concept of using simple function.
// Program – 1.cpp
#include
void example(); // Function Declaration
void main ()
{
cout << “\n I am in function main”;
example(); // Function Call
cout << “\n I am back in function main”;
}
void example() // Function Definition
{
cout << “\n I am in function example”;
}
From this program, it is cleared that three features are needed to use user-defined
functions:
1) Function declaration
2) Function call
3) Function definition
1) Function Declaration:
We know that we can not use a variable without declaring it. Likewise we can’t use a
function until we declare it at the beginning of the program. Although K & R’s C did not
have that requirement but C++ has a strong type checking built into the language
definition. Thus in C++ you must tell the compiler the number and the types of the list of
arguments (parameters) and its return value; otherwise a compile time error results. The
function declaration consists of the return type, the name of the function, and the list of
arguments.
return_type function_name(list_of_arguments);
void example();
Actually you can say that a function declaration describes the kind of information the
function must receive (list of arguments) and the kind of information it returns back, if
necessary. If the function has no return value we will use void keyword. We can not call
such function in the context of an expression where it is expected to return a value. For
example, we can not call a void function from the right side of an assignment statement.
K & R’s C did not have void function. In C, if you do not specify the return value of a
function in its declaration, it was assumed to return an int.
If it takes no argument then parenthesis must be empty. We can also use a void
keyword in parenthesis to indicate that the function takes no argument as:
The return type of a function can be a built-in data type, such as an int or a float or any
user-defined data types, such as struct or class, etc. Here are some more examples of
possible return types:
You can also specify parameter names in the list of arguments. A parameter name is
just a documentation aid that allows the parameter to be accessed from within the body
of the function such as:
However some programmers prefer to omit the identifier in the list of arguments
whereas others prefer to assign meaningful parameter identifiers in the prototype
declaration. Note that no two-parameter names appearing in the list of arguments can
be same as:
Let we have used a function complex that receives two variables of type int and its
return type is also an int then its function declaration will be as:
2) Function Call:
The function is called by its name, followed by parenthesis as:
example();
The syntax of function calling is similar to that of declaration except that the return type
is not used. Like function prototype, the function call also is terminated by semicolon.
When the program is executed and it encounters a function call, it immediately transfers
the control to the called function. Therefore firstly that function would get completed and
then control would return to the statement follows the function call.
3) Function Definition:
Function definition contains the actual code for the function. The syntax of function
definition is as:
return_data_type function_name(list_of_arguments)
{
// Declaration of local variables
// Function body
}
must agree with its declaration – the same function name, the same number of
arguments in same order and the same return type. When the function is called, the
control is transferred to the first statement in function body. The other statements of the
function body are then executed and when the closing braces is encountered, control
returns to the calling program. In program 1 the function definition is as:
void example()
{
cout << endl << “I am in function example”;
}
As stated earlier that C++ is a strongly typed language. The arguments of every function
call are type-checked during the compilation process. If the types of the arguments
specified in the list of arguments in function declaration do not match then an implicit
conversion is applied, if possible, such as conversion of a float to an int. Let you have a
function declaration as:
This declaration that the function sum() is receiving two arguments of type ints. Thus
when we call this function as:
sum(240);
Or what happens if sum() is passed more than two arguments as:
sum(2, 4, 6);
Here the compiler would certainly flag a compile-time error. But if the arguments are of
type floats as:
sum(2.0, 4.0);
Then the value of type float can be converted to a value of type int implicitly. In this case
the compiler would not flag any error, rather than it just displays a warning message. If
an implicit conversion is not possible or the number of arguments does not match, a
compile-time error would be certainly issued by the compiler. And this is the main
reason that a function can not be called until it has been first declared.
Call by Address
In call by address, instead of passing the actual values of the actual argument we pass addresses of
actual values. Whenever we deal with addresses, we must know how to handle them. That’s why before
discussing call by address, we will briefly discuss pointers that handle addresses.
Introduction to Pointers
We all know that the internal data storage of a computer is a memory unit. Memory unit is an
ordered sequence of memory cells, each capable of containing a piece of data. Each memory cell
has a distinct address that can be used to refer to it when data is stored in it or retrieved from it.
The addresses of memory depend upon its capacity. For a 640 KB of memory we have addresses
from 0 to 655,359; for 1 MB of memory we have addresses from 0 to 1,048,575 & so on. Since
the memory holds data and instructions, therefore when our program is loaded into memory it
occupies some space in memory. It means that every variable and every function starts at a
particular address.
//Program–8.cpp
#include
Void main()
{
int i=4, j=8;
cout<< i << j;
}
Here the addresses of variable i and j are 62800 and 62802 respectively. And the value 4 and 8
are stored at the addresses 62800 and 62802 respectively. Program 9.cpp illustrates this concept.
// Program –9.cpp
#include
void main()
{
int i=4, j=8;
cout << “\n Value=”<< i << “\tAddress=”<< &i;
cout << “\n Value=”<< j << “\tAddress=”<< &j;
}
The output represents the addresses in hexadecimal form, as indicated by the prefix 0x before
each address. One main point to note that their addresses may vary during particularly in multi
user computer system.
Pointer Declaration :
As we store integer values into integer variables, we can also store addresses of variables in a
special type of variables, known as pointer variables. Thus a pointer variable is defined as the
variable that holds an address of a memory location. The syntax of the declaration pointer
variable is
datatype * pointer_var_name;
The datatype is any valid C++ data type and pointer_var_name is the name of the pointer
variable name. Here the asterisk (*) operator implies pointer to. The result of pointer operator, *,
does the reverse of address operator &. It means that the pointer operator (*) returns the value of
variable stored at the address following it. Thus to access the value stored at any address we will
use pointer operator. Program 10.cpp illustrates this concept:
// Program – 10.cpp
#include
void main()
{
int i=4;
int *iptr;
iptr = &i;
cout << “\n Value = ”<< i << “\tAddress = ”<< &i;
cout << “\n Value = ” << *iptr << “\tAddress = ” <
}
int *iptr;
means that iptr is a pointer variable that contains an address of variable type int, in other words
iptr acts as a pointer to integer. Thus if iptr contains an address then *(iptr) contains a value
stored at this address.
*(iptr) results in 4.
Like integer pointer we can also have pointers for other data type such as char, float or even for a
user defined data type as:
char *cptr;
float *fptr;
long *lptr;
Like ordinary variables, we can also define multiple pointers in one line as:
While using pointer variables one should remember that we store the address of a data type into
the pointer of same data type. We can not store the address of a variable of one type into another
type of pointer variable. It means that integer pointer can hold an address of integer variable,
float pointer can hold an address of float variable and so on.
Now we will see how to use pointers in call by address functions. In cal by address we pass
addresses of actual arguments to the called function. These addresses are stored into formal
arguments, which are nothing other than pointer variables. Now whatever changes are made into
the formal arguments they are directly reflected to the actual arguments..
int a, b ;
cout << "\nEnter two numbers = " ;
cin >> a >> b;
cout << "Before calling swapadd() function.";
cout << "\na = " << a;
cout << "\nb = " << b;
swapadd (&a, &b ) ;
cout << "\nAfter calling swapadd() function.";
cout << "\na = " << a;
cout << "\nb = " << b ;
}
void swapadd(int *aa, int *bb)
{
int temp;
temp = (*aa);
(*aa) = (*bb);
(*bb) = temp;
}
In program 11.cpp, we pass the addresses of variables a and b to the functions swapadd(). When
the function swapadd() is invoked, the addresses of a and b are copied into the integer pointers aa
and bb respectively.
Call by Reference
In call by reference, a function passes a reference as an argument to another function. In this case
the called function works on the callers copy of parameters and not on a local copy. Before the
discussion of call by reference we must know what is a reference.
Introduction to Reference
A reference is referred to as an alias or synonym, that is an alternate name for another variable.
Like pointers, the reference enables us to pass large amount of data without the overhead of
copying them. Of course pointer also is an important feature of C and C++, but sometimes it may
trouble you and even a good programmer for some complex operations.
References are much like pointers. You can do anything with a reference that you can do with a
pointer. The C++ reference variables can give you same type of problem until you understand
them. However it has certainly some plus points over pointers.
A reference is indicated following the type specifier with the address-of & operator or you can
say the & operator identifies a reference variable. A reference must be initialized when it is
declared as in the following example:
int a=10;
int &b = a;
Here we have declared an integer variable, a, that has another name, b. Note that a reference can
not be made to refer to another variable (this is why it must be initialized. If you make any
change to a reference then that change is actually applied to the variable to which the reference
refers. Therefore now all references to either name have the same effect.
For example,
b+= 5;
adds 5 to a, the variable referred to by b. Another main point to note that each definition of a
reference must be preceded by the address of operator. For example,
int &x = a, y = b;
defines one reference and one variable. Let us take a simple example that illustrates the concept
of a reference:
In this program b is called as reference to a. From the above program we see that a variable and
its reference are so closely inter–linked that if one changes then another will automatically
change. And remember that even the address of a and b are same.
From this output, it is clear that a reference is neither a copy nor a pointer to the object to which
it refers. Instead it is just like another name. However you can verify this by executing program
13.cpp.
// Program – 13.cpp
#include
void main()
{
int a = 20 ;
int & b = a;
cout << “\n a = “ << a << “ Address of a = “ << &a ;
cout << “\n b = “ << b << “ Address of b = “ << &b ;
}
There is a subtle difference between a normal reference and a const reference. A const reference
can be initialized to a variable of a different data type; obviously there is a conversion from one
type to another, as well as to some constants. For example,
float x = 25.75;
const int & a = x;
const int & b = x+10;
const int & c = 204;
These above initializations are completely invalid for non-const references and thus they result in
compile-time errors. When is initialized to a variable type then the compiler must generate a
temporary object that the reference actually address but unfortunately user has no access to it.
Thus the following two statements:
float x = 25.75;
const int & a = x;
float x = 25.75;
int temp = x;
const int &a = temp;
Naturally the above program looks very simple and convenient way than call by address.
The const reference arguments ensures the caller that the called function can view them but can
not modify the values in the referenced arguments. The const references are treated as read only
arguments. In program 14.cpp if you use the following reference function.
Returning a Reference
We have already studied that how to pass a reference to a function as a parameter. However you
also can return a reference from a function. In such cases when a function returns a reference the
function call can exist in any context in which a reference can exist, including on the receiving
side of an assignment. Program 15.cpp illustrates this concept.
// Program - 15.cpp
#include
int &max(int &, int &);
void main()
{
int x, y;
cout<<”\n Enter any two numbers = ”;
cin >> x >> y;
int &z=max(x, y);
In this program, the program declares an int reference named z and initialize the reference with
the reference returned by the max() function/
When you execute this program, you get the following output:
Enter any two numbers = 10 15
Largest number is 15
A C++ function prototype can declare that one or more of the function’s argument have default
argument values for arguments in a C++ prototype like this
Now let us examine the output of program 16.cpp. When we call the function add() with three
arguments, say add(aa, bb, cc), then the formal arguments are replaced with actual arguments aa,
bb and cc. When second call statement add (aa, bb) is executed, the first and second formal
arguments are replaced with actual arguments and the third formal arguments uses default value,
which is 30, that’s why second statements results in 330. Now in third statements you will think
that we pass the values of bb and cc and in called function they are stored in b and c respectively
and the third argument, which is default, is a.
So you expect the output to be 510. But this is wrong, because the values of bb and cc are stored
in a and b respectively and the missing argument is assumed to be the last argument which is c in
our program 10. That’s why its output is 530. The forth statement also outputs in the same way.
The fifth statement, add (aa), passes just one argument thus two argumen ts are to be default.
Thus in default arguments case, we will have to remember two main points: