At the end of the chapter, you should be able to understand and use
Pointers and references, and know when to use what?
Objects and pointers.
Objects and references.
Dangling pointers and memory leaks.
Constant pointers, constant objects and references.
In our experience of teaching C++, we found that learners are pretty confused about pointers and references and related memory management. This is mainly because they would have probably picked up the “what” of pointers and references and not the “why” of pointers and references. In this chapter, we would like to bring out special characteristics of pointers and references like
In this chapter, starting from basics we would teach you how to handle pointers and references for C++ paradigm, without pitfalls such as dangling pointers and memory leaks.
In C++, we would like to use pointers because they point to location in memory and are very efficient to move multiple data items between the main program and function as function arguments. In addition, you can have pointers to a function and execute different functions just by reassigning the pointer based on the user's choice. Pointers would facilitate reassignment just like you can point at any person with your index finger.
How does Arjuna, the famous archer in Mahabharata, use his arrows? Firstly, he removed an arrow from his storage. Secondly, he gave a name (mantra like Nag Astra as shown in Figure 9.1). Then he points it toward the ground while thinking or getting address from his guide (Lord Krishna). He then pointed it to the ground so that the arrow did not take off accidentally and hit passers by or unintended targets. Lastly, he aimed at the target at the address given before letting it go! We will also do the same in the case of pointers.
Figure 9.1 A pointer example with terms
int *ptr=0; // you have created a pointer of type int
// Note ptr is the pointer
// Pointer is the address
// *ptr is the value
// you have now pointed to NULL (0 is treated as NULL)
When * precedes a variable in declaration statement, it means that the variable is a pointer variable. For example, ptr in int *ptr=0; is a pointer variable. It is a good safe programming practice to initialize the pointer as soon as it is created.
Let us say that at address 2513 we have stored an integer variable called age as shown in Figure 9.2. At address 2613 we have integer variable age2.
Figure 9.2 Pointer in a memory
int age=50;
int age2=18;
//we want pointer ptr to point to age;
ptr = & age; // you have assigned ptr to age. & is called address operator
cout<< age; // displays 50
cout<<*ptr; // displays 50 . *ptr which is value stored location, i.e. 50
//Once created you can reassign pointers
ptr=& age2;
cout<<*ptr; // displays 18 . *ptr which is value stored location, i.e. 18
Dereference or indirection operator ( *) is used to obtain the value pointed by the pointer. For example, cout<<*ptr; // displays 50
Example 9.2: ptr1.cpp Pointers Usage
#include<iostream>
using namespace std;
void main()
{ int age1=50;
int age2=18;
//create a pointer
int * ptr=0;
// assign it to age1
ptr = & age1; // & is address of operator
cout<<”
age1 “<< age1<<endl; // displays 50
cout<<”
age1 with *ptr “<< *ptr<<endl; // displays 50 .*ptr is value.
cout<<”
address using (&age1) and ptr : “<<&age1<<” ”<<ptr<<endl;
// ptr is address of age1, so is &age1. Hence both must be same
// now we will reassign the same pointer to age2
ptr = & age2;
cout<<”
your age (*ptr) : “<<” ”<< *ptr; // displays 18 .*ptr is value stored location
cout<<”
address of (&age2) and ptr : “<<& age2<<” ”<<ptr<<endl;
// ptr is address of age2 so is &age2. Hence both must be same.
cout<<”
address of(&ptr) :”<<” ”<< & ptr<<endl; // prints out address of variable
// ptr. We are not interested in this address. It is just another address.
}//end of main
/*Output:
age1 50
age1 with *ptr 50
address using (&age1) and ptr : 0012FF7C 0012FF7C
your age (*ptr) : 18
address of (&age2) and ptr : 0012FF78 0012FF78
address of(&ptr) : 0012FF74
A note about address scheme of Intel processors is appropriate: When you ask for a display of address, the system would display a 32-bit address like fffffff4 in hexadecimal notation, which means
1111 1111 1111 1111 1111 1111 1111 0100 in binary.
What are they? You can pass variables to a function by either of:
Both types are effective. We will use pointers if reassigning is required, whereas if you use reference, its fixed memory location and reassignment to new location is NOT feasible.
Example 9.3: valptrref. Program to Highlight Call by Value and Call by Reference Using Pointers
#include <iostream>
using namespace std;
// declaration of function prototypes
void Swap( int a , int b); // call by value
void PtrSwap ( int *a , int * b); // Call by Ref. a & b are pointers by def
void main()
{ int x=5;
int y=10;
// call by value
Swap( x,y);
cout<<"
after call by value :"<<endl;
cout<<"x value after swap:"<<x<<endl;
cout<<"y value after swap:"<<y<<endl;
// call by reference using pointers. Note that we have to send pointers
//i.e. addresses of x & y . Hence we will pass &x , and & y.
PtrSwap(&x,&y);
cout<<"
after call by ref using pointers :"<<endl;
cout<<"x value after Ptrswap:"<<x<<endl;
cout<<"y value after Ptrswap:"<<y<<endl;
}//end of main
// Function definitions
void Swap ( int a, int b)
{ int temp ; // two local variables
temp=a;
a=b;
b=temp;
cout<<"
inside Swap using pointers :"<<endl;
cout<<"x value inside Swap:"<<a<<endl;
cout<<"y value inside Swap:"<<b<<endl;
}
void PtrSwap ( int *a, int *b)
{ // a & b are pointers . Hence we need a pointer called temp
int temp;
temp=*a;
*a=*b;
*b=temp;
cout<<"
inside PtrSwap using pointers :"<<endl;
cout<<"x value inside Ptrswap:"<<*a<<endl;
cout<<"y value inside Ptrswap:"<<*b<<endl;
}
/*Output :inside Swap using pointers :
x value inside Swap:10
y value inside Swap:5
after call by value :
x value after swap:5
y value after swap:10
inside PtrSwap using pointers :
x value inside Ptrswap:10
y value inside Ptrswap:5
after call by ref using pointers :
x value after Ptrswap:10
y value after Ptrswap:5 */
In Example 9.3, a few interesting results are given. Though inside Swap function values actually were interchanged, they were not reflected in the main program as discussed. Whereas in the case of PtrSwap, wherein we have passed pointers, the result of PtrSwap was reflected to main programs. This is in consonance with what we have learnt.
We have learnt the memory management and mapping of C++ language in Chapter 3. In this section, we will learn tools and techniques to use heap memory, also called free space or dynamic memory, by pointers and references by using operators such as new and delete.
Dynamic memory, or heap memory as it is known, affords very large programs to be run on limited primary memory resource. For example, the real memory requirement is known only at run-time from the user, whereas the memory allocation normally takes place at compile time. Further, to execute several of the overloaded functions, the system compiles, loads and then runs. So if the user chooses at run time only one of the several functions loaded on to primary memory, the balance memory is wasted and hence we cannot solve problems requiring large memories. Dynamic memory solves this problem with new and delete operators. Allocate the heap memory with new operators and immediately after use, release the memory with delete operator. Thus, precious and limited memory is available for allocation and thus we can solve larger problems demanding larger memory. We can declare a heap variable using new operator.
int *x = new int; // creation and allocation of heap memory
*x=25; // assign value
Alternately, we can use a single statement
int *x = new int(12); allocate value 12 to pointer variable on heap memory.
Once allocated, you can use the dynamic memory pointer like an ordinary pointer. Remember that you have to release the memory after use so that the released memory can be used for other heap memory requirements. In this way, we can solve more complex problems because compiler loads a heap variable and allocates the exact memory requirements indicated by the user as well as frees the memory after use. It is good practice to delete the dynamic memory allocated using delete operator. In fact, the number of new declarations must match the number of deletes, though the system automatically releases the memory once the program ends.
int *x = new int(12); // created a pointer x on heap and allocated a value =12
*q *=*q ; // find the square of value, i.e. 144
cout<<*q;
……………
delete q; // q pointer has been deleted
If you reallocate the dynamic pointer to a new variable without deleting the existing assignment, the originally assigned variable and heap memory allocated is permanently lost and not available to program. This is called memory leak.
int *x = new int(12);
*q *=*q ; // find the square of value i.e. 144
cout<<*q;
int *x = new int(75); // Error since reassigned to new without deleting
delete q; // q pointer has been deleted.
In this, the user tries to use the pointer after it has been deleted
Example 9.5: Dangling Pointer: An Example
int *x = new int(12);
*q *=*q ; // find the square of value i.e. 144
delete q; // q pointer has been deleted.
cout<<*q; // Error. q has become dangling pointer
Let us understand the connection between pointers and arrays:
Note that ‘x’ is the name of the array. ‘x’ is also the address of the array and as well as the address of the first element of the array. Hence, we can call ‘x’ as the pointer to the array too.
Suppose you want to print the 4th element, i.e. 40; as per C++ convention, you would write cout<<x[3]. Now as the element, we are interested in is at position 4 (3 in case we are counting from 0), i.e. at address x+3, we have learnt that if we want value from address we have to de-reference the address by using *.
Ex cout<< *(x+3);
Figure 9.3 shows array elements together with their addresses.
Figure 9.3 Array with addresses (pointers)
Let us say that you have a two-dimensional array ‘a’ with 12 rows and 20 columns.
Then we can declare it as:
int a[12][20]
or
as a one-dimensional array using pointers. For example:
int *a[20]
We can also depict the above a as pointer to pointer ** a
Pictorially following the figure makes the concept clear. Therefore, a[0] points to the beginning of the first row. a[11] points to the beginning of the 11th row. Note that a[0]….a[11] are pointers to respective rows.
Now suppose you want to access the 1st row 5 element; then a[1] is the pointer to the first row and 5 elements displacement is 5:
We know we can write a[1] as *(a+1)
Therefore, the address of the desired element is a[1]+5 or *(a+1) +5
The value of element is : * (*(a+1) + 5 ).
We can declare an array of 12 integers as : int x[12]. This array declaration reserves 12 contiguous locations in memory. In case the user does not use all 12 locations, memory will be wasted. Array declaration is an example of static memory allocation. Instead, we can also declare an array as
int *x =new int[12]; // x is a pointer variable pointing to array by name x
//, having 12 contiguous locations.
int *ptr=x; // now ptr points x[0], i.e. starting of an array
Let us write a program to pass an array to a function that receives an array by reference and sorts an integer array. We can define an array of 12 integers using new function and release the heap memory after use by deleting function, as follows:
Example 9.6: dynarray.cpp A Program for Sorting of an Array by Passing an Array by Reference and to Find the Maximum of an Array
#include<iostream>
sing namespace std;
// function prototypes
template<class T>
T FindMax( T x[] , int n);
template<class T>
void SortArray( T *a , int n);
void main()
{ int n;
int max; // n=no of values in an array
int *x; // x is a pointer to an array
cout<<"how many elements in your array :";
cin>>n;
// allocate dynamic memory space using new operator
x=new int[n]; // allocates 12 contiguous location to pointer x
// read in the array
for (int i=0;i<n;i++)
{ cout<<"value for "<<i+1<<"element:";
cin>>x[i];
}
cout<<("
The entered array is….
");
for (i=0;i<n;i++)
cout<<" "<<* (x+i); // same as writing x[i]
// call Findmax function
max=FindMax(x,n);//x is a pointer to array
cout<<"
maximum value of given array="<<max<<endl;
// call SortArray function
SortArray(x,n);
cout<<("
The entered array is….
");
for (i=0;i<n;i++)
cout<<" "<<x[i]; // same as writing *(x+i)
// now that our work with array is over let us delete the memory allocated
delete [] x; // memory allocated with new operator stands released
}//end of main
// Fn definition
template<class T>
T FindMax(T x[], int n)
{ T max;
int i;
max=T(); // *x is the value of 1 element
for(i=1;i<n;i++)
{ if (max<*(x+i))
max=*(x+i);
}
return max;
} // end of FindMax
template<class T>
void SortArray( T *a ,int n)
{ int i,j; // i for outer loop j for inner loop and temp for swapping
T temp=T();
for ( i=0; i< n-1; i++) // last value need not be sorted
{
// find the smallest of remaining numbers and exchange it with
for ( j=i+1; j< n; j++)
{ if (*(a+j) < *(a+i))
{ // swap
temp=*(a+i);
*(a+i)=*(a+j);
*(a+j)=temp;
}
}
}
}
/*output : how many elements in your array :6
value for 1element:32
value for 2element:43
value for 3element:34
value for 4element:65
value for 5element:67
value for 6element:12
The entered array is….
32 43 34 65 67 12
maximum value of given array=67
The sorted array is….
12 32 34 43 65 67
You remember the treasure hunt game we all have played at some time or the other. In a first clue, we would receive a chit that gives clues regarding a second address at which the second clue or treasure is kept. Pointer to pointer can be viewed as pointer to an address, i.e. an address that points to another address. We can recover the value from the second address. For example, consider a two-dimensional matrix.
Let us say that you have a two-dimensional array ‘a’ with 12 rows and 20 columns.
Then we can declare it as:
int a[12][20]
or
as a one-dimensional array using pointers. For example:
int *a[20]
We have learnt in Section 9.4.4 that we can also depict the above a as pointer to pointer ** a. We have shown deployment of dynamic memory allocation techniques in Example 9.4.
When will the pointer to pointer be useful? An array or function is known by its name. We have also learnt by now that name is address. Symbol Address Table stores names and also address allocation for functions, arrays, variables, etc. Now in situations wherein there is a need to delete a first entry like the first element of the array or there is a need to add an element in the front, a normal pointer would entail changing of name in the symbol address table and entail in fructuous work. A pointer to pointer would isolate names and addresses stored by the system and hence adding in the front and deletion would become less cumbersome.
In our next example, we will demonstrate the creation and usage of dynamic memory using new operators. We will read a 2 x 2 matrix. First, we will allocate dynamic memory for rows and then we will allocate for columns of each row.
We will use try and catch blocks. This feature will be explained in detail in the chapter on errors and exceptions, but for now, we will introduce the concept in brief here. When an error occurs during the execution of a program, due to non-availability of resources, normally the program stops execution and reports the error or exception. Try and catch blocks provide a way out for the programmer to take corrective steps for the errors and exceptions that occur during run time. Try block will allocate heap memory during run time. If it fails due to nonavailability of memory or for any other reason, then it will throw the exception object. Catch block will catch the exception thrown by try block and take remedial measures.
Example 9.7: matptrptr.cpp A Program for Reading and Printing of Matrix with Dynamic Memory Allocation Using Pointer to Pointer
#include<iostream>
using namespace std;
// functional prototype declarations
void ReadMatrix( int **A,int m , int n);
void PrintMatrix( int **A , int m , int n);
void main()
{ int m,n;
int **A=0; // A is a pointer to pointer
cout<<”Enter the order of matrix <m,n> :”;
cin>>m>>n;
/* Now allocate dyn memory. First allocate to rows
Then allocate to columns. We will use try and catch blocks.
Try will allocate dyn memory. If it fails due to non-availability of memory then it will throw the exception object.
Catch block will catch the exception thrown by try block and take
remedial measures. */
try
{ A=new int * [m]; // dynamic memory for row allocation
for (int i=0;i<m;i++)
A[i]=new int[n]; // dynamic memory for columns
}
catch (bad_alloc)
{ cout<<”
bad allocation”<<endl;
exit(1);
}
ReadMatrix(A,m,n);
printf(“The elements of the Matrix are:
”);
PrintMatrix(A,m,n);
} /*end of main*/
void ReadMatrix( int **A, int m,int n)
{ int i,j;
cout<<”Enter the elements :”;
for(i=0;i<m;i++)
{ for(j=0;j<n;j++)
cin>>A[i][j]; /*input elements*/
}
}//end of ReadMatrix
void PrintMatrix( int **A, int m,int n)
{ int i,j;
for(i=0;i<m;i++)
{ for(j=0;j<n;j++)
cout<<” “<<A[i][j];
cout<<endl;
}
}
/*output: Enter the order of matrix <m,n> :2 2
Enter the elements :1 2 3 4
The elements of the Matrix are:
1 2
3 4*/
To access an element a[3][4][5]
Pointers can be stored in arrays. You already know that pointer means address, hence an array of pointers means a collection of addresses. For example, you can store a set of five pointers each pointing to a string variable like:
char * ptr[5] = { “welcome”, “to” ,”self_learning”,”C++” , ”Book” }
ptr is a dimension 5, i.e. an array of five pointers. The following example will make the concept clear:
#include<iostream>
using namespace std;
void main()
{ // array of pointers with 5 elements
char *ptr[5]={“welcome”,”to”,”self_learning”,”C++A”,”Books”};
char *x; // x is a pointer of type char
x=ptr[0]; // x now points to ptr, i.e. starting pointer in an array of pointers
for ( int i = 0 ; i< 5; i++)
cout<<”
”<< *(ptr+i)<<endl;
// following cout statements will teach you more about array of pointers
cout<<”
”<< *ptr[3]; // you can expect value of starting element in CDS i.e. C
}
/*Output:
welcome
to
self_learning
C++
Books*/
Remember ‘void’ is a data type. Usually, we will declare pointer to point to a particular type of data. For example, int * ptr or char * ptr, etc. The void can be employed if your program has multiple data types. But typecasting is essential, when the void pointer is used as shown in Figure 9.4.
Figure 9.4 Void pointer declaration, definition and reassignment
Declaration:
int x;
float salary;
void *ptr ; // pointer to void data type declaration
Definition:
ptr = & x ; // assign pointer to type integer
Usage:
Type casting the void pointer is mandatory
cout<<*(int*)ptr;
Reassignment:
ptr=&sal;
cout<< * (float*)ptr; // typecasting of ptr to float
Example 9.9: voidptr.cpp A Program to Demonstrate the Use of Void Pointers
#include<iostream>
using namespace std;
#include<iostream>
using namespace std;
void main()
{ int x=100;
float sal=2000.00;
void * ptr;// ptr is a pointer to data type void
// assign void pointer to int
ptr=&x;
cout<<”
ptr type casted to integer :”<< *(int*)ptr; // typecasting of ptr to int
// assign void pointer to float
ptr=&sal;
cout<<”
ptr type casted to float :”<<*(float*)ptr; // typecasting of ptr to float
}//end of program
/*Output : ptr type casted to integer :100
ptr type casted to float :2000*/
We are aware that pointers are addresses and provide us a fast access to memory and data manipulation. But there are issues of safe operation and data integrity. There are situations wherein we want that data should not be altered. In such cases, we would have declared that data as constant. The main advantage of pointers is that they can be reassigned. This feature allows us to navigate through the array or memory, etc. But there are situations when we need the pointers to be constant, i.e. they should not be reassigned. In such cases, we would declare const pointers.
Thus, there are two combinations involved, i.e. pointer type and data type. Each type can have two variations of data type: constant and normal. Therefore, we can have a total of four variations in the declaration of variables. These are shown below:
For example, let us say we have two variables declared as
int val = 25;
const float PI=3.14159;
Pointer to data // normal pointer and normal data
int *x=& val; Pointer to const data // y is a pointer to constant float. It cannot be changed const float * y=&PI; Const pointer to data // constant pointer to int data type. Pointer cannot be reassigned int * const x=& val; Const pointer to a const data // constant pointer to constant data type. Hence value cannot be changed // and pointer cannot be reassigned const float * const z=& PI
Example 9.10: Pointers Constant Data and Constant Pointers. Constructors and Destructors of a Class
// pointer to int
int val = 25; // int variable
int *ptr = & val ; // ptr is a normal pointer
cout<<++(*ptr); // output 26
cout<<++ptr; // ptr is incremented
// constant pointer to int
int const * cptr = & val; // cptr is constant pointer to int
cout<<++(*cptr); // Allowed . output 26
cout<<++cptr; // Not allowed . cptr cannot be incremented
// pointer to constant float PI
const float PI=3.14159; // float variable PI declared as constant
const float * cfptr = &PI; // cfptr is pointer to const data type float
cout<<++(*cfptr); // Not Allowed as *cfptr is constant
cout<<++cfptr; // Allowed . Increments cfptr
// constant pointer to constant float PI
const float * const cfptc = & PI ; // cfptr is const pointer to const data
cout<<++(*cfptr); // Not Allowed as *cfptr is constant
cout<<++cfptr; // Not Allowed . cfptr is constant.
We are aware a name means an address. Like array, name is address of the array. Hence, we can call it as pointer to an array. Function name likewise is an address. We can think of it as a pointer to a constant. At that address, the code for the function is stored.
Pointer to function hence means pointer to a constant pointer.
int Findmax( int a[] , int n); // A function is declared
int (*ptrfun ) (int) ; // a pointer to function i.e. ptrfun is created
ptrfun = & FindMax ; // pointer to function is assigned to FindMax function
Note that in the statement int (*ptrfun ) (int) ; the function takes int as argument and returns int data type.
Example 9.11: ptrtofun.cpp. Program to Demonstrate Use of Pointers to Function
#include<iostream>
using namespace std;
void FindTriangle(float &a , float & b );
void FindRect(float &a , float & b );
void (*funptr) ( float & , float & ); // ptr to function
void main()
{ float x= 25.0 , y=50.0;
int choice;
cout<<"
Enter your choice .. < 0 to quit : 1 for Triangle : 2 for Rectangle >";
cin>>choice;
while ( choice !=0)
{ switch (choice)
case 0 : cout<<"
exiting the programme…."<<endl;
exit(0);
case 1 : funptr = FindTriangle; break;
case 2 : funptr=FindRect; break;
}// end of switch
funptr(x,y);
cout<<"
Enter your choice .. < 0 to quit : 1 for Triangle : 2 for Rectangle >";
cin>>choice;
}//end of while
}//end of main
//Fn definitions
void FindTriangle( float &a , float &b)
{cout<<"
Area of the Triangle = "<< 0.5*a*b << endl;}
void FindRect( float &a , float &b)
{cout<<"
Area of the Rectangle = "<< a*b << endl;}
/*Output : Enter your choice .. < 0 to quit : 1 for Triangle : 2 for Rectangle >1
Area of the Triangle = 625
Enter your choice .. < 0 to quit : 1 for Triangle : 2 for Rectangle >2
Area of the Rectangle = 1250
Enter your choice .. < 0 to quit : 1 for Triangle : 2 for Rectangle >0*/
C++ gives us an additional facility called reference. A reference is an alias or another name to a variable. Figure 9.5 shows usage of reference.
Figure 9.5 Reference x and rx refer to the same location 2513 and value 25
Reference operator &: It has two uses
&x ; // evaluates the address of x
int & rx = x ; implies that rx is a reference of type int
Example 9.12: ptrtofun.cpp. 6 ref1.cpp Program to Introduce Reference Concepts
#include<iostream>
using namespace std;
void main()
{ int age1=50;
int age2=18;
//create a reference to age1 i.e. an alias by name rage to age1
int & rage=age1; //rage is an alias or another name to age1
cout<<”
age1 “<< age1<<” ”<<”&age1 “<< &age1<<endl; // displays address of age1
cout<<”
age1 with rage”<< rage<<” ”<<”&rage “<< &rage<<endl;
cout<<”
both rage and age1 must have same addresses..”<<endl;
/* you cannot reassign references like you did for pointers. If you do, the original assigned data will be lost*
rage = age2;
cout<<”
wehave forcibly reassigned a reference to “;
cout<<”
another variable. Rage is an alias of age1.”;
cout<<”
Therefore age1 will now have value of age2.”<<endl;
cout<<”
age1 “<< age1<<” ”<<”&age1 “<< &age1<<endl;
cout<<”
age2 “<< age2<<” ”<<”&age2 “<< &age2<<endl;
cout<<”
rage assigned to age2 but value it hold is age1 :”<<rage<<endl;
}//end of main
/*Output : age1 50 &age1 0012FF7C
age1 with rage50 &rage 0012FF7C
both rage and age1 must have same addresses..
we have forcibly reassigned a reference to
another variable. Rage is an alias of age1.
Therefore age1 will now have value of age2.
age1 18 &age1 0012FF7C
age2 18 &age2 0012FF78
rage assigned to age2 but value it holds is age1 :18*/
Pointers are used when you have to reassign. For example, if you are using an array that stores values at contiguous memory locations, you will need to increment the pointer to refer to the next element of the array. But pointers, though quick acting , have inherent dangers associated with them like memory leak, memory crash, dangling pointers, etc.
References are aliases – another name for variables. They cannot be reassigned. If you insist and reassign, as reference is an alias, the first variable will be assigned with reassigned variables value.
Common advantages of both pointers and references. Both forward only addresses to function, i.e. they employ pass by reference technique. Hence, there are no overhead like making copies of variables and objects while passing these items to a function. Function can return more than one value.
References offer a clean efficient and risk and error-free environment and hence it is the experienced programmers first choice. We will present the advanced concepts involved with references through a series of programs in our chapter on objects. References offer risk-free and efficient programming. To start with, recall how PtrSwap program in Example 9.2 ensured that changes made in function reflected in the main program. In our next example, we have shown how we can achieve the same result by using pass by reference.
Example 9.13: RefSwap.cpp. A Program to Swap Values by Using References Concepts
#include<iostream>
using namespace std;
// declaration of function prototypes
void RefSwap ( int &a , int & b); // Call by Ref. a & b are pointers by def.
void main()
{ int x=5, y=10;
// call by reference using reference. Note that we have to send reference
//In prototype we have promised to send references like &a and &b
//i.e. addresses of x & y . Hence we will pass x and y.
RefSwap(x,y);
cout<<”
after call by ref using References :”<<endl;
cout<<”x value after RefSwap:”<<x<<endl;
cout<<”y value after RefSwap:”<<y<<endl;
}//end of main
// Function definitions
void RefSwap ( int &a, int &b)
{ // a & b are references . Hence we need ordinary variable temp
int temp; temp=a; a=b; b=temp;
cout<<”
inside RefSwap using reference :”<<endl;
cout<<”x value inside RefSwap:”<<a<<endl;
cout<<”y value inside RefSwap:”<<b<<endl;
}
/*Output:
inside RefSwap using reference :
x value inside RefSwap:10
y value inside RefSwap:5
after call by ref using References :
x value after RefSwap:10
y value after RefSwap:5 */
Example 9.14: RefSwap.cpp. A Program to Swap Values by Using References Concepts
In this example, we will show how to return a reference from a function FindLarge. We declare a function prototype as double & FindLarge(double &r, double &s).
The function finds the largest of the two double quantity and returns a reference to largest, in this case to m. Also observe the working of FindLarge (k, m)=10 ; & FindLarge (k, m) ++; statements.
#include <iostream>
using namespace std;
double & FindLarge(double &r, double &s);
int main ()
{ double k=5, m=9;
cout <<" Given Values k: " << k <<" : m: " << m << endl;
cout <<"
Values after FindLarge (k, m) : "<<FindLarge (k, m)<<endl;
cout <<" Values k: " << k <<" : m: " << m << endl; //output 9
cout << endl;
FindLarge (k, m)=10; // largest is m=9 ,it is replaced by 10 .
cout <<"
Values after FindLarge (k, m) = 10"<<endl;
cout <<" Values k: " << k <<" : m: " << m << endl; //output 3 & 10
cout << endl;
FindLarge (k, m) ++;
cout <<"
Values after FindLarge (k, m)++"<<endl;
cout <<" Values k: " << k <<" : m: " << m << endl; //output 3 & 11
cout << endl;
return 0;
}
double & FindLarge(double &r, double &s)
{if (r > s) return r;
else return s;
}
/*output :Given Values k: 5 : m: 9
Values after FindLarge (k, m): 9
Values k: 5 : m: 9
Values after FindLarge (k, m)=10
Values k: 5 : m: 10
Values after FindLarge (k, m)++
Values k: 5 : m: 11 :*/
3.144.41.229