KEMBAR78
e computer notes - Reference variables | PDF
ecomputernotes.com – Data Structures
Lecture No. 17
___________________________________________________________________
Data Structures
Lecture No. 17
After demonstrating the use of const and reference variables in the interface class for
a binary search tree in the previous lectures, we will now see what these reference
variables are and how does internal process go on during the use of reference
variables.
Reference Variables
Before proceeding ahead, there is need to know why the reference variables are used;
and what benefits a programmer can get while employing them. We will discuss these
all things in detail with the help of examples.
The symbol &, used for reference variable has a few different purposes with respect
to its occurrence in the code. In C++ programming, we have seen that when the
ampersand sign i.e. & appears in front of a variable name, it is the address operator. It
returns the address of the variable in front of which it is written. Thus for example, if
x is a variable name, then &x ; will return the address of the variable x. In general we
can say that
&variablename ;
will return the address of the variable. We know that an address can be stored in a
pointer. To further understand this concept, let’s suppose that there are following
lines in our code.
int x ;
int* ptr = &x;
The first line declares a variable x of type int while the second one declares a pointer
to int and assigns it the address of x. This address of variable x is returned by the &
sign written in front of the variable x. Thus a pointer variable is initialized by
assigning it the address of a variable. This address of the variable is gotten by using
the & sign with the variable name.
The other place where & sign can appear is the signature of the function where it
appears after the type of the parameter. Consider the insert and remove methods from
BinarySearchTree class that were declared as the following.
void insert( const EType& x );
void remove( const EType& x );
Notice that the & sign is after the type. Here we define the class and functions as
templates. Whenever, we use these methods, the type EType will be replaced with a
proper data type.
Suppose that we have designed the BinarySearchTree class to hold the integers only.
This means that there are no templates and the class can be defined only for integers.
Page 1 of 14
ecomputernotes.com – Data Structures
Lecture No. 17
___________________________________________________________________
So the insert and remove methods of this class will be as follows.
void insert( const int& x );
void remove( const int& x );
Here, in the function signature, & sign after the type of the parameter indicates that
the parameter is a reference variable. We can use this & sign with any data type i.e.
built- in or user defined, of an argument to show that this is a reference variable. This
is the syntax for the reference variable. Now let’s see why and how we use it and
what is its advantage? Let’s look at an example that will explain the reference
variable. Suppose we have the following three different functions.
The name of the first function is intMinus1, written as under.
//Function 1
int intMinus1( int oldVal)
{
oldVal = oldVal – 1;
return oldVal;
}
This function takes an integer as an argument. The local name of this argument is
oldVal. The first statement in the body of the function decreases the value of oldVal
by 1 then the next statement returns this value to the calling function.
The second function is intMinus2. This function takes a pointer to integer as an
argument. In the statement
*oldVal = *oldVal – 2 ;
*oldVal means the value at the location where oldVal is pointing to. To get the value
this way is called dereferencing. After experiencing a decrease by 2, this value
remains at the same location i.e. where oldVal is pointing to. Then the pointer to
integer is returned. This function is defined as follows.
// Function 2
int intMinus2( int* oldVal)
{
*oldVal = *oldVal – 2;
return *oldVal;
}
The third function intMinus3 takes a reference variable as an argument. Its definition
is as under.
// Function 3
int intMinus3( int& oldVal)
{
Page 2 of 14
ecomputernotes.com – Data Structures
Lecture No. 17
___________________________________________________________________
oldVal = oldVal – 3;
return oldVal;
}
The & sign after the type in the signature (declaration line) indicates that this
argument is a reference variable. Notice that & sign is used only in the function
declaration, leaving no need for its use in the body of the function. The statements in
the body of the function decrease the vale of oldVal by 3 and return it to the calling
function.
We can see that these three functions have the same return type and their body
performs the task of decreasing the passed value. However it is clear from the
declaration of these functions that the way of passing argument to these functions is
different. We will now see what changes occur while passing the argument in
different ways. We will write calling functions those call the above three functions
one by one. We will see how these calls are made and what differences happen during
the process of passing same value (in different ways) to these functions. The use of
call stack will help in ascertaining what happens to these local variables and
parameters.
Following is the function that calls the first function i.e. intMinus1.
void caller()
{
int myInt = 31;
int retVal;
retVal = intMinus1( myInt );
cout << myInt << retVal;
}
In this function (caller), we declare an integer variable myInt and assign it a value 31.
We also declare a variable retVal of type int. In the statement
retVal = intMinus1( myInt );
We call the function intMinus1 by passing it the variable myInt (the value of which is
31) and assign the return value of this function call to retVal. In the next statement,
we print the value of these two variables.
While talking about runtime environment, we noticed that an executable program
while in run, is loaded in the memory. It later becomes a process. This process is
given a block of memory, which it uses during its execution. Suppose we are running
many programs simultaneously i.e. browser, MS Word, Excel and dev-C++. We can
also run programs written by us. The figure 17.1 shows that process4 is a program
written by us. Every program, which we run takes a block of memory and becomes a
process. The memory occupied by a process is further partitioned into different parts.
The first part of the memory is for the code of the program. This code is in binary
form i.e. it is the compiled code. Afterwards, there is some area of memory for static
data that holds static and global variables. Then in the memory, there becomes the
stack. This stack is used in function calls. At the end, there is some area, called heap.
Page 3 of 14
ecomputernotes.com – Data Structures
Lecture No. 17
___________________________________________________________________
When we allocate memory dynamically by using new operator, this memory is
allocated from the heap. The following figure shows the internal memory
organization of a program (ourtest.exe).
Fig 17.1: Internal memory organization of a process (ourtest.exe)
We have discussed in detail the call stack that is used in function calls. We know that
when a function call is made, it’s all the arguments go on the stack. The return
address of the function also goes to the stack. The local variables are placed on the
stack. When a function calls some other function, an activation record is made. It has
much information including all these things (parameters, return address etc). The
detail of activation record relates to the compiler construction course. Here we are
concerned with only the call stack. Following figure shows the call stack layout.
In the stack layout figure, there are the entries of the caller in the upper portion. This
is due to the fact that the caller function itself was called (executed) by some one else.
The lower portion of the stack describes the stack status when the function intMinus1
is called. The stack contains parameters, local variables and return address of the
Page 4 of 14
Process 1
(browser)
Process 3
(Word)
Process 4
(ourtest.exe)
Process 2
(Dev-C++)
Windows Os Heap
Static data
Stack
Code
Parameters (caller)
Local variables(caller)
Return address (caller)
Parameters (intMinus1)
Local
variables(intMinus1)
Return address
stack grows downwards
sp
Fig 17.2: call stack layout
ecomputernotes.com – Data Structures
Lecture No. 17
___________________________________________________________________
function intMinus1. There is a stack pointer sp that points to the top of the stack (the
figure shows the stack downward; it should not be confused with the top). As the
caller has called intMinus1, this function is on the top of the stack.
The following figure shows the contents of the stack when the function intMinus1 is
called.
The figure shows the stack in two parts. The first part that is in the upper curly
bracket, shows the contents of the calling function i.e. caller. The lower part shows
the contents of the called function i.e. intMinus1. Recall that we declared two
variables in the caller function. These variables were myInt and retVal. We also
assigned a value 31 to myInt. This value (31) is in the memory location of myInt in
the stack. When we declared the variable retVal, there was no value assigned to it. So
its memory location contains nothing yet. After it, there is the other stuff of the caller
function. We have also shown the memory addresses of the locations on the left hand
side. We can see that the memory address of myInt is 1072 while that of retVal is
1068. Similarly, we see the addresses 1060, 1056 and 1052 further down. We note
that the addresses are with a difference of four. This is because of the use of the
integer variable, as an integer requires four bytes in the memory for storing. Similarly
the pointer variables are also of four bytes. The memory addresses are in 32 bits that
is four bytes (eight bits make a byte). Generally we start addressing the memory from
down. The lowest byte is addressed 0, followed by 1, 2, 3 and so on to upward
direction. If we have larger variables, for example, objects created by our defined
classes, these will require more memory. In that case, the memory chunks will not be
of four bytes. Rather, it will be equal to the size of the object. In C++, we have an
operator size or sizeof by which the size of a type or variable, acquired in the
memory, can be found. There are some machines that do not use byte addressing.
These machines use word addressing. Every word is of 48 bits. All these things
(memory addressing etc) relate to computer architecture course.
Now in the stack, there are the entries of the called function. There is the parameter
oldVal of the called function in the stack. It has the value 31. This is the same value
as that of myInt in the caller function. As studied earlier, in call by value
phenomenon, when arguments (whatever type they have) are sent to a function, a
Page 5 of 14
31
?
callers other
stuff
31
stack grows downward
sp
1072
1068
1060
1056
1052
myInt
retVal
oldVal
calling function “caller”
Called function
“intMinus1”
Fig 17.3: call stack layout when intMinus1 is called
ecomputernotes.com – Data Structures
Lecture No. 17
___________________________________________________________________
copy of these arguments is made before sending. That copy is sent to the called
function. The called function uses this copy of the argument. Thus a copy of myInt is
passed to the called function intMinus1. Thus its parameter oldVal has value 31. Now
intMinus1 function uses this value (i.e. oldVal) to do its functionality. It makes
alternations to this copy. The original value that is myInt does not change. This
phenomenon is shown in the following figure. Here the function intMinus1 decreases
the value of oldVal by 1 and becomes 30. The original value (myInt) remains
unchanged.
When the return call of intMinus1 is executed, the control comes back to the calling
function. The stuff of the called function intMinus1 is popped from the stack and the
pointer sp moves up accordingly. In other words, the activation record of the function
intMinus1 has been removed from the stack. The oldval (value of which is 30 now) is
returned to the caller function. We have written in the code that this value is assigned
to retVal variable. So in the call stack layout, the memory location of retVal has the
value 30. The figure 17.5 shows the stack layout after return from the called function
i.e. intMinus1.
In the call by value phenomenon of function calling, we can pass a literal or even an
expression. Thus in the previous function caller, we could have called the function
intMinus1 as follows.
Page 6 of 14
31
?
callers other
stuff
31 30
stack grows downward
sp
1072
1068
1060
1056
1052
myInt
retVal
oldVal
calling function “caller”
Called function
“intMinus1”
Fig 17.4: call stack layout after subtraction in intMinus1
31
30
callers other
stuff
stack grows downward
sp
1072
1068
myInt
retVal
calling function “caller”
Fig 17.5 call stack layout after return from intMinus1
ecomputernotes.com – Data Structures
Lecture No. 17
___________________________________________________________________
void caller()
{
int retVal;
retVal = intMinus1( 31 ); // a literal is passed
cout << retVal;
}
Here we did not put the value 31 in an integer variable. Rather, it was directly passed
as an argument in the function call i.e. intMinus1 (31). We are not passing a variable
as it was in the previous code of the function caller. The calling statement also be
written as under:
retVal = intMinus1( 30 + 1 );
In this statement, first the expression 30 + 1 is evaluated and then the copy of the
result goes to the call stack as a value of oldVal of called function.
In the previous calling function (i.e. caller), it was witnessed that the value of the
passed variable (myInt) remained same when we passed the variable by value. Now
there may be situations where we want to actually change the value of a variable of
the caller function from within the called function. In such a situation, we send the
pointer to the variable (i.e. the address of the variable) as an argument. Look at the
following code of the function caller. In this code, we call the function intMinus2 by
passing it the address of the variable myInt.
void caller()
{
int retVal;
int myInt = 31;
retVal = intMinus2( &myInt );
cout << myInt << retVal;
}
Following is the function calling statement
retVal = intMinus2( &myInt );
The ‘&’ sign before the name of the variable myInt means that the address of the
variable is being passed. The called function will take it as a pointer. Remember that
we have declared the argument of the function intMinus2 as int* oldVal that means
this function takes a pointer as an argument.
Now, keeping in mind that a pointer is being sent to the function, let’s see what is
happening in the call stack. The stack portion which has the stuff of the calling
function i.e. caller is the same as seen in the call by value process. The variable myInt
has value 31 and value of retVal will be written after returning from the called
function. Its stack layout is shown in the figure 17.6 below.
Page 7 of 14
31
?
callers other
stuff
1072
stack grows downward
sp
1072
1068
1060
1056
1052
myInt
retVal
oldVal
calling function “caller”
Called function
“intMinus2”
Fig 17.6 call stack layout when intMinus2 is called
ecomputernotes.com – Data Structures
Lecture No. 17
___________________________________________________________________
In the stuff of the called function i.e. intMinus2, the memory location of the oldVal
holds the value 1072. We can see on the left side of the stack in the figure above that
this 1072 is the address of the variable myInt. Look at the statement
*oldVal = *oldVal – 2 ;
of intMinus2. Here *oldVal can be expressed as ‘the value at the memory address that
is in oldVal’. In the stack layout, we see that the memory address in oldVal is 1072.
The value stored at the address 1072 is 31. The following statement
*oldVal = *oldVal – 2 ;
decreases this value 2 and thus brings the value at the memory address 1072 down to
29. As 1072 is the address of myInt, thus actually the value of myInt is changed. The
following figure of stack layout depicts this process.
Now when the execution of the called function ends after returning *oldVal, the
activation record of this function is removed from the stack. The pointer of the stack
comes up. The value 29 is put in the variable retVal of the calling function. Following
is the stack layout after return from the function intMinus2.
Page 8 of 14
31 29
?
callers other
stuff
1072
stack grows downward
sp
1072
1068
1060
1056
1052
myInt
retVal
oldVal
calling function “caller”
Called function
“intMinus2”
Fig 17.7: call stack layout after *oldVal = *oldVal – 2;
ecomputernotes.com – Data Structures
Lecture No. 17
___________________________________________________________________
Notice that the value of myInt of the caller function has also been changed.
We have seen that in call by value a copy of the argument is passed and used by the
called function. In this method, the original value of the argument in the calling
function remains unchanged. In the other method, we saw that when we pass the
address of the variable, the pointer is used to manipulate the variable data. In this
case, the original value of the variable in the calling function is changed. Suppose that
we want a function to change an object (variable/argument) but don’t want to send
the copy of the object to the function. The reason of not sending a copy is that the
object may be large (as we have seen the object Customer in bank simulation
example) and making a copy of it costs time and memory space. Say, the object
Customer is of 500 bytes. Now when a calling function will call a function using call
by value method, a copy of this object will be made on the call stack same as in our
previous example a copy of myInt was made. The copy constructor will make a copy
of this whole object that costs time. Moreover, the copy of this object will take 500
bytes on the stack that is a lot of memory consuming. There will be as many copies as
the number of calls. In case of a large number of calls, there may be inefficient
memory as call stack has a limited memory. So we do not use call by value
methodology. Furthermore, we want to avoid the massive syntax of pointers. For this
purpose, we do not use pointers in function calling. Now the question arises is there
any way through which we can fulfill our requirement. (i.e. we don’t want to make a
copy and want to change the objective without using the pointers ). The use of
reference variables may be a suitable answer to this very ticklish situation. The
phenomenon of function calls using reference variables is termed as call by reference.
Following is the code of the caller function that involves call by reference.
Void caller()
{
int retVal;
int myInt = 31;
Page 9 of 14
31 29
29
callers other
stuff
stack grows downward
sp
1072
1068
myInt
retVal
calling function “caller”
Fig 17.8: call stack after return from intMinus2
ecomputernotes.com – Data Structures
Lecture No. 17
___________________________________________________________________
retVal = intMinus3( myInt );
cout << myInt << retVal;
}
Note that this is almost the same function, we wrote at first to call intMinus1. The
only difference is that here we are calling the function intMinus3 instead of
intMinus1. We did not use & sign with myInt as used in the call for intMinus2. This is
only due to the fact that we are not sending an address. It is pertinent to note that in
the definition of the function intMinus3, we have used & sign with the argument
variable. We have written it as
int intMinus3( int& oldVal)
This statement means that the function intMinus3 will take a reference as an
argument. In other words, a reference of the argument variable will be passed to this
function. Thus the idea of reference variable is that an object will be used exactly as it
exists in the caller function. The called function simply accesses it through a different
name i.e. other than the name in the caller function. Here in our example, the called
function intMinus3 accesses (and uses) the passed argument i.e. myInt with the name
oldVal. The function intMinus3 cannot use the name myInt as it is in the caller’s
scope. Now the both variable names (myInt and oldVal) refer to the same object. It
means that the same memory cell where the object lies. We have read the scope of
variables that the local variables can be used only by the function in which they are
declared. The other functions cannot use the local variables of a function. But in
reference variables, we can access the memory location of a local variable in another
function by using another name. Thus in our example, we access the local variable
myInt (actually the memory location) of the function caller in the other function
intMinus3 with the name oldVal. The following figure explains this phenomenon of
reference variables with the help of call stack layout.
The caller function part of the stack contains myInt, retVal and other stuff of the
caller function. In the stack part intMinus3, the name oldVal shows that it has nothing
Page 10 of 14
31
?
callers other
stuff
stack grows downward
sp
1072
1068
1060
1056
1052
myInt
retVal
oldVal
calling function “caller”
called function “intMinus3”
Fig 17.9: call stack when intMinus3 is called
ecomputernotes.com – Data Structures
Lecture No. 17
___________________________________________________________________
in this portion but it is the other name of the memory location 1072, named as myInt
in the caller function. The dotted arrow shows this.
In the following figure 17.10, we show the oldVal along with the myInt at same
memory location. Here we want to show that the oldVal of called function and myInt
of caller function are the two names of the same memory location.
Now when the body of the intMinus3 executes the statement i.e.
oldVal = oldVal – 3 ;
It changes the value at the memory location in the caller function as it is referring to
that memory location. This value now becomes 28. Actually, the value of myInt is
changed as it also refers to the same memory location. The following figure explains
the stack lay out after the execution of the above statement.
Now when the function intMinus3 returns, the returned value (that is 28) is written in
retVal and the stuff (activation record) of intMinus3 is removed. The stack layout
becomes as shown in the figure below.
Page 11 of 14
31
?
callers other
stuff
stack grows downward
sp
OldVal 1072
1068
1060
1056
1052
myInt
retVal
calling function “caller”
called function “intMinus3”
Fig 17.10: call stack when intMinus3 is clled
31 28
?
callers other
stuff
stack grows downward
sp
oldVal 1072
1068
1060
1056
1052
myInt
retVal
calling function “caller”
called function “intMinus3”
Fig 17.11: call stack layout after oldVal = oldVal - 3
;
31 28
28
callers other
stuff
stack grows downward
sp
1072
1068
myInt
retVal
calling function “caller”
Fig 17.12: call stack layout after return from intMinus3
ecomputernotes.com – Data Structures
Lecture No. 17
___________________________________________________________________
This phenomenon of call by reference is actually implemented by the compiler by
using pointers. The obtaining of address and de-referencing will be done behind the
scene. We have no concern to do this. For a programmer, it is simply a renaming
abstraction, in which we rename the argument variable of the caller function and use
it in the called function.
Sample Program
Following is the program, which demonstrate the above three function calls that we
discussed in the previous example. We define the three functions intMinus1,
intMinus2 and intMinus3. These functions accept the argument as value, pointer and
reference variable respectively. The endl puts a new line and is used in the program
for the output clarity. Here is the code of the program followed by the output of the
program.
/*This program demonstrate tha how the value in a caller function is effected when it
is passed to a function by using call by value, by using pointers and by using call by
reference methods.
*/
#include <iostream.h>
//Function 1, call by value
int intMinus1( int oldVal)
{
oldVal = oldVal – 1;
return oldVal;
}
// Function 2, call by using pointers
int intMinus2( int* oldVal)
Page 12 of 14
ecomputernotes.com – Data Structures
Lecture No. 17
___________________________________________________________________
{
*oldVal = *oldVal – 2;
return *oldVal;
}
// Function 3, call by reference
int intMinus3( int& oldVal)
{
oldVal = oldVal – 3;
return oldVal;
}
void main ()
{
int myInt = 31;
int retVal;
retVal = intMinus1( myInt ); //call by value
cout << “After returning from the called function intMinus1” << endl ;
cout << ”The value returned by the called function (retVal) is : ” << retVal ;
cout << endl ;
cout << ”The value of the calling function’s variable (myInt) is : ” << myInt ;
cout << endl << endl;
// now pass the argument by using pointer, also initialize the value of myInt
myInt = 31 ;
retVal = intMinus2( &myInt ); //call by passing a pointer
cout << “After returning from the called function intMinus2” << endl;
cout << ”The value returned by the called function (retVal) is : ” << retVal ;
cout << endl;
cout << ”The value of the calling function’s variable (myInt) is : ” << myInt ;
cout << endl << endl;
// now pass the argument by as reference, also initialize the value of myInt
myInt = 31 ;
retVal = intMinus3( myInt ); //call by passing a reference
cout << “After returning from the called function intMinus3” << endl;
cout << ”The value returned by the called function (retVal) is : ” << retVal ;
cout << endl;
cout << ”The value of the calling function’s variable (myInt) is : ” << myInt ;
}
Following is the output of the program.
After returning from the called function intMinus1
The value returned by the called function (retVal) is : 30
Page 13 of 14
ecomputernotes.com – Data Structures
Lecture No. 17
___________________________________________________________________
The value of the calling function's variable (myInt) is : 31
After returning from the called function intMinus2
The value returned by the called function (retVal) is : 29
The value of the calling function's variable (myInt) is : 29
After returning from the called function intMinus3
The value returned by the called function (retVal) is : 28
The value of the calling function's variable (myInt) is : 28
We can see from the output of the program how the passed variable of the caller
function is affected by these different ways of function calling. Note that the values of
the variables used are the same as we have discussed with the help of call stack
layout.
Page 14 of 14

e computer notes - Reference variables

  • 1.
    ecomputernotes.com – DataStructures Lecture No. 17 ___________________________________________________________________ Data Structures Lecture No. 17 After demonstrating the use of const and reference variables in the interface class for a binary search tree in the previous lectures, we will now see what these reference variables are and how does internal process go on during the use of reference variables. Reference Variables Before proceeding ahead, there is need to know why the reference variables are used; and what benefits a programmer can get while employing them. We will discuss these all things in detail with the help of examples. The symbol &, used for reference variable has a few different purposes with respect to its occurrence in the code. In C++ programming, we have seen that when the ampersand sign i.e. & appears in front of a variable name, it is the address operator. It returns the address of the variable in front of which it is written. Thus for example, if x is a variable name, then &x ; will return the address of the variable x. In general we can say that &variablename ; will return the address of the variable. We know that an address can be stored in a pointer. To further understand this concept, let’s suppose that there are following lines in our code. int x ; int* ptr = &x; The first line declares a variable x of type int while the second one declares a pointer to int and assigns it the address of x. This address of variable x is returned by the & sign written in front of the variable x. Thus a pointer variable is initialized by assigning it the address of a variable. This address of the variable is gotten by using the & sign with the variable name. The other place where & sign can appear is the signature of the function where it appears after the type of the parameter. Consider the insert and remove methods from BinarySearchTree class that were declared as the following. void insert( const EType& x ); void remove( const EType& x ); Notice that the & sign is after the type. Here we define the class and functions as templates. Whenever, we use these methods, the type EType will be replaced with a proper data type. Suppose that we have designed the BinarySearchTree class to hold the integers only. This means that there are no templates and the class can be defined only for integers. Page 1 of 14
  • 2.
    ecomputernotes.com – DataStructures Lecture No. 17 ___________________________________________________________________ So the insert and remove methods of this class will be as follows. void insert( const int& x ); void remove( const int& x ); Here, in the function signature, & sign after the type of the parameter indicates that the parameter is a reference variable. We can use this & sign with any data type i.e. built- in or user defined, of an argument to show that this is a reference variable. This is the syntax for the reference variable. Now let’s see why and how we use it and what is its advantage? Let’s look at an example that will explain the reference variable. Suppose we have the following three different functions. The name of the first function is intMinus1, written as under. //Function 1 int intMinus1( int oldVal) { oldVal = oldVal – 1; return oldVal; } This function takes an integer as an argument. The local name of this argument is oldVal. The first statement in the body of the function decreases the value of oldVal by 1 then the next statement returns this value to the calling function. The second function is intMinus2. This function takes a pointer to integer as an argument. In the statement *oldVal = *oldVal – 2 ; *oldVal means the value at the location where oldVal is pointing to. To get the value this way is called dereferencing. After experiencing a decrease by 2, this value remains at the same location i.e. where oldVal is pointing to. Then the pointer to integer is returned. This function is defined as follows. // Function 2 int intMinus2( int* oldVal) { *oldVal = *oldVal – 2; return *oldVal; } The third function intMinus3 takes a reference variable as an argument. Its definition is as under. // Function 3 int intMinus3( int& oldVal) { Page 2 of 14
  • 3.
    ecomputernotes.com – DataStructures Lecture No. 17 ___________________________________________________________________ oldVal = oldVal – 3; return oldVal; } The & sign after the type in the signature (declaration line) indicates that this argument is a reference variable. Notice that & sign is used only in the function declaration, leaving no need for its use in the body of the function. The statements in the body of the function decrease the vale of oldVal by 3 and return it to the calling function. We can see that these three functions have the same return type and their body performs the task of decreasing the passed value. However it is clear from the declaration of these functions that the way of passing argument to these functions is different. We will now see what changes occur while passing the argument in different ways. We will write calling functions those call the above three functions one by one. We will see how these calls are made and what differences happen during the process of passing same value (in different ways) to these functions. The use of call stack will help in ascertaining what happens to these local variables and parameters. Following is the function that calls the first function i.e. intMinus1. void caller() { int myInt = 31; int retVal; retVal = intMinus1( myInt ); cout << myInt << retVal; } In this function (caller), we declare an integer variable myInt and assign it a value 31. We also declare a variable retVal of type int. In the statement retVal = intMinus1( myInt ); We call the function intMinus1 by passing it the variable myInt (the value of which is 31) and assign the return value of this function call to retVal. In the next statement, we print the value of these two variables. While talking about runtime environment, we noticed that an executable program while in run, is loaded in the memory. It later becomes a process. This process is given a block of memory, which it uses during its execution. Suppose we are running many programs simultaneously i.e. browser, MS Word, Excel and dev-C++. We can also run programs written by us. The figure 17.1 shows that process4 is a program written by us. Every program, which we run takes a block of memory and becomes a process. The memory occupied by a process is further partitioned into different parts. The first part of the memory is for the code of the program. This code is in binary form i.e. it is the compiled code. Afterwards, there is some area of memory for static data that holds static and global variables. Then in the memory, there becomes the stack. This stack is used in function calls. At the end, there is some area, called heap. Page 3 of 14
  • 4.
    ecomputernotes.com – DataStructures Lecture No. 17 ___________________________________________________________________ When we allocate memory dynamically by using new operator, this memory is allocated from the heap. The following figure shows the internal memory organization of a program (ourtest.exe). Fig 17.1: Internal memory organization of a process (ourtest.exe) We have discussed in detail the call stack that is used in function calls. We know that when a function call is made, it’s all the arguments go on the stack. The return address of the function also goes to the stack. The local variables are placed on the stack. When a function calls some other function, an activation record is made. It has much information including all these things (parameters, return address etc). The detail of activation record relates to the compiler construction course. Here we are concerned with only the call stack. Following figure shows the call stack layout. In the stack layout figure, there are the entries of the caller in the upper portion. This is due to the fact that the caller function itself was called (executed) by some one else. The lower portion of the stack describes the stack status when the function intMinus1 is called. The stack contains parameters, local variables and return address of the Page 4 of 14 Process 1 (browser) Process 3 (Word) Process 4 (ourtest.exe) Process 2 (Dev-C++) Windows Os Heap Static data Stack Code Parameters (caller) Local variables(caller) Return address (caller) Parameters (intMinus1) Local variables(intMinus1) Return address stack grows downwards sp Fig 17.2: call stack layout
  • 5.
    ecomputernotes.com – DataStructures Lecture No. 17 ___________________________________________________________________ function intMinus1. There is a stack pointer sp that points to the top of the stack (the figure shows the stack downward; it should not be confused with the top). As the caller has called intMinus1, this function is on the top of the stack. The following figure shows the contents of the stack when the function intMinus1 is called. The figure shows the stack in two parts. The first part that is in the upper curly bracket, shows the contents of the calling function i.e. caller. The lower part shows the contents of the called function i.e. intMinus1. Recall that we declared two variables in the caller function. These variables were myInt and retVal. We also assigned a value 31 to myInt. This value (31) is in the memory location of myInt in the stack. When we declared the variable retVal, there was no value assigned to it. So its memory location contains nothing yet. After it, there is the other stuff of the caller function. We have also shown the memory addresses of the locations on the left hand side. We can see that the memory address of myInt is 1072 while that of retVal is 1068. Similarly, we see the addresses 1060, 1056 and 1052 further down. We note that the addresses are with a difference of four. This is because of the use of the integer variable, as an integer requires four bytes in the memory for storing. Similarly the pointer variables are also of four bytes. The memory addresses are in 32 bits that is four bytes (eight bits make a byte). Generally we start addressing the memory from down. The lowest byte is addressed 0, followed by 1, 2, 3 and so on to upward direction. If we have larger variables, for example, objects created by our defined classes, these will require more memory. In that case, the memory chunks will not be of four bytes. Rather, it will be equal to the size of the object. In C++, we have an operator size or sizeof by which the size of a type or variable, acquired in the memory, can be found. There are some machines that do not use byte addressing. These machines use word addressing. Every word is of 48 bits. All these things (memory addressing etc) relate to computer architecture course. Now in the stack, there are the entries of the called function. There is the parameter oldVal of the called function in the stack. It has the value 31. This is the same value as that of myInt in the caller function. As studied earlier, in call by value phenomenon, when arguments (whatever type they have) are sent to a function, a Page 5 of 14 31 ? callers other stuff 31 stack grows downward sp 1072 1068 1060 1056 1052 myInt retVal oldVal calling function “caller” Called function “intMinus1” Fig 17.3: call stack layout when intMinus1 is called
  • 6.
    ecomputernotes.com – DataStructures Lecture No. 17 ___________________________________________________________________ copy of these arguments is made before sending. That copy is sent to the called function. The called function uses this copy of the argument. Thus a copy of myInt is passed to the called function intMinus1. Thus its parameter oldVal has value 31. Now intMinus1 function uses this value (i.e. oldVal) to do its functionality. It makes alternations to this copy. The original value that is myInt does not change. This phenomenon is shown in the following figure. Here the function intMinus1 decreases the value of oldVal by 1 and becomes 30. The original value (myInt) remains unchanged. When the return call of intMinus1 is executed, the control comes back to the calling function. The stuff of the called function intMinus1 is popped from the stack and the pointer sp moves up accordingly. In other words, the activation record of the function intMinus1 has been removed from the stack. The oldval (value of which is 30 now) is returned to the caller function. We have written in the code that this value is assigned to retVal variable. So in the call stack layout, the memory location of retVal has the value 30. The figure 17.5 shows the stack layout after return from the called function i.e. intMinus1. In the call by value phenomenon of function calling, we can pass a literal or even an expression. Thus in the previous function caller, we could have called the function intMinus1 as follows. Page 6 of 14 31 ? callers other stuff 31 30 stack grows downward sp 1072 1068 1060 1056 1052 myInt retVal oldVal calling function “caller” Called function “intMinus1” Fig 17.4: call stack layout after subtraction in intMinus1 31 30 callers other stuff stack grows downward sp 1072 1068 myInt retVal calling function “caller” Fig 17.5 call stack layout after return from intMinus1
  • 7.
    ecomputernotes.com – DataStructures Lecture No. 17 ___________________________________________________________________ void caller() { int retVal; retVal = intMinus1( 31 ); // a literal is passed cout << retVal; } Here we did not put the value 31 in an integer variable. Rather, it was directly passed as an argument in the function call i.e. intMinus1 (31). We are not passing a variable as it was in the previous code of the function caller. The calling statement also be written as under: retVal = intMinus1( 30 + 1 ); In this statement, first the expression 30 + 1 is evaluated and then the copy of the result goes to the call stack as a value of oldVal of called function. In the previous calling function (i.e. caller), it was witnessed that the value of the passed variable (myInt) remained same when we passed the variable by value. Now there may be situations where we want to actually change the value of a variable of the caller function from within the called function. In such a situation, we send the pointer to the variable (i.e. the address of the variable) as an argument. Look at the following code of the function caller. In this code, we call the function intMinus2 by passing it the address of the variable myInt. void caller() { int retVal; int myInt = 31; retVal = intMinus2( &myInt ); cout << myInt << retVal; } Following is the function calling statement retVal = intMinus2( &myInt ); The ‘&’ sign before the name of the variable myInt means that the address of the variable is being passed. The called function will take it as a pointer. Remember that we have declared the argument of the function intMinus2 as int* oldVal that means this function takes a pointer as an argument. Now, keeping in mind that a pointer is being sent to the function, let’s see what is happening in the call stack. The stack portion which has the stuff of the calling function i.e. caller is the same as seen in the call by value process. The variable myInt has value 31 and value of retVal will be written after returning from the called function. Its stack layout is shown in the figure 17.6 below. Page 7 of 14 31 ? callers other stuff 1072 stack grows downward sp 1072 1068 1060 1056 1052 myInt retVal oldVal calling function “caller” Called function “intMinus2” Fig 17.6 call stack layout when intMinus2 is called
  • 8.
    ecomputernotes.com – DataStructures Lecture No. 17 ___________________________________________________________________ In the stuff of the called function i.e. intMinus2, the memory location of the oldVal holds the value 1072. We can see on the left side of the stack in the figure above that this 1072 is the address of the variable myInt. Look at the statement *oldVal = *oldVal – 2 ; of intMinus2. Here *oldVal can be expressed as ‘the value at the memory address that is in oldVal’. In the stack layout, we see that the memory address in oldVal is 1072. The value stored at the address 1072 is 31. The following statement *oldVal = *oldVal – 2 ; decreases this value 2 and thus brings the value at the memory address 1072 down to 29. As 1072 is the address of myInt, thus actually the value of myInt is changed. The following figure of stack layout depicts this process. Now when the execution of the called function ends after returning *oldVal, the activation record of this function is removed from the stack. The pointer of the stack comes up. The value 29 is put in the variable retVal of the calling function. Following is the stack layout after return from the function intMinus2. Page 8 of 14 31 29 ? callers other stuff 1072 stack grows downward sp 1072 1068 1060 1056 1052 myInt retVal oldVal calling function “caller” Called function “intMinus2” Fig 17.7: call stack layout after *oldVal = *oldVal – 2;
  • 9.
    ecomputernotes.com – DataStructures Lecture No. 17 ___________________________________________________________________ Notice that the value of myInt of the caller function has also been changed. We have seen that in call by value a copy of the argument is passed and used by the called function. In this method, the original value of the argument in the calling function remains unchanged. In the other method, we saw that when we pass the address of the variable, the pointer is used to manipulate the variable data. In this case, the original value of the variable in the calling function is changed. Suppose that we want a function to change an object (variable/argument) but don’t want to send the copy of the object to the function. The reason of not sending a copy is that the object may be large (as we have seen the object Customer in bank simulation example) and making a copy of it costs time and memory space. Say, the object Customer is of 500 bytes. Now when a calling function will call a function using call by value method, a copy of this object will be made on the call stack same as in our previous example a copy of myInt was made. The copy constructor will make a copy of this whole object that costs time. Moreover, the copy of this object will take 500 bytes on the stack that is a lot of memory consuming. There will be as many copies as the number of calls. In case of a large number of calls, there may be inefficient memory as call stack has a limited memory. So we do not use call by value methodology. Furthermore, we want to avoid the massive syntax of pointers. For this purpose, we do not use pointers in function calling. Now the question arises is there any way through which we can fulfill our requirement. (i.e. we don’t want to make a copy and want to change the objective without using the pointers ). The use of reference variables may be a suitable answer to this very ticklish situation. The phenomenon of function calls using reference variables is termed as call by reference. Following is the code of the caller function that involves call by reference. Void caller() { int retVal; int myInt = 31; Page 9 of 14 31 29 29 callers other stuff stack grows downward sp 1072 1068 myInt retVal calling function “caller” Fig 17.8: call stack after return from intMinus2
  • 10.
    ecomputernotes.com – DataStructures Lecture No. 17 ___________________________________________________________________ retVal = intMinus3( myInt ); cout << myInt << retVal; } Note that this is almost the same function, we wrote at first to call intMinus1. The only difference is that here we are calling the function intMinus3 instead of intMinus1. We did not use & sign with myInt as used in the call for intMinus2. This is only due to the fact that we are not sending an address. It is pertinent to note that in the definition of the function intMinus3, we have used & sign with the argument variable. We have written it as int intMinus3( int& oldVal) This statement means that the function intMinus3 will take a reference as an argument. In other words, a reference of the argument variable will be passed to this function. Thus the idea of reference variable is that an object will be used exactly as it exists in the caller function. The called function simply accesses it through a different name i.e. other than the name in the caller function. Here in our example, the called function intMinus3 accesses (and uses) the passed argument i.e. myInt with the name oldVal. The function intMinus3 cannot use the name myInt as it is in the caller’s scope. Now the both variable names (myInt and oldVal) refer to the same object. It means that the same memory cell where the object lies. We have read the scope of variables that the local variables can be used only by the function in which they are declared. The other functions cannot use the local variables of a function. But in reference variables, we can access the memory location of a local variable in another function by using another name. Thus in our example, we access the local variable myInt (actually the memory location) of the function caller in the other function intMinus3 with the name oldVal. The following figure explains this phenomenon of reference variables with the help of call stack layout. The caller function part of the stack contains myInt, retVal and other stuff of the caller function. In the stack part intMinus3, the name oldVal shows that it has nothing Page 10 of 14 31 ? callers other stuff stack grows downward sp 1072 1068 1060 1056 1052 myInt retVal oldVal calling function “caller” called function “intMinus3” Fig 17.9: call stack when intMinus3 is called
  • 11.
    ecomputernotes.com – DataStructures Lecture No. 17 ___________________________________________________________________ in this portion but it is the other name of the memory location 1072, named as myInt in the caller function. The dotted arrow shows this. In the following figure 17.10, we show the oldVal along with the myInt at same memory location. Here we want to show that the oldVal of called function and myInt of caller function are the two names of the same memory location. Now when the body of the intMinus3 executes the statement i.e. oldVal = oldVal – 3 ; It changes the value at the memory location in the caller function as it is referring to that memory location. This value now becomes 28. Actually, the value of myInt is changed as it also refers to the same memory location. The following figure explains the stack lay out after the execution of the above statement. Now when the function intMinus3 returns, the returned value (that is 28) is written in retVal and the stuff (activation record) of intMinus3 is removed. The stack layout becomes as shown in the figure below. Page 11 of 14 31 ? callers other stuff stack grows downward sp OldVal 1072 1068 1060 1056 1052 myInt retVal calling function “caller” called function “intMinus3” Fig 17.10: call stack when intMinus3 is clled 31 28 ? callers other stuff stack grows downward sp oldVal 1072 1068 1060 1056 1052 myInt retVal calling function “caller” called function “intMinus3” Fig 17.11: call stack layout after oldVal = oldVal - 3 ; 31 28 28 callers other stuff stack grows downward sp 1072 1068 myInt retVal calling function “caller” Fig 17.12: call stack layout after return from intMinus3
  • 12.
    ecomputernotes.com – DataStructures Lecture No. 17 ___________________________________________________________________ This phenomenon of call by reference is actually implemented by the compiler by using pointers. The obtaining of address and de-referencing will be done behind the scene. We have no concern to do this. For a programmer, it is simply a renaming abstraction, in which we rename the argument variable of the caller function and use it in the called function. Sample Program Following is the program, which demonstrate the above three function calls that we discussed in the previous example. We define the three functions intMinus1, intMinus2 and intMinus3. These functions accept the argument as value, pointer and reference variable respectively. The endl puts a new line and is used in the program for the output clarity. Here is the code of the program followed by the output of the program. /*This program demonstrate tha how the value in a caller function is effected when it is passed to a function by using call by value, by using pointers and by using call by reference methods. */ #include <iostream.h> //Function 1, call by value int intMinus1( int oldVal) { oldVal = oldVal – 1; return oldVal; } // Function 2, call by using pointers int intMinus2( int* oldVal) Page 12 of 14
  • 13.
    ecomputernotes.com – DataStructures Lecture No. 17 ___________________________________________________________________ { *oldVal = *oldVal – 2; return *oldVal; } // Function 3, call by reference int intMinus3( int& oldVal) { oldVal = oldVal – 3; return oldVal; } void main () { int myInt = 31; int retVal; retVal = intMinus1( myInt ); //call by value cout << “After returning from the called function intMinus1” << endl ; cout << ”The value returned by the called function (retVal) is : ” << retVal ; cout << endl ; cout << ”The value of the calling function’s variable (myInt) is : ” << myInt ; cout << endl << endl; // now pass the argument by using pointer, also initialize the value of myInt myInt = 31 ; retVal = intMinus2( &myInt ); //call by passing a pointer cout << “After returning from the called function intMinus2” << endl; cout << ”The value returned by the called function (retVal) is : ” << retVal ; cout << endl; cout << ”The value of the calling function’s variable (myInt) is : ” << myInt ; cout << endl << endl; // now pass the argument by as reference, also initialize the value of myInt myInt = 31 ; retVal = intMinus3( myInt ); //call by passing a reference cout << “After returning from the called function intMinus3” << endl; cout << ”The value returned by the called function (retVal) is : ” << retVal ; cout << endl; cout << ”The value of the calling function’s variable (myInt) is : ” << myInt ; } Following is the output of the program. After returning from the called function intMinus1 The value returned by the called function (retVal) is : 30 Page 13 of 14
  • 14.
    ecomputernotes.com – DataStructures Lecture No. 17 ___________________________________________________________________ The value of the calling function's variable (myInt) is : 31 After returning from the called function intMinus2 The value returned by the called function (retVal) is : 29 The value of the calling function's variable (myInt) is : 29 After returning from the called function intMinus3 The value returned by the called function (retVal) is : 28 The value of the calling function's variable (myInt) is : 28 We can see from the output of the program how the passed variable of the caller function is affected by these different ways of function calling. Note that the values of the variables used are the same as we have discussed with the help of call stack layout. Page 14 of 14