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 pointerptrthat points tovalue.int** ptrPtr = &ptr;defines a pointer to a pointerptrPtrthat points toptr.**ptrPtraccesses the value ofvaluethrough two levels of indirection.- Modifying
**ptrPtrchanges 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
allocate2DArrayfunction allocates memory for a 2D array and returns a pointer to the array. - The
deallocate2DArrayfunction deallocates the memory for the 2D array. - The 2D array is initialized, printed, and deallocated in the
mainfunction.
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
allocate3DArrayfunction allocates memory for a 3D array and returns a pointer
to the array.
- The
deallocate3DArrayfunction deallocates the memory for the 3D array. - The 3D array is initialized, printed, and deallocated in the
mainfunction.
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.