Double Pointers
A double pointer is a pointer that points to another pointer. In other words, it is a pointer to a pointer.
Declaration:
int **ptr;
Why Use Double Pointers?
- Dynamic memory allocation: Double pointers are used when we need to allocate memory dynamically to a pointer or pass a pointer to a pointer to a function.
- Modifying original pointer: When you need to modify the original pointer inside a function, a double pointer allows the function to access and change the pointer itself, not just the value it points to.
Example: Simple Double Pointer:
#include <iostream>using namespace std;
int main() { int x = 10; int *ptr = &x; // pointer to x int **dptr = &ptr; // double pointer pointing to ptr
cout << "Value of x: " << x << endl; // Output: 10 cout << "Value of *ptr (x): " << *ptr << endl; // Output: 10 cout << "Value of **dptr (x): " << **dptr << endl; // Output: 10
cout << "Address of ptr: " << dptr << endl; // Address of ptr cout << "Address of x: " << ptr << endl; // Address of x}
Key Points:
- Single Pointer: *ptr holds the address of a variable (e.g., x).
- Double Pointer: **dptr holds the address of a pointer (e.g., ptr), which in turn points to a variable.
Use Case 1: Passing Pointer to a Function (Pass by Reference):
#include <iostream>using namespace std;
void updatePointer(int **dptr) { **dptr = 20; // Modifying the value of x through double pointer}
int main() { int x = 10; int *ptr = &x;
cout << "Before update: " << *ptr << endl; // Output: 10
updatePointer(&ptr);
cout << "After update: " << *ptr << endl; // Output: 20
return 0;}
- The function updatePointer takes a double pointer **dptr and updates the value of x by dereferencing twice (**dptr).
Use Case 2: Dynamic Memory Allocation:
#include <iostream>using namespace std;
int main() { int rows = 3, cols = 4;
// Creating a 2D array using double pointers int **arr = new int*[rows];
for (int i = 0; i < rows; i++) { arr[i] = new int[cols]; // Allocating memory for each row }
// Initializing the 2D array for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { arr[i][j] = i + j; } }
// Displaying the 2D array for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { cout << arr[i][j] << " "; } cout << endl; }
// Deallocating memory for (int i = 0; i < rows; i++) { delete[] arr[i]; } delete[] arr;
return 0;}
Output:
0 1 2 31 2 3 42 3 4 5
Explanation:
- We first create an array of pointers (
int **arr
) where each pointer points to an array (representing rows). - Then, each row is dynamically allocated a new array (representing columns). After using the 2D array, we deallocate memory by deleting each row and finally the array of pointers.
Key Points to Remember:
- Dereferencing:
- *ptr: Accesses the value pointed to by ptr.
- **dptr: Accesses the value pointed to by the pointer *dptr.
- Pointer to Pointer:
- A double pointer is used to store the address of another pointer.
- Memory Allocation:
- Dynamic memory allocation with 2D arrays requires double pointers.
Other Example:
#include <iostream>using namespace std;
// Function to update double pointervoid update(int **p2) { p2 = p2 + 1; // This only updates the local copy of the pointer in this function, does not affect the original p2 in main // No change in the actual pointer that is passed from main
//*p2 = *p2 + 1; // This increments the pointer (p) that p2 points to, effectively changing where p points // This would change the address stored in p (no effect in this specific case as it's commented)
**p2 = **p2 + 1; // This increments the actual value that p2 points to (which is `i` from main). // Change occurs, as it modifies the value at the address `i`}
// Function to update value through single pointervoid update(int *p) { *p = (*p) * 2; // This doubles the value stored in the variable `i` (if this function was called for `i`)}
// Function to increment value through double pointervoid increment(int **p) { ++(**p); // This increments the value pointed to by the pointer inside `p`}
int main() {
int i = 5; int* p = &i; // Pointer `p` points to variable `i` int** p2 = &p; // Pointer `p2` points to pointer `p`
cout << endl << endl <<" Sab sahi chal rha h " << endl << endl ;
// Display the value of `i` using different ways cout << i << endl; // Output: 5 (direct value of `i`) cout << *p << endl; // Output: 5 (dereferencing pointer `p`) cout << **p2 << endl; // Output: 5 (dereferencing pointer-to-pointer `p2`)
// Display the addresses of `i`, `p`, and `p2` cout << &i << endl; // Address of `i` cout << p << endl; // Address of `i` (value stored in pointer `p`) cout << *p2 << endl; // Address of `i` (value stored in pointer `p`, via dereferencing `p2`)
cout << &p << endl; // Address of pointer `p` cout << p2 << endl; // Address of pointer `p` (value stored in `p2`)
cout << endl << endl;
// Display values before calling `update` cout << "before " << i << endl; // Output: 5 (value of `i`) cout << "before " << p << endl; // Output: Address of `i` cout << "before " << p2 << endl; // Output: Address of `p`
// Call the update function update(p2); // This modifies the value of `i` through `p2`
// Display values after calling `update` cout << "after " << i << endl; // Output: 6 (value of `i` is incremented by `update`) cout << "after " << p << endl; // Output: Address of `i` (no change in `p`) cout << "after " << p2 << endl; // Output: Address of `p` (no change in `p2`)
cout << endl << endl;
// Increment using a double pointer int num = 110; int *ptr = # // Pointer `ptr` points to `num` increment(&ptr); // This increments the value of `num` using the `increment` function
cout << num << endl; // Output: 111 (value of `num` incremented by 1)
return 0;}