C++ Double Pointers Explained
Introduction to Pointers
Addresses for Your Data
Every time you create a variable in C++, the computer sets aside a small piece of memory to store its value. Think of your computer's memory as a giant street with millions of houses. Each house has a unique address. In the same way, each piece of memory has a unique address.
A pointer is simply a special type of variable that doesn't store a value like a number or a character. Instead, it stores a memory address. It's like having a piece of paper where you've written down the address of your friend's house. The paper isn't the house, but it tells you exactly where to find it.
A pointer is a variable that stores the memory address of another variable.
Pointers are useful because they allow us to work with memory directly. This can make programs more efficient and enables powerful features like dynamic memory allocation, where you can create variables while the program is running.
Declaring and Using Pointers
Working with pointers involves three key operators: *, &, and * again (it does double duty!). Let's break it down.
First, you declare a pointer using the asterisk (*). This tells the compiler that the variable will hold an address, not a regular value. The type of the pointer must match the type of the variable it will point to.
// Declares a pointer that can hold the address of an integer.
int *p_number;
// Declares a pointer that can hold the address of a character.
char *p_char;
Next, to get the memory address of a variable, you use the address-of operator (&). You can then assign this address to your pointer.
int score = 95;
// Use the address-of operator (&) to get the memory
// address of 'score' and store it in the pointer.
int *p_score = &score;
At this point, p_score doesn't contain the value 95. It contains the memory location where 95 is stored. To access the value at that memory location, we use the dereference operator, which is also an asterisk (*). When you put * in front of a pointer's name, you're saying, "Go to the address stored in this pointer and give me the value you find there."
#include <iostream>
int main() {
int score = 95;
int *p_score = &score; // p_score now points to score
// Print the value using the original variable
std::cout << score << std::endl; // Prints 95
// Print the value by dereferencing the pointer
std::cout << *p_score << std::endl; // Also prints 95
// We can also change the original value through the pointer
*p_score = 100;
// The original 'score' variable is now changed
std::cout << score << std::endl; // Prints 100
return 0;
}
Common Pitfalls
Pointers are powerful, but they require care. Two common mistakes are working with uninitialized pointers and dangling pointers.
Uninitialized Pointer
noun
A pointer that has been declared but does not yet hold a specific memory address. It points to a random, unknown location in memory.
If you try to use an uninitialized pointer, your program's behavior will be unpredictable. It might crash, or it might corrupt other data. It's good practice to initialize pointers to a special value called nullptr if you don't have a valid address for them yet.
int *p_value = nullptr; // Good practice: initialize to nullptr
// ... some code later ...
if (p_value != nullptr) {
// Only dereference if the pointer is valid
std::cout << *p_value << std::endl;
}
A dangling pointer is a pointer that points to a memory location that has already been freed or is no longer valid. This can happen when you work with memory that you allocate and deallocate yourself, a topic we'll explore in more detail later. Using a dangling pointer is just as dangerous as using an uninitialized one.
Always ensure your pointers point to valid memory before you use them. This simple rule will save you from many hard-to-find bugs.
What does a pointer variable store?
Consider the following C++ code snippet:
int value = 42;
int* ptr = &value;
What is the result of *ptr?
With these fundamentals, you're ready to start using pointers to manage memory more effectively in your C++ programs.