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–1.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-2.cpp illustrates this concept.

Program–2.cpp

 #include
 void main()
 {
 int i=4, j=8;
 cout << “n Value=”<< i << “tAddress=”<< &i;
 cout << “n Value=”<< j << “tAddress=”<< &j;
 }
The output of this program is:

Value = 4    Address = 0x8facfff4
Value = 8    Address = 0x8facfff2

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-3.cpp illustrates this concept:

Program-3.cpp

 #include
 void main()
 {
 int i=4;
 int *iptr;
 iptr = &i;
 cout << “n Value = ”<< i << “tAddress = ”<< &i;
 cout << “n Value = ” << *iptr << “tAddress = ” <
}
The output of this program is as:

Value = 4    Address = 0x8facfff4
Value = 4    Address = 0x8facfff4

In this program, the statement 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.That is why in this program*(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:

int *iptr1, *iptr2, *iptr3;

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 call 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..

Program–4.cpp – Call by address

 #include
 void swapadd (int *, int *);
 void main ()
 {
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-4.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.

Here is the output of this program….

Enter two number = 10    20
Before calling swapadd() function.
a = 10
b = 20
After calling swapadd() function.
a = 20
b = 10

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:

// Program-5.cpp – Use of reference
 #include
 void main()
 {
 int a = 20 ;
 int & b = a;
 cout << “n a = “ << a << “ b = “ << b ;
 b = 40;
 cout << “n a = “ << a << “ b = “ << b ;
 a = 60;
 cout << “n a = “ << a << “ b = “ << b ;
 }

The output of this program is
a = 20 b = 20
a = 40 b = 40
a = 60 b = 60

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-6.cpp.
Program-6.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 ;
 }

The output of this program is

a = 20 Address of a = Ox8facfff420
b = 20 Address of b = Ox8facfff420

Thus the two addresses are same.

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;

are internally transformed as:

float x = 25.75;
 int temp = x;
 const int &a = temp;

Also the statement

const int &c = 204;

is also interpreted as:

int temp = 204;
 const int &c = temp;

Now we see how it helps in function swapref().

Program-7.cpp: Call by reference

 #include
 void swapref(int &, int &);
 void main()
 {
 int a, b;
 cout << “nEnter two numbers = ” ;
 cin >> a >> b ;
 cout << "Before calling swapref() function.";
 cout << “na = ”<< a << “tb = ”<< b;
 swapref(a, b);
 cout << "After calling swapref() function.";
 cout << “na = ” << a << “tb = ” << b;
 }
 void swapref(int &aa, int &bb)
 {
 int temp;
 temp = aa;
 aa = bb;
 bb = temp;
 }

The output of this program is:

Enter two numbers = 5 10
Before calling swapref() function.
a = 5 b = 10
After calling swapref() function.";
a = 10 b = 5

Naturally the above program looks very simple and convenient way than call by address.

The const Reference :

In program-7.cpp, the swapref() function modifies the caller’s variables because the parameters are references to those variables. However in certain situations, a function is restricted to modify caller’s referenced variable. To handle this, we declare such arguments as const.

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-7.cpp if you use the following reference function.

void swapref(const int &aa, const int &bb)
 {
 int temp;
 aa = temp;
 aa = bb;
 bb = temp;
 }

You would certainly get an error message, saying:

Can not be a const object

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-8.cpp illustrates this concept.
Program-8.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);
cout<<”nLargest number is “< }
 int & max(int &a, int &b)
 {
 if (a>b)
 return a;
 else
 return b;
 }

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

Default Functions Arguments

In earlier programs we have discussed such programs that receives same number of arguments as they are provided to it. That is if we pass three arguments then the called function must receive three arguments in three formal variables. C++ provides a facility to define initial values for arguments that are not passed when the function is called.

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

int add(int a=10, int b=20, int c=30);

Now when a call to the function does not contain the corresponding arguments, the compiler inserts the default values where it expects to see the arguments. Let us understand this concept of default arguments by examining Program-9.cpp
Program-9.cpp: Default arguments

 #include
 int add(int a = 10, int b = 20, int c = 30);
 void main ()
 {
 int aa, bb, cc, dd;
 cout << “nEnter three numbers = ” ;
 cin >> aa >> bb >> cc;
 dd = add(aa, bb, cc);
 cout << “nThe addition of three numbers = ” << dd ;
 dd = add(aa, bb);
 cout << “nThe addition of three numbers = ” << dd ;
 dd = add (bb, cc ) ;
 cout << “nThe addition of three numbers = ” << dd ;
 dd = add (cc, aa) ;
 cout << “nThe addition of three numbers = ” << dd ;
 dd = add (aa);
 cout << “nThe addition of three numbers = ” << dd ;
 dd = add (bb);
 cout << “nThe addition of three numbers = ” << dd ;
 dd = add (cc);
 cout << “nThe addition of three numbers = ” << dd ;
 dd = add();
 cout << “nThe addition of three numbers = ” << dd ;
 }
int add(int a, int b, int c)
 {
 return (a + b + c);
 }

The output of this program is

Enter three numbers = 100 200 300
The addition of three numbers = 600
The addition of three numbers = 330
The addition of three numbers = 530
The addition of three numbers = 430
The addition of three numbers = 150
The addition of three numbers = 250
The addition of three numbers = 350
The addition of three numbers = 60

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 arguments are to be default.Thus in default arguments case, we will have to remember two main points:- Default values are always been taken from trailing variables.
– Default values should be defined where we are defining the function prototype and should not be repeated in function definition.