Introduction
Pointers to pointers (double pointers) in C++ are used to store the address of another pointer. This level of indirection can be useful in various scenarios, such as managing dynamic memory for multi-dimensional arrays, passing pointers to functions that need to modify the pointer itself, and handling complex data structures.
Defining and Using Pointers to Pointers
Basic Example
To define a pointer to a pointer, use the following syntax:
type** ptr;
Example: Pointer to a Pointer
#include <iostream>
using namespace std;
int main() {
int value = 42;
int* ptr = &value; // Pointer to int
int** ptrPtr = &ptr; // Pointer to pointer to int
// Accessing the value using pointers
cout << "Value: " << value << endl;
cout << "Value through ptr: " << *ptr << endl;
cout << "Value through ptrPtr: " << **ptrPtr << endl;
// Modifying the value using pointers
**ptrPtr = 100;
cout << "Modified value: " << value << endl;
return 0;
}
Output
Value: 42
Value through ptr: 42
Value through ptrPtr: 42
Modified value: 100
Explanation
int* ptr = &value;
defines a pointerptr
that points tovalue
.int** ptrPtr = &ptr;
defines a pointer to a pointerptrPtr
that points toptr
.**ptrPtr
accesses the value ofvalue
through two levels of indirection.- Modifying
**ptrPtr
changes the value ofvalue
.
Dynamic Memory Allocation for Multi-dimensional Arrays
Pointers to pointers are often used to dynamically allocate memory for 2D arrays.
Example: Dynamic 2D Array Allocation
#include <iostream>
using namespace std;
int main() {
int rows = 3, cols = 3;
// Allocate memory for a 2D array
int** matrix = new int*[rows];
for (int i = 0; i < rows; i++) {
matrix[i] = new int[cols];
}
// Initialize the 2D array
int value = 1;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = value++;
}
}
// Print the 2D array
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
cout << matrix[i][j] << " ";
}
cout << endl;
}
// Deallocate memory
for (int i = 0; i < rows; i++) {
delete[] matrix[i];
}
delete[] matrix;
return 0;
}
Output
1 2 3
4 5 6
7 8 9
Explanation
int** matrix = new int*[rows];
allocates memory for an array of pointers.- The loop
for (int i = 0; i < rows; i++) { matrix[i] = new int[cols]; }
allocates memory for each row. - The nested loops initialize and print the 2D array.
- The memory is deallocated using
delete[]
for each row and then for the array of pointers.
Passing Pointers to Pointers to Functions
Passing pointers to pointers to functions allows the function to modify the original pointer.
Example: Modifying a Pointer in a Function
#include <iostream>
using namespace std;
// Function to allocate memory and assign a value
void allocateAndAssign(int** ptr, int value) {
*ptr = new int;
**ptr = value;
}
int main() {
int* ptr = nullptr;
// Allocate memory and assign a value through the function
allocateAndAssign(&ptr, 42);
// Print the assigned value
cout << "Value: " << *ptr << endl;
// Deallocate memory
delete ptr;
return 0;
}
Output
Value: 42
Explanation
- The function
allocateAndAssign(int** ptr, int value)
takes a pointer to a pointer as an argument. *ptr = new int;
allocates memory for an integer and assigns the address to the pointer.**ptr = value;
assigns the value to the allocated memory.- The original pointer is modified by the function, and the assigned value is printed in
main
.
Example Programs
Example 1: Managing a Dynamic 2D Array with Functions
#include <iostream>
using namespace std;
// Function to allocate memory for a 2D array
int** allocate2DArray(int rows, int cols) {
int** array = new int*[rows];
for (int i = 0; i < rows; i++) {
array[i] = new int[cols];
}
return array;
}
// Function to deallocate memory for a 2D array
void deallocate2DArray(int** array, int rows) {
for (int i = 0; i < rows; i++) {
delete[] array[i];
}
delete[] array;
}
int main() {
int rows = 3, cols = 3;
// Allocate memory for a 2D array
int** matrix = allocate2DArray(rows, cols);
// Initialize the 2D array
int value = 1;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = value++;
}
}
// Print the 2D array
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
cout << matrix[i][j] << " ";
}
cout << endl;
}
// Deallocate memory
deallocate2DArray(matrix, rows);
return 0;
}
Output
1 2 3
4 5 6
7 8 9
Explanation
- The
allocate2DArray
function allocates memory for a 2D array and returns a pointer to the array. - The
deallocate2DArray
function deallocates the memory for the 2D array. - The 2D array is initialized, printed, and deallocated in the
main
function.
Example 2: Dynamic 3D Array Allocation and Deallocation
#include <iostream>
using namespace std;
// Function to allocate memory for a 3D array
int*** allocate3DArray(int rows, int cols, int depth) {
int*** array = new int**[rows];
for (int i = 0; i < rows; i++) {
array[i] = new int*[cols];
for (int j = 0; j < cols; j++) {
array[i][j] = new int[depth];
}
}
return array;
}
// Function to deallocate memory for a 3D array
void deallocate3DArray(int*** array, int rows, int cols) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
delete[] array[i][j];
}
delete[] array[i];
}
delete[] array;
}
int main() {
int rows = 2, cols = 2, depth = 2;
// Allocate memory for a 3D array
int*** array = allocate3DArray(rows, cols, depth);
// Initialize the 3D array
int value = 1;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
for (int k = 0; k < depth; k++) {
array[i][j][k] = value++;
}
}
}
// Print the 3D array
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
for (int k = 0; k < depth; k++) {
cout << "Element [" << i << "][" << j << "][" << k << "]: " << array[i][j][k] << endl;
}
}
}
// Deallocate memory
deallocate3DArray(array, rows, cols);
return 0;
}
Output
Element [0][0][0]: 1
Element [0][0][1]: 2
Element [0][1][0]: 3
Element [0][1][1]: 4
Element [1][0][0]: 5
Element [1][0][1]: 6
Element [1][1][0]: 7
Element [1][1][1]: 8
Explanation
- The
allocate3DArray
function allocates memory for a 3D array and returns a pointer
to the array.
- The
deallocate3DArray
function deallocates the memory for the 3D array. - The 3D array is initialized, printed, and deallocated in the
main
function.
Conclusion
Pointers to pointers in C++ provide a powerful way to manage dynamic memory allocation for multi-dimensional arrays, modify pointers through functions, and handle complex data structures. This chapter covered the basics of defining and using pointers to pointers, dynamic memory allocation for 2D and 3D arrays, and passing pointers to pointers to functions. Example programs demonstrated practical applications of pointers to pointers, including managing dynamic 2D and 3D arrays and modifying pointers in functions. Understanding how to use pointers to pointers effectively is essential for writing efficient and flexible C++ programs.