Let us study the below example:
File: "db1.c"
/* Double pointer program */
#include<stdio.h>
#include<stdlib.h>
int main( )
{
int x1 = 100 ;
int x2 = 200 ;
int* ptr1 ;
int** doublePtr ;
ptr1 = &x1 ;
doublePtr = &ptr1 ;
printf( "%d\n" , *ptr1 ) ;
//2 Levels of indirection
printf( "%d\n" , **doublePtr ) ;
*doublePtr = &x2 ;
printf( "%d\n" , **doublePtr ) ;
printf( "%d\n" , *ptr1 ) ;
return(1) ;
}
/*
RAM
x1 0 100
x2 5 200
ptr1 10 0 --> 5
doublePtr 15 10
*/
Output:
100
100
200
200
In the above example we have a pointer "ptr1" . A pointer variable will always hold an address. This is true regardless of what the pointer type will be. It is always helpful to draw a diagram in the RAM to understand pointers. We do not need the exact RAM address that will be assigned when the program is run. We need a conceptual understanding and the diagram can help with that. Initially the pointer "ptr1" holds the address of the variable "x1" . We define the double pointer with the declaration:
int** doublePtr ;
What is the above stating ? The "doublePtr" is also a pointer. It occupies space in the memory and it's value is an address.
ptr1 = & x1
We have the "ptr1 " holding the address of the variable x1 . In our conceptual diagram x1 is at the address 0 holding the value 100 and x2 is at the address 5 holding the value 200 . So the "ptr1" variable is now going to hold the address 0 . Remember "ptr1" is also a variable and thus resides at an address . In our example "ptr1" is at the address 10 .
doublePtr = &ptr1 ;
In the above line we are taking the address of "ptr1" and assigning it to "doublePtr". The "doublePtr" is also a pointer and it contains an address .
However when we apply the operation of "*doublePtr" We do not get an integer value. Instead we get another address. In the above diagram if we do "*doublePtr" we follow the "10" to the pointer variable "ptr1" where we get the value "0" . This is yet another address and we could follow it to where x1 is by another "*" . Using the notation "**doublePtr" we can obtain the value of the "x1" variable which is 100 .
Next we have the statement
cout << *ptr1 << endl ;
The above statement states that we look up the address in the "ptr1" variable which is "0" and follow that to obtain the value of "x1" which is 100 .
cout << **doublePtr << endl ;
What the "**" does is 2 levels of indirection. The first "*doublePtr" gives us "0" which is the address of x1 that ptr1 stores. Recall that "doublePtr" itself stores the address 10 ( address of ptr1 ) and with "*" we are following that. Now that we have 0 we do another "*" ( we have 2 stars in **doublePtr ) . Following 0 leads us to the value of x1 which is 100 and that gets printed out.
now we have the value of "x2" printed out and that is 200 .
1)
Run the following program on your computer and draw the RAM diagram to understand the output:
File: "db2.c"
#include<stdio.h>
#include<stdlib.h>
int main()
{
int num = 100 ;
//A normal pointer ptr1
//The below is an alternat style to declaring pointers vs
// int* ptr.
int *ptr1;
//This pointer ptr1 is a double pointer
int **double_ptr;
/* Assigning the address of variable num to the
* pointer ptr1
*/
ptr1 = &num ;
/* Assigning the address of pointer ptr1 to the
* pointer-to-pointer double_ptr
*/
double_ptr = &ptr1;
/* Possible ways to find value of variable num*/
printf("\n Value of num is: %d", num );
printf("\n Value of num using ptr1 is: %d", *ptr1 );
printf("\n Value of num using double_ptr is: %d", **double_ptr );
/*Possible ways to find address of num*/
printf("\n Address of num is: %p", &num );
printf("\n Address of num using ptr1 is: %p", ptr1 );
printf("\n Address of num using double_ptr is: %p", *double_ptr );
/*Find value of pointer*/
printf("\n Value of Pointer ptr1 is: %p", ptr1 );
printf("\n Value of Pointer ptr1 using double_ptr is: %p", *double_ptr );
/*Ways to find address of pointer*/
printf("\n Address of Pointer ptr1 is:%p", &ptr1 );
printf("\n Address of Pointer ptr1 using double_ptr is:%p", double_ptr );
/*Double pointer value and address*/
printf("\n Value of Pointer double_ptr is:%p", double_ptr );
printf("\n Address of Pointer double_ptr is:%p", &double_ptr );
return 0;
}
2)
What does the following print ?
#include<stdio.h>
#include<stdlib.h>
int main()
{
int x1 = 100 ;
int x2 = 200 ;
int* ptr1 = &x1 ;
int* ptr2 = &x2 ;
int** dblPtr1 = &ptr1 ;
int** dblPtr2 = &ptr2 ;
**dblPtr1 = x2 ;
**dblPtr2 = x1 ;
printf( "%d %d\n" , *ptr1, *ptr2 ) ;
printf( "%d %d\n" , x1 , x2 ) ;
return ( 1 ) ;
}
1)
Value of num is: 100
Value of num using ptr1 is: 100
Value of num using double_ptr is: 100
Address of num is: 0xffffcc1c
Address of num using ptr1 is: 0xffffcc1c
Address of num using double_ptr is: 0xffffcc1c
Value of Pointer ptr1 is: 0xffffcc1c
Value of Pointer ptr1 using double_ptr is: 0xffffcc1c
Address of Pointer ptr1 is:0xffffcc10
Address of Pointer ptr1 using double_ptr is:0xffffcc10
Value of Pointer double_ptr is:0xffffcc10
Address of Pointer double_ptr is:0xffffcc08
2)
#include<stdio.h>
#include<stdlib.h>
int main()
{
int x1 = 100 ;
int x2 = 200 ;
int* ptr1 = &x1 ;
int* ptr2 = &x2 ;
int** dblPtr1 = &ptr1 ;
int** dblPtr2 = &ptr2 ;
**dblPtr1 = x2 ;
**dblPtr2 = x1 ;
printf( "%d %d\n" , *ptr1, *ptr2 ) ;
printf( "%d %d\n" , x1 , x2 ) ;
return ( 1 ) ;
}
Output:
200,200
200,200