0
0
Cprogramming~15 mins

Pointers to pointers in C - Deep Dive

Choose your learning style9 modes available
Overview - Pointers to pointers
What is it?
Pointers to pointers are variables that store the address of another pointer. Instead of pointing directly to a value, they point to a pointer that then points to the value. This allows multiple levels of indirection, which can be useful for managing complex data structures or modifying pointers themselves. In C, this is written using double asterisks, like **ptr.
Why it matters
Without pointers to pointers, it would be difficult to change the address stored in a pointer from inside a function or to create complex data structures like dynamic arrays of strings. They let programmers write flexible and powerful code that can manipulate memory addresses at multiple levels. Without this concept, many advanced programming tasks would be cumbersome or impossible.
Where it fits
Before learning pointers to pointers, you should understand basic pointers and how they store addresses of variables. After mastering pointers to pointers, you can explore dynamic memory allocation, multi-dimensional arrays, and advanced data structures like linked lists and trees.
Mental Model
Core Idea
A pointer to a pointer is like a signpost pointing to another signpost, which then points to the actual destination.
Think of it like...
Imagine a treasure map where one map points to another map, and only the second map shows the treasure location. The first map is the pointer to the pointer, guiding you to the second map, which finally leads to the treasure.
Value: 42
Address: 0x100

Pointer (p) ──> 0x100 (points to Value)
Pointer to Pointer (pp) ──> &p (points to Pointer p)

Memory layout:
+---------+       +---------+       +-------+
|   pp    |  -->  |    p    |  -->  |  42   |
+---------+       +---------+       +-------+
Build-Up - 7 Steps
1
FoundationUnderstanding basic pointers
🤔
Concept: Learn what a pointer is and how it stores the address of a variable.
In C, a pointer holds the memory address of a variable. For example: int x = 10; int *p = &x; // p points to x Here, p stores the address of x. Using *p gives the value of x.
Result
You can access and modify the value of x through the pointer p.
Understanding that pointers hold addresses is the foundation for grasping pointers to pointers.
2
FoundationPointer variables and addresses
🤔
Concept: Learn how to declare pointers and get their addresses.
Every variable has an address in memory. A pointer variable stores this address. You can also get the address of a pointer itself: int x = 5; int *p = &x; int **pp = &p; // pp points to p Here, pp stores the address of p, which stores the address of x.
Result
You now have a pointer to a pointer, allowing two levels of indirection.
Knowing that pointers themselves have addresses lets you create pointers to pointers.
3
IntermediateAccessing values via double pointers
🤔Before reading on: do you think **pp gives the value of x or the address of x? Commit to your answer.
Concept: Learn how to use double dereferencing to get the original value through a pointer to a pointer.
Given: int x = 7; int *p = &x; int **pp = &p; *pp gives the value of p (address of x). **pp gives the value of x. Example: printf("%d", **pp); // prints 7
Result
Using **pp accesses the original value stored in x through two levels of pointers.
Understanding double dereferencing is key to using pointers to pointers effectively.
4
IntermediateModifying pointers via pointers to pointers
🤔Before reading on: Can you change where p points by modifying *pp? Yes or No? Commit to your answer.
Concept: Pointers to pointers allow changing the address stored in a pointer from another place in code.
Example: int a = 10, b = 20; int *p = &a; int **pp = &p; *pp = &b; // changes p to point to b Now, *p is 20 instead of 10.
Result
You can change the pointer p itself by modifying *pp, showing how pointers to pointers enable indirect pointer manipulation.
Knowing you can modify pointers through pointers to pointers unlocks powerful programming techniques.
5
IntermediatePointers to pointers with arrays
🤔
Concept: Understand how pointers to pointers can represent arrays of pointers, like arrays of strings.
Example: char *names[] = {"Alice", "Bob", "Carol"}; char **pp = names; Here, pp points to the first element of the array, which is a pointer to a string. You can access names like: printf("%s", pp[1]); // prints Bob
Result
Pointers to pointers let you handle arrays of pointers, useful for lists of strings or dynamic arrays.
Seeing pointers to pointers as arrays of pointers helps understand common C data structures.
6
AdvancedUsing pointers to pointers in function arguments
🤔Before reading on: Can a function change a pointer's address by receiving a pointer to pointer? Yes or No? Commit to your answer.
Concept: Passing pointers to pointers to functions allows the function to modify the original pointer's address.
Example: void changePointer(int **pp) { static int y = 50; *pp = &y; // changes the pointer passed in } int x = 10; int *p = &x; changePointer(&p); printf("%d", *p); // prints 50
Result
Functions can modify pointers outside their scope by using pointers to pointers.
Understanding this enables writing functions that can update pointers, not just values.
7
ExpertCommon pitfalls and memory safety with double pointers
🤔Before reading on: Does using pointers to pointers increase risk of memory errors? Yes or No? Commit to your answer.
Concept: Pointers to pointers add complexity and can cause bugs like dangling pointers or memory leaks if not managed carefully.
Because pointers to pointers involve multiple levels of indirection, mistakes like dereferencing null or uninitialized pointers become more common. Example of a bug: int **pp = NULL; printf("%d", **pp); // crashes because pp is NULL Proper checks and initialization are critical.
Result
Using pointers to pointers requires careful memory management to avoid crashes and bugs.
Knowing the risks helps write safer, more robust code when using pointers to pointers.
Under the Hood
In C, every variable and pointer has a memory address. A pointer stores the address of another variable. A pointer to a pointer stores the address of a pointer variable. When the program runs, dereferencing a pointer fetches the value at the stored address. Double dereferencing fetches the value at the address stored in the pointer pointed to. The compiler uses the type information to calculate how many bytes to read or write at each address.
Why designed this way?
C was designed to give programmers direct control over memory for efficiency and flexibility. Pointers to pointers allow manipulation of pointers themselves, enabling dynamic data structures and complex memory management. Alternatives like references in other languages hide this complexity but reduce control. C's design trades safety for power and speed.
+-----------------+       +-----------------+       +------------+
| Pointer to Ptr   |  -->  | Pointer (p)     |  -->  | Value (x)  |
| (int **pp)       |       | (int *p)        |       | (int x)    |
+-----------------+       +-----------------+       +------------+

Dereference steps:
**pp = value at address stored in p
*pp = address stored in p
pp = address of p
Myth Busters - 4 Common Misconceptions
Quick: Does *pp give the value of the original variable or the address of the pointer? Commit to your answer.
Common Belief:Many think *pp gives the original variable's value directly.
Tap to reveal reality
Reality:*pp gives the address stored in the pointer p, not the original variable's value. You need **pp to get the original value.
Why it matters:Confusing *pp and **pp leads to wrong data access and bugs that are hard to debug.
Quick: Can you safely dereference a pointer to pointer without checking if it is NULL? Commit to yes or no.
Common Belief:Some believe pointers to pointers are always safe to dereference if the first pointer is valid.
Tap to reveal reality
Reality:If the pointer to pointer is NULL or uninitialized, dereferencing causes crashes or undefined behavior.
Why it matters:Ignoring null checks causes program crashes and security vulnerabilities.
Quick: Does passing a pointer to pointer to a function allow changing the original pointer? Commit to yes or no.
Common Belief:Some think functions cannot change the original pointer's address even if passed a pointer to pointer.
Tap to reveal reality
Reality:Passing a pointer to pointer allows the function to modify the original pointer's address, changing what it points to.
Why it matters:Misunderstanding this limits function design and causes bugs when pointers don't update as expected.
Quick: Does using pointers to pointers automatically manage memory safely? Commit to yes or no.
Common Belief:Some assume pointers to pointers handle memory safely by default.
Tap to reveal reality
Reality:Pointers to pointers add complexity and require careful manual memory management to avoid leaks and errors.
Why it matters:Overlooking this leads to memory leaks, crashes, and unstable programs.
Expert Zone
1
Pointers to pointers can be used to simulate pass-by-reference for pointers in C, enabling functions to modify pointer arguments directly.
2
In multi-dimensional arrays, pointers to pointers do not always represent contiguous memory, which can cause subtle bugs if misunderstood.
3
Pointer arithmetic on pointers to pointers must be done carefully, as it moves by the size of the pointer type, not the pointed-to data.
When NOT to use
Avoid pointers to pointers when simpler data structures or references (in other languages) suffice. For multi-dimensional arrays, consider using arrays of arrays or structs to ensure memory contiguity. Use smart pointers or higher-level abstractions in modern languages to reduce manual memory errors.
Production Patterns
In real-world C code, pointers to pointers are common in APIs that allocate or modify pointers, such as dynamic array resizing or linked list manipulation. They are also used in command-line argument handling (char **argv) and complex data structures like trees and graphs where nodes hold pointers to other pointers.
Connections
References in C++
Pointers to pointers in C provide similar functionality to references to pointers in C++, enabling indirect modification of pointers.
Understanding pointers to pointers clarifies how references work under the hood and why C++ introduced references for safer pointer manipulation.
Linked lists in data structures
Pointers to pointers are often used to manipulate linked list nodes, especially when inserting or deleting nodes.
Knowing pointers to pointers helps understand how linked lists maintain and update node connections efficiently.
Nested function calls in mathematics
Just as pointers to pointers add a level of indirection, nested functions apply functions to functions, adding layers of abstraction.
Recognizing layers of indirection in programming and math helps grasp complex abstractions and recursive structures.
Common Pitfalls
#1Dereferencing a null pointer to pointer causes a crash.
Wrong approach:int **pp = NULL; printf("%d", **pp); // crashes
Correct approach:int **pp = NULL; if (pp != NULL && *pp != NULL) { printf("%d", **pp); }
Root cause:Not checking if the pointer to pointer or the pointer it points to is NULL before dereferencing.
#2Confusing *pp and **pp leads to wrong data access.
Wrong approach:int x = 5; int *p = &x; int **pp = &p; printf("%d", *pp); // prints address, not value
Correct approach:printf("%d", **pp); // prints 5
Root cause:Misunderstanding levels of indirection and dereferencing operators.
#3Trying to increment a pointer to pointer as if it points to data directly.
Wrong approach:int **pp; pp++; // moves pointer incorrectly if not intended
Correct approach:Use pointer arithmetic carefully, knowing pp points to a pointer, not data. // Example: pp++ moves to next pointer in an array of pointers
Root cause:Not recognizing that pointer arithmetic depends on the type pointed to.
Key Takeaways
Pointers to pointers store the address of a pointer, adding a second level of indirection.
Double dereferencing (**pp) accesses the original value through two layers of pointers.
They enable functions to modify pointers themselves by passing pointer addresses.
Using pointers to pointers requires careful memory management to avoid crashes and bugs.
Understanding pointers to pointers is essential for advanced C programming and data structure manipulation.