Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Understanding what a pointer (an address) is, is fairly easy and an eleven-year old can understand it. But how do we express why we have a need for a pointer to a pointer? what is a very pedagogical example? Does it extend to pointing to a pointer to a pointer (and/or onward)?

Example problem

T[][] does not decay to a T**

Example problem 2

brainfuck command   C equivalent
(Program Start) char array[30000];
                char *ptr=array;
>   ++ptr;
<   --ptr;
+   ++*ptr;
-   --*ptr;
.   putchar(*ptr);
,   *ptr=getchar();
[   while (*ptr) {
]   }
share|improve this question
10  
If a pointers are so easy to understand, why do so many get it so wrong? (Hint : the answer is 42) –  mattnz Feb 4 '13 at 2:39
5  
How about int main(int argc, char **argv); –  Brian Feb 4 '13 at 17:21
    
Even a higher-level language like C# has [under the hood] a pointer to pointer void foo (ref myObject){...} as opposed to using a single pointer - void foo (myObject){...}. In the second case you can change the content of myObject but not its address. In the first case you can also change the address of myObject, say by doing myObject = new MyObject(). When passed by "ref" (pointer to a pointer), this address change will survive after the method is done. This is useful if you need to return multiple things and you hate using Tuples, because .Item1, .Item2, .Item3 do not help –  Job Feb 4 '13 at 20:17
1  
@Brian I agree that the example you put in is very good since it's common. It's one I've seen. –  909 Niklas Feb 4 '13 at 22:23

4 Answers 4

up vote 7 down vote accepted

A pointer lets you talk about some piece of information without specifying that information explicitly:

  • the value at location 0x007d32f8
  • the house at 105 West Street

A pointer to a pointer lets you talk about the location of something without specifying that location explicitly:

  • the address at location 0x012a0052
  • the street address listed on my business card

An easy to understand, practical use of pointers to pointers is when you want some other function or method to give you a pointer to some piece of data. Instead of asking for the data outright (after all, it might be very large) you can instead just ask for the address of the data. You can say: here's the address of a pointer that I'd like you to change so that it points to the data I want. To use the street address analogy, it's like telling your friend:

Please write your home address on this note pad.

The phrase "this note pad" specifies the location of a specific storage space, so it's like a pointer. Once the address is written down, it's like a pointer to your friend's home.

Another common example of a pointer to a pointer (pointed out in Brian's comment) is multidimensional arrays. In C, for example, a string is a null-terminated array of characters, and a string variable is just a pointer to the first element of the array. If you wanted to build an array of strings, you'd create an array of the pointers, each one pointing to a different string. If you wanted a 2-dimensional array of strings, you could repeat the process and create an array of arrays of strings.

Being able to talk about addresses allows for more sophisticated expression, both in code and in the real world.

share|improve this answer
2  
Excellent answer! –  Ross Patterson Feb 9 '13 at 14:58

Sometimes called a Handle, Windows and the Mac OS use this structure to allow memory compaction on the heap. The program manages the pointer p, while the operating system manages the pointer *p. Because the OS manages *p, the block pointed to by p (*p) can be moved, and *p can be changed to reflect the move without affecting the program using p. Pointers to pointers are also frequently used in C to handle pointer parameters in functions.

http://computer.howstuffworks.com/c32.htm

share|improve this answer
2  
True enough, but the last line is really the most applicable these days. Virtual memory systems have obviated the need for heap compaction and relocatable blocks. Also, a handle (at least in the classic MacOS memory manager) isn't just a pointer to any old pointer -- it's a pointer to a "master pointer," i.e. a pointer that the OS knows it's supposed to manage. –  Caleb Feb 4 '13 at 19:31
1  
"Virtual memory systems have obviated the need for heap compaction and relocatable blocks."? Uh, no, that's exactly what Java and .NET do in their garbage collectors. At least one early JVM implemented objects via handles for exactly that reason. –  Ross Patterson Feb 9 '13 at 14:57

If you have a pointer, and you want to call a function that modifies the pointer, you need to tell that function where the pointer is stored. In order to tell the function where it is stored, you need to get the address of the pointer, which is a pointer to a pointer

int foo(const char **error_message)
{
    if (!bar())
    {
        // The type of error_message is const char ** (the parameter)
        // The type of *error_message is const char * (the caller's msg)
        // The type of **error_message is const char ('N' from "No error")

        // Note here, I have a * before error_message, it changes the callers msg
        // *error_message is the caller's msg variable
        // reading or writing *error_message will read/write msg
        // before this line executes, msg points to the first character of "No error"
        // after this line, msg points first character of "bar failed"
        *error_message = "bar failed";
        return -2;
    }

    return 0;
}

int main()
{
    // make a variable 'msg' and point it to the first character of "No error"
    const char *msg = "No error";

    // Get the address of 'msg' and pass it to foo.
    // '&msg' is a pointer to 'msg' (which happens to be a pointer).
    int status = foo(&msg);

    // foo could have modified msg, since it knew the address of msg
    if (status < 0 && msg != 0)
       printf("%s\n", msg);
}

In my example, the caller needs to pass a pointer to msg (a pointer to a pointer) so foo can set it to point to the error message.

The idea is the same as any use of a pointer. If you want a piece of code to be able to read or write at arbitrary addresses, you pass a pointer. A pointer to a pointer, simply points to a pointer.

share|improve this answer

What does it mean that a pointer is an address? It means that it refers to a memory location where the value pointing to is stored, usually a variable. When you say that a pointer points to something, you really mean a pointer pointing to a something variable.

This variable can hold an int, but it can as well hold another pointer. Thus more correctly, you have a pointer to a pointer variable. This makes the explanation easy: You need a pointer to a pointer variable for the same reasons you need a pointer to an integer variable.

A pointer to a pointer doesn't exist as its own type. If you have this:

int **p;

then p ist still a single leveled pointer. Don't read it as this:

int (**)p;  // wrong

but as this:

(int *) *p;  // correct

because it is a pointer to another pointer variable that holds a pointer to an int variable.

int i = 125;
int *p1 = &i;
int **p2 = &p1;

Address     Value
0x10000000  [0x20000000]  p2 
0x20000000  [0x30000000]  p1
0x30000000  [125]         i

EDIT:

If you still find this confusing, then don't try to think about the pointer to infinity. It works in plain C, is completely undefined behavior (and thus bad), and requires sizeof(unsigned int) == sizeof(unsigned int *). But then it works with any amount of * the compiler supports.

unsigned int **********p;

p = (void *)&p;

printf("%x\n", **********p);
printf("%p\n", (void *)p);
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.