How do pointers-to-pointers work in C?
When might you use them?

- 59,987
- 13
- 123
- 180
-
47No not homework.... just wanted to know..coz i see it a lot when i read C code. – May 22 '09 at 11:18
-
1A pointer to pointer is not a special case of something, so I don't understand what you don't understand about void**. – akappa May 22 '09 at 11:19
-
1for 2D arrays the best example is the command line args "prog arg1 arg2" is stored char**argv. And if the caller doesnt want to allocate the memory ( the called function will allocate the memory ) – resultsway Mar 21 '13 at 22:29
-
1You have a nice example of "pointer to pointer" usage in Git 2.0: see [my answer below](http://stackoverflow.com/a/22354860/6309) – VonC Mar 12 '14 at 14:40
14 Answers
Let's assume an 8 bit computer with 8 bit addresses (and thus only 256 bytes of memory). This is part of that memory (the numbers at the top are the addresses):
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| | 58 | | | 63 | | 55 | | | h | e | l | l | o | \0 | |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
What you can see here, is that at address 63 the string "hello" starts. So in this case, if this is the only occurrence of "hello" in memory then,
const char *c = "hello";
... defines c
to be a pointer to the (read-only) string "hello", and thus contains the value 63. c
must itself be stored somewhere: in the example above at location 58. Of course we can not only point to characters, but also to other pointers. E.g.:
const char **cp = &c;
Now cp
points to c
, that is, it contains the address of c
(which is 58). We can go even further. Consider:
const char ***cpp = &cp;
Now cpp
stores the address of cp
. So it has value 55 (based on the example above), and you guessed it: it is itself stored at address 60.
As to why one uses pointers to pointers:
- The name of an array usually yields the address of its first element. So if the array contains elements of type
t
, a reference to the array has typet *
. Now consider an array of arrays of typet
: naturally a reference to this 2D array will have type(t *)*
=t **
, and is hence a pointer to a pointer. - Even though an array of strings sounds one-dimensional, it is in fact two-dimensional, since strings are character arrays. Hence:
char **
. - A function
f
will need to accept an argument of typet **
if it is to alter a variable of typet *
. - Many other reasons that are too numerous to list here.

- 5,527
- 2
- 32
- 48

- 59,965
- 13
- 127
- 133
-
7yes good example..i understand what they are..but how and when to use them is more important..now.. – May 22 '09 at 11:33
-
2Stephan did a good job reproducing, basically, the diagram in Kernighan & Richie's The C Programming Language. If you're programming C, and don't have this book and are cool with paper documentation, I highly suggest you get it, the (fairly) modest expense will pay for itself very quickly in productivity. It tends to be very clear in its examples. – J. Polfer May 22 '09 at 13:33
-
5char* c = "hello" should be const char* c = "hello". Also it's at most misleading to say that "an array is stored as the address of the first element". An array is stored as... an array. Often its name yields a pointer to its first element, but not always. About pointers to pointers, I would simply say that they are useful when a function has to modify a pointer passed as a parameter (then you pass a pointer to the pointer instead). – Bastien Léonard May 22 '09 at 20:12
-
@sheepsimulator: That's coincidental then. I did recently buy K&R, but I haven't read up to that point in the book yet :) – Stephan202 May 23 '09 at 16:10
-
@Bastien: thanks. I updated the text slightly (though one could argue that I now make improper use of the word 'reference'...) – Stephan202 May 23 '09 at 16:10
-
4Unless I'm misinterpreting this answer, it looks wrong. c is stored at 58 and points to 63, cp is stored at 55 and points to 58, and cpp is not represented in the diagram. – Thanatos May 23 '09 at 16:16
-
You are right... so many upvotes, and nobody noticed... I'll fix it right away! – Stephan202 May 23 '09 at 16:31
-
1Looks good. Than minor issue was all that was stopping me from saying: Great post. The explaination itself was excellent. Changing to an up-vote. (Perhaps stackoverflow needs to review pointers?) – Thanatos May 23 '09 at 16:54
-
Now all the problems that made me retract my upvote are fixed. So i can give you back the vote. Great :) – Johannes Schaub - litb May 24 '09 at 15:16
-
Why not say "So if the array contains elements of type t, a reference to the array usually has type t *". That will make it not abuse the word anymore. Or say "So if the array contains elements of type t, a value of that array has type t *" . That's safe to say, since in all contexts that yields a value from an array, that value has type "t*" in C, but not in contexts where a value is not generated (like "sizeof(array)", or "&array). – Johannes Schaub - litb May 24 '09 at 15:21
-
1@procrastinator: Indeed, fixed it now. (Took me several minutes until I understood what you meant... the mind is a funny thing.) – Stephan202 Mar 04 '14 at 21:17
-
1
How do pointers to pointers work in C?
First a pointer is a variable, like any other variable, but that holds the address of a variable.
A pointer to a pointer is a variable, like any other variable, but that holds the address of a variable. That variable just happens to be a pointer.
When would you use them?
You can use them when you need to return a pointer to some memory on the heap, but not using the return value.
Example:
int getValueOf5(int *p)
{
*p = 5;
return 1;//success
}
int get1024HeapMemory(int **p)
{
*p = malloc(1024);
if(*p == 0)
return -1;//error
else
return 0;//success
}
And you call it like this:
int x;
getValueOf5(&x);//I want to fill the int varaible, so I pass it's address in
//At this point x holds 5
int *p;
get1024HeapMemory(&p);//I want to fill the int* variable, so I pass it's address in
//At this point p holds a memory address where 1024 bytes of memory is allocated on the heap
There are other uses too, like the main() argument of every C program has a pointer to a pointer for argv, where each element holds an array of chars that are the command line options. You must be careful though when you use pointers of pointers to point to 2 dimensional arrays, it's better to use a pointer to a 2 dimensional array instead.
Why it's dangerous?
void test()
{
double **a;
int i1 = sizeof(a[0]);//i1 == 4 == sizeof(double*)
double matrix[ROWS][COLUMNS];
int i2 = sizeof(matrix[0]);//i2 == 240 == COLUMNS * sizeof(double)
}
Here is an example of a pointer to a 2 dimensional array done properly:
int (*myPointerTo2DimArray)[ROWS][COLUMNS]
You can't use a pointer to a 2 dimensional array though if you want to support a variable number of elements for the ROWS and COLUMNS. But when you know before hand you would use a 2 dimensional array.

- 47,999
- 5
- 74
- 91

- 339,232
- 124
- 596
- 636
I like this "real world" code example of pointer to pointer usage, in Git 2.0, commit 7b1004b:
Linus once said:
I actually wish more people understood the really core low-level kind of coding. Not big, complex stuff like the lockless name lookup, but simply good use of pointers-to-pointers etc.
For example, I've seen too many people who delete a singly-linked list entry by keeping track of the "prev" entry, and then to delete the entry, doing something like:if (prev) prev->next = entry->next; else list_head = entry->next;
and whenever I see code like that, I just go "This person doesn't understand pointers". And it's sadly quite common.
People who understand pointers just use a "pointer to the entry pointer", and initialize that with the address of the list_head. And then as they traverse the list, they can remove the entry without using any conditionals, by just doing a
*pp = entry->next
Applying that simplification lets us lose 7 lines from this function even while adding 2 lines of comment.
- struct combine_diff_path *p, *pprev, *ptmp; + struct combine_diff_path *p, **tail = &curr;
Chris points out in the comments to the 2016 video "Linus Torvalds's Double Pointer Problem".
kumar points out in the comments the blog post "Linus on Understanding Pointers", where Grisha Trubetskoy explains:
Imagine you have a linked list defined as:
typedef struct list_entry { int val; struct list_entry *next; } list_entry;
You need to iterate over it from the beginning to end and remove a specific element whose value equals the value of to_remove.
The more obvious way to do this would be:list_entry *entry = head; /* assuming head exists and is the first entry of the list */ list_entry *prev = NULL; while (entry) { /* line 4 */ if (entry->val == to_remove) /* this is the one to remove ; line 5 */ if (prev) prev->next = entry->next; /* remove the entry ; line 7 */ else head = entry->next; /* special case - first entry ; line 9 */ /* move on to the next entry */ prev = entry; entry = entry->next; }
What we are doing above is:
- iterating over the list until entry is
NULL
, which means we’ve reached the end of the list (line 4).- When we come across an entry we want removed (line 5),
- we assign the value of current next pointer to the previous one,
- thus eliminating the current element (line 7).
There is a special case above - at the beginning of the iteration there is no previous entry (
prev
isNULL
), and so to remove the first entry in the list you have to modify head itself (line 9).What Linus was saying is that the above code could be simplified by making the previous element a pointer to a pointer rather than just a pointer.
The code then looks like this:list_entry **pp = &head; /* pointer to a pointer */ list_entry *entry = head; while (entry) { if (entry->val == to_remove) *pp = entry->next; else pp = &entry->next; entry = entry->next; }
The above code is very similar to the previous variant, but notice how we no longer need to watch for the special case of the first element of the list, since
pp
is notNULL
at the beginning. Simple and clever.Also, someone in that thread commented that the reason this is better is because
*pp = entry->next
is atomic. It is most certainly NOT atomic.
The above expression contains two dereference operators (*
and->
) and one assignment, and neither of those three things is atomic.
This is a common misconception, but alas pretty much nothing in C should ever be assumed to be atomic (including the++
and--
operators)!

- 1,262,500
- 529
- 4,410
- 5,250
-
4This will help to understand better - http://grisha.org/blog/2013/04/02/linus-on-understanding-pointers/ – kumar May 12 '14 at 15:52
-
@kumar good reference. i have included it in the answer for more visibility. – VonC May 12 '14 at 17:04
-
[This video](https://www.youtube.com/watch?v=GiAhUYCUDVc) was essential for me in understanding your example. In particular I was feeling confused (and belligerent) until I drew a memory diagram and traced the program's progress. That said, it still seems somewhat mysterious to me. – Chris Jul 11 '17 at 10:15
-
@Chris Great video, thank you for mentioning it! I have included your comment in the answer for more visibility. – VonC Jul 11 '17 at 17:09
-
@VonC This code won’t work **if there are two or more entries which `value(s)` are equal to `to_remove`**. Because after removing the first one, `pp = &entry->next;` is executed when it shouldn’t. Due to this error pp will end pointing to memory location of the next pointer **of the node just deleted** and following delete, `*pp = entry->next;` will be writing the address of the element following the deleted node (entry->next) to the previously deleted node next pointer severing the **link(s)** in linked list. – abetancort Sep 25 '20 at 11:08
-
@abetancort Interresting. I suppose when Linus wrote that in 2012 (https://meta.slashdot.org/story/12/10/11/0030249/linus-torvalds-answers-your-questions), he didn't have this particular edge case in mind. – VonC Sep 25 '20 at 11:32
-
@VonC What Linus wrote is right, your implementation is missing an else clause before pp = &entry->next; The entry = entry->next should be outside of the else as its now. – abetancort Sep 25 '20 at 11:44
-
-
When covering pointers on a programming course at university, we were given two hints as to how to begin learning about them. The first was to view Pointer Fun With Binky. The second was to think about the Haddocks' Eyes passage from Lewis Carroll's Through the Looking-Glass
“You are sad,” the Knight said in an anxious tone: “Let me sing you a song to comfort you.”
“Is it very long?” Alice asked, for she had heard a good deal of poetry that day.
“It's long,” said the Knight, “but it's very, very beautiful. Everybody that hears me sing it - either it brings the tears to their eyes, or else -”
“Or else what?” said Alice, for the Knight had made a sudden pause.
“Or else it doesn't, you know. The name of the song is called ‘Haddocks' Eyes.’”
“Oh, that's the name of the song, is it?" Alice said, trying to feel interested.
“No, you don't understand,” the Knight said, looking a little vexed. “That's what the name is called. The name really is ‘The Aged Aged Man.’”
“Then I ought to have said ‘That's what the song is called’?” Alice corrected herself.
“No, you oughtn't: that's quite another thing! The song is called ‘Ways And Means’: but that's only what it's called, you know!”
“Well, what is the song, then?” said Alice, who was by this time completely bewildered.
“I was coming to that,” the Knight said. “The song really is ‘A-sitting On A Gate’: and the tune's my own invention.”
-
1I had to read that passage a couple of times... +1 for making me think! – Ruben Steins Aug 26 '09 at 11:07
-
-
1So... it would go like this? name -> 'The Aged Aged Man' -> called -> 'Haddock's Eyes' -> song -> 'A-sitting On A Gate' – tisaconundrum Apr 08 '18 at 01:43
Since we can have pointers to int, and pointers to char, and pointers to any structures we've defined, and in fact pointers to any type in C, it shouldn't come as too much of a surprise that we can have pointers to other pointers.
Consider the below figure and program to understand this concept better.
As per the figure, ptr1 is a single pointer which is having address of variable num.
ptr1 = #
Similarly ptr2 is a pointer to pointer(double pointer) which is having the address of pointer ptr1.
ptr2 = &ptr1;
A pointer which points to another pointer is known as double pointer. In this example ptr2 is a double pointer.
Values from above diagram :
Address of variable num has : 1000
Address of Pointer ptr1 is: 2000
Address of Pointer ptr2 is: 3000
Example:
#include <stdio.h>
int main ()
{
int num = 10;
int *ptr1;
int **ptr2;
// Take the address of var
ptr1 = #
// Take the address of ptr1 using address of operator &
ptr2 = &ptr1;
// Print the value
printf("Value of num = %d\n", num );
printf("Value available at *ptr1 = %d\n", *ptr1 );
printf("Value available at **ptr2 = %d\n", **ptr2);
}
Output:
Value of num = 10
Value available at *ptr1 = 10
Value available at **ptr2 = 10

- 33,420
- 29
- 119
- 214
A pointer-to-a-pointer is used when a reference to a pointer is required. For example, when you wish to modify the value (address pointed to) of a pointer variable declared in a calling function's scope inside a called function.
If you pass a single pointer in as an argument, you will be modifying local copies of the pointer, not the original pointer in the calling scope. With a pointer to a pointer, you modify the latter.

- 25,981
- 23
- 80
- 125

- 3,218
- 4
- 27
- 36
A pointer to a pointer is also called a handle. One usage for it is often when an object can be moved in memory or removed. One is often responsible to lock and unlock the usage of the object so it will not be moved when accessing it.
It's often used in memory restricted environment, ie the Palm OS.
it's a pointer to the pointer's address value. (that's terrible I know)
basically, it lets you pass a pointer to the value of the address of another pointer, so you can modify where another pointer is pointing from a sub function, like:
void changeptr(int** pp)
{
*pp=&someval;
}

- 9,209
- 2
- 28
- 29
-
sorry, I know it was pretty bad. Try reading, erm, this: http://www.codeproject.com/KB/cpp/PtrToPtr.aspx – Luke Schafer May 22 '09 at 11:22
You have a variable that contains an address of something. That's a pointer.
Then you have another variable that contains the address of the first variable. That's a pointer to pointer.

- 26,650
- 27
- 89
- 114
A pointer to pointer is, well, a pointer to pointer.
A meaningfull example of someType** is a bidimensional array: you have one array, filled with pointers to other arrays, so when you write
dpointer[5][6]
you access at the array that contains pointers to other arrays in his 5th position, get the pointer (let fpointer his name) and then access the 6th element of the array referenced to that array (so, fpointer[6]).

- 10,220
- 3
- 39
- 56
-
2pointers to pointers should not to be confused with arrays of rank2, eg int x[10][10] where you write x[5][6] you access the value in the array. – Pete Kirkham May 22 '09 at 11:27
-
This is only an example where a void** is appropriate. A pointer to pointer is only a pointer that points to, well, a pointer. – akappa May 22 '09 at 14:51
How it works: It is a variable that can store another pointer.
When would you use them : Many uses one of them is if your function wants to construct an array and return it to the caller.
//returns the array of roll nos {11, 12} through paramater
// return value is total number of students
int fun( int **i )
{
int *j;
*i = (int*)malloc ( 2*sizeof(int) );
**i = 11; // e.g., newly allocated memory 0x2000 store 11
j = *i;
j++;
*j = 12; ; // e.g., newly allocated memory 0x2004 store 12
return 2;
}
int main()
{
int *i;
int n = fun( &i ); // hey I don't know how many students are in your class please send all of their roll numbers.
for ( int j=0; j<n; j++ )
printf( "roll no = %d \n", i[j] );
return 0;
}

- 5,393
- 9
- 44
- 53

- 12,299
- 7
- 36
- 43
There so many of the useful explanations, but I didnt found just a short description, so..
Basically pointer is address of the variable. Short summary code:
int a, *p_a;//declaration of normal variable and int pointer variable
a = 56; //simply assign value
p_a = &a; //save address of "a" to pointer variable
*p_a = 15; //override the value of the variable
//print 0xfoo and 15
//- first is address, 2nd is value stored at this address (that is called dereference)
printf("pointer p_a is having value %d and targeting at variable value %d", p_a, *p_a);
Also useful info can be found in topic What means reference and dereference
And I am not so sure, when can be pointers useful, but in common it is necessary to use them when you are doing some manual/dynamic memory allocation- malloc, calloc, etc.
So I hope it will also helps for clarify the problematic :)

- 1,270
- 2
- 18
- 37