Let’s Start!

In this article, we’ll discuss reference variables with help of examples.

The symbol &, used for reference variable has a few different purposes with respect to its occurrence in the code.

when the ampersand sign i.e. & appears in front of a variable name, it is the address operator.

Let’s suppose that there are following lines in our code:

int x ;
int* ptr = &x;

In the above code, pointer “ptr” has the address of “x” wherever it’s stored.

The other place where & sign can appear is the signature of the function where it appears after the type of the parameter. Here, in the function signature, & sign after the type of the parameter indicates that the parameter is a reference variable.

void insert( const EType& x );
void remove( const EType& x );

Internal Memory Organization

Fig 1: Internal memory organization of a process

We already know that 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).

Fig 2: Call stack layout

Call by Value

Consider the code given below. We’re going to perform call be value and visualize the scenario through images.

//Function 1
int intMinus1( int oldVal) {
	oldVal = oldVal – 1;
	return oldVal;
}
void caller() {
	int myInt = 31;
	int retVal;
	retVal = intMinus1( myInt );
	cout << myInt << retVal;
}
Fig 3: Call stack layout when intMinus1 is called

In the Fig 3, copy of “myInt” is sent to “oldVal”. So, alterations are done to the copy of “31” (stored on oldVal) but not to original “myInt”.

When a parameter is sent to the function, then actually we send its copy. While array is sent by reference (starting address of the array).

In calling function “caller”, “retVal” is declared empty (you see ‘?’ in its place).

Now, let’s do it.

Fig 4: Call stack layout after subtraction in intMinus1

Now, you see that the function “intMinus1” decreases the value of “oldVal” by 1 and original value “myInt” remains unchanged in Fig 4.

Now, see the below figure after returning from “intMinus1”.

Fig 5: Call stack layout after return from intMinus1

Call by using Pointers

// Function 2
int intMinus2( int* oldVal) {
	*oldVal = *oldVal – 2;
	return *oldVal;
}
void caller() {
	int retVal;
	int myInt = 31;
	retVal = intMinus2( &myInt );
	cout << myInt << retVal;
}

Look at the stack layout in the call by using pointer in Fig 6, we’re using address of “myInt” in the “oldVal” of caller to do our job.

Fig 6: Call stack layout when intMinus2 is called

Now, you see that it changes the original value, stored in “myInt”.

Fig 7: Call stack layout after *oldVal = *oldVal – 2

After returning from “intMinus2”:

Fig 8: Call stack after return from intMinus2

Call by Reference

// Function 3
int intMinus3( int& oldVal) {
	oldVal = oldVal – 3;
	return oldVal;
}
Void caller() {
	int retVal;
	int myInt = 31;
	retVal = intMinus3( myInt );
	cout << myInt << retVal;
}

In the call by reference, we’re directly messing with the original value, look at Fig 9:

Fig 9: Call stack when intMinus3 is called

The idea is that the integer object “myInt” is used exactly as it exists in the caller. The function is simply reaches it through a different name “oldVal”.

Now, see the result when “intMinus3” is called:

Fig 10: Call stack layout after oldVal = oldVal – 3

After returning from “intMinus3”:

Fig 11: Call stack layout after return from intMinus3

REFERENCE: CS301 Handouts (page 189 to 200)

Categorized in:

Data Structures, Learning,

Last Update: March 27, 2024