6.14 — Pointers to pointers

This lesson is optional, for advanced readers who want to learn more about C++. Future lessons do not build on it.

A pointer to a pointer is exactly what you’d expect: a pointer that holds the address of another pointer.

Pointers to pointers

A normal pointer to an int is declared using a single asterisk:

A pointer to a pointer to an int is declared using two asterisks

A pointer to a pointer works just like a normal pointer — you can dereference it to retrieve the value pointed to. And because that value is itself a pointer, you can dereference it again to get to the underlying value. These dereferences can be done consecutively:

The above program prints:


Note that you can not set a pointer to a pointer directly to a value:

This is because the address of operator (operator&) requires an lvalue, but &value is an rvalue.

However, a pointer to a pointer can be set to null:

Arrays of pointers

Pointers to pointers have a few uses. The most common use is to dynamically allocate an array of pointers:

This works just like a standard dynamically allocated array, except the array elements are of type “pointer to integer” instead of integer.

Two-dimensional dynamically allocated arrays

Another common use for pointers to pointers is to facilitate dynamically allocated multidimensional arrays.

Unlike a two dimensional fixed array, which can easily be declared like this:

Dynamically allocating a two-dimensional array is a little more challenging. You may be tempted to try something like this:

But it won’t work.

There are two possible solutions here. If the right-most array dimension is a compile-time constant, you can do this:

The parenthesis are required here to ensure proper precedence. In C++11 or newer, this is a good place to use automatic type deduction:

Unfortunately, this relatively simple solution doesn’t work if the right-most array dimension isn’t a compile-time constant. In that case, we have to get a little more complicated. First, we allocate an array of pointers (as per above). Then we iterate through the array of pointers and allocate a dynamic array for each array element. Our dynamic two-dimensional array is a dynamic one-dimensional array of dynamic one-dimensional arrays!

We can then access our array like usual:

With this method, because each array column is be dynamically allocated independently, it’s possible to make dynamically allocated two dimensional arrays that are not rectangular. For example, we can make a triangle-shaped array:

In the above example, note that array[0] is an array of length 1, array[1] is an array of length 2, etc…

Deallocating a dynamically allocated two-dimensional array using this method requires a loop as well:

Note that we delete the array in the opposite order that we created it. If we delete array before the array elements, then we’d have to access deallocated memory to delete the array elements. And that would result in undefined behavior.

Because allocating and deallocating two-dimensional arrays is complex and easy to mess up, it’s often easier to “flatten” a two-dimensional array (of size x by y) into a one-dimensional array of size x * y:

Simple math can then be used to convert a row and column index for a rectangular two-dimensional array into a single index for a one-dimensional array:

Passing a pointer by address

Much like we can use a pointer parameter to change the actual value of the underlying argument passed in, we can pass a pointer to a pointer to a function and use that pointer to change the value of the pointer it points to (confused yet?).

However, if we want a function to be able to modify what a pointer argument points to, this is generally better done using a reference to a pointer instead. So we won’t talk about it further here.

We’ll talk more about pass by address and pass by reference in the next chapter.

Pointer to a pointers to a pointer to…

It’s also possible to declare a pointer to a pointer to a pointer:

These can be used to dynamically allocate a three-dimensional array. However, doing so would require a loop inside a loop, and are extremely complicated to get correct.

You can even declare a pointer to a pointer to a pointer to a pointer:

Or higher, if you wish.

However, in reality these don’t see much use because it’s not often you need so much indirection.


We recommend avoiding using pointers to pointers unless no other options are available, because they’re complicated to use and potentially dangerous. It’s easy enough to dereference a null or dangling pointer with normal pointers — it’s doubly easy with a pointer to a pointer since you have to do a double-dereference to get to the underlying value!

6.15 -- An introduction to std::array
6.13 -- Void pointers

37 comments to 6.14 — Pointers to pointers

  • Avneet

    Doesn’t this code causes memory leak:

    In main (), a pointer to int is declared. It’s  address is then sent to allocateArray() that returns a bool. We dereference the pointer (with single asterisk) and get access to a pointer. Dynamically Allocate some memory and then return true, in this case. Now control is back to main (). main () neither uses that memory, nor deallocates it. When ‘array’ is going out of scope, only reference to that memory is destroyed and results a memory leak. Am I right? Correct me if not. The next code also has a memory leakage problem I think.

    And a confusion. We are sending the address of ‘array’ by value, that means a copy of that address would be passed. Isn’t the copy of the address is same as the real address. I mean, array and ptr are pointing to same address right? So, main’s ‘array’ can deallocate the dynamically allocated memory in allocateArray(), where ‘ptr’ is controlling the dynamic allocation? Confused? My bad english 🙁

    • Alex

      Yes, the memory is never deallocated. It wasn’t relevant to the example so I didn’t flesh out that part of the example. However, I think it’s good practice, so I’ve added it. Thanks for the thought.

      Consider this code:

      This is a pass-by-value example. In this case, ptr gets a copy of array’s value. We allocate memory to ptr, but the address of that memory never gets assigned back to array because ptr is a copy.

      In the example in the lesson, we are sending the address of array by address, not by value. So the ptr is set to the _address_ of array. Think of it this way:

      ptr -> array -> array element 0

      In this case, when we dereference ptr, we get array (which itself points to the array). By allocating memory to *ptr, we’re essentially changing the address of array, which is why when we return to main, array is still pointing at the allocated memory.

      This allows array to deallocate the memory allocated in allocateArray() because array is a valid pointer to that memory.

      On second thought, I think I’m going to remove the example altogether. It’s a little complicated for this point in the tutorials, and we haven’t even hit the lessons on pass by value, pass by address, and pass by reference yet.

    • Elpidius

      Hey Avneet,

      The following code does not cause a memory leak. I also commented everything to try and illustrate what is happening:

  • venkata prasad

    I read everywhere that if I have a need to do arithematic operations on pointers always choose pass by pointer mentod over pass by reference method.

    but what about this code?

    incrementptr1(int *ptr1)


    return 0;


    incrementptr2(int* &ptr2)


    int main()


       int value=5;

    return 0;


    with the increment2 method I could increment the pointer though I did pass it by reference.

    does this work?

    • Alex

      It really depends on what your intent is. If you want to increment the pointer inside the function without affecting the argument, pass the pointer by value (incrementptr1). If you want the function to be able to change the argument, then pass the pointer by reference (incrementptr2).

  • Anton

    Regarding dynamic multidimensional arrays Ivor Horton writes in his book "Beginning Visual C++ 2013" about another way to create such matrices:

    or for one-line initialization

    for three-dimensional matrices:

    and so on …

    As for the way to remove the kebab he suggests:

    I’m confused here. This couldn’t possibly be a proper way to declare a true dynamic multidimensional array. Firstly, I don’t truly understand the syntax and secondly the code:

    looks like

    Hayl, I don’t even understand what it does! It doesn’t look like something that the compiler would accept.

    If you want to check it out it is found in chapter 4 (“Arrays, Strings and Pointers”) in section [i]???[b]num[/b]???[/i] (“Dynamic Memory Allocation”) in the last subsection [i]???[b]num.num[/b]???[/i] (“Dynamic Allocation of Multidimensional Arrays”).

    • Alex

      That’s super neat. I’ve updated the lesson to incorporate this. Thanks for the tip!

      means (in English) define a pointer that points to an object of type double[4]. In other words, *pbeans (or pbeans[0]) has type double[4].

      The {} aren’t necessary, but can be used to initialize the array to the default value for the type (in this case, the default value for double is 0.0).

  • cesare

    I need a little clarification about what you say here:

    "With this method, because each array column is be dynamically allocated independently, it’s possible to make dynamically allocated two dimensional arrays that are not rectangular. For example, we can make a triangle-shaped array:"

    And then:
    "In the above example, note that array[0] is an array of length 1, array[1] is an array of length 2, etc…"

    Well, from my point of view, during the first iteration of the loop, the value of ‘count’ equals 0, so the instruction run like this:

    On the left hand side it clearly refer to the first position in the array, but on the right hand side it seems to allocate an array with length 0 not length 1.
    Am I missing something or is it just a typo?

    • Alex

      Typo. I’ve updated the example to:

  • Narendra Kangralkar

    Below is the better way of allocating memory to 2-D array. It requires only 2 calls to allocate/deallocate memory regardless of number of rows and columns.

    • Elpidius

      Hi Narendra,

      Accessing memory from a "flattened 2-D array", i.e. a 1-D array, using a 2-D array nullifies the need of "flattening" the 2-D array in the first place. You’ve basically created a "flattened" 1-D array in array[0], then used a 2-D array in array[1] to array[9] to access this 1-D array. What’s the point in that?

      Furthermore you’re using twice the amount of memory, since both an int and a pointer to an int take up 4 bytes of memory (on a 32-bit machine). The first row (row 0) contains the data, and the rest of the rows simply hold addresses. Nevertheless I’ve tried to understand your code and have explained what is happening below.

      You’ve explicity assigned each pointer to pointer, to point to the address of every 5 array elements (columns) of array[0] (row 0).

      The array assigned to array[0] is illustrated as:

      [0][0]  [0][1]  [0][2]  [0][3]  [0][4] [0][5] [0][6] etc… [0][49] // row 0

      The rows pointed to colums is illustrated as:

      [1][0] = &[0][5] // row 1 (2nd row) points to column 5 (6th column)
      [2][0] = &[0][10] // row 2 (3rd row) points to column 10 (7th column)
      [3][0] = &[0][15]
      [4][0] = &[0][20]
      [5][0] = &[0][25]
      [6][0] = &[0][30]
      [7][0] = &[0][35]
      [8][0] = &[0][40]
      [9][0] = &[0][45]

      Conceptually our final array is as follows:

      [0][0]  [0][1]  [0][2]  [0][3]  [0][4] [0][5] [0][6] etc… [0][49] // row 0
      [1][0]  [1][1]  [1][2]  [1][3]  [1][4] // row 1 -- points to [0][5] to [0][9]
      [2][0]  [2][1]  [2][2]  [2][3]  [2][4] // row 2 -- points to [0][10] to [0][14]
      [9][0]  [9][1]  [9][2]  [9][3]  [9][4] // row 9 -- points to [0][45] to [0][49]

      Here’s your code which I’ve commented:

      Despite it being easier to access this array, it takes up double the memory and the for loop in particular is more difficult to understand. Alex’s method is much easier and doesn’t take up any additional memory.

      • Elpidius

        The code I commented above had typos in them. Here’s the corrected comments:

        • Elpidius

          Further typos/edits in the comments:

      • Elpidius

        Further explanation of a comment:

        Remember, when the compiler sees the subscript operator ([]), it actually translates that into a pointer addition and dereference! Generalizing, array[n] is the same as *(array + n), where n is an integer.

        Revisit lesson 6.8a — Pointer arithmetic and array indexing, if you’re having trouble understanding this.

  • raha

    Hello, thank you so much for the great website, I have a problem in calling a matrix to a function, my main function is as following,

    I’ve defined matrix X and vector y, Im filling these two by function ReadData, and everything is fine by now, but when I try to pass matrix X to function LogReg, which has defined as "double LogReg(double **X, double *y, Parameter* param, Objective* obj)", Im getting "segmentation fault", it happens when I want to use the elements of matrix X such X[i][j], but when I use the elements of vector y such y[i], everything is fine, the thing is why I can pass X to function ReadData(which has been defined in the same file as main) but I can not do the same thing with function "LogReg" which has been define in a header file..

    Thank you so much for your help..

  • Federico

    I have a question:

    For the function funz i have a warning: address of local variable ‘var’ returned [-Wreturn-local-addr]
    and this is ok, but not for function gunz.
    The output is:
    segmentation fault

    It isn’t the same situation?

    Thanks and sorry for my english.

  • Nyap

    This is confusing

    • Alex

      Yeah, it is a little bit, and it’s hard to explain. The good news is that you’ll almost never need to use it, so if you’re finding it confusing, just move on. You can always come back later if needed.

      • Elpidius

        Hey Alex, I think you did a wonderful job explaining pointers to pointers. I’m sure your explanation is better than most textbooks out there!

  • Elpidius

    I thought I’d try to dynamically allocate a three-dimensional array. Note I’ve left the number of layers, rows and columns as the values 2, 10 and 5 respectively to make logic behind the code easier to understand.

    We can allocate the arrays in separate loops within loops (for the rows + columns):

    Or in one loop within a loop (for the rows + columns):

    We then assign values to each array element:

    Accessing the element of a dynamic three-dimensional array is analogous to a fixed three-dimensional array:

    To deallocate the arrays in separate loops within loops (for the rows + columns):

    delete[] array[0][0] -- deletes the int[5]
    delete[] array[0][1] -- deletes the int[5]
    delete[] array[0][2] -- deletes the int[5]
    delete[] array[0][9] -- deletes the int[5]

    delete[] array[0] -- deletes the int*[10]
    delete[] array[1] -- deletes the int*[10]

    To deallocate the arrays in one loop within a loop (for the rows + columns):

    Putting all the code together:

    I hope this helps anyone trying to do this!

    • Darren

      Brain. Is. Melting…

      • Alex

        Seriously. 🙂 Flattened arrays are so much easier to work with.

        • Darren

          I’m going to be starting a new job in about a month’s time doing C++ programming, initially refactoring some old C and Fortran code into something more modern and maintainable, then adding more functionality once I’ve got it doing what the old code could do. Among other things there is some linear algebra involved, so manipulation of matrices and vectors, that is currently done using Fortran’s LAPACK. I essentially have three options: I either try to interface C++ with Fortran but don’t think this is straightforward (or lends itself to maintainability or cross-platform compatibility): I write my own classes and functions to handle linear algebra (time consuming with lots of potential for error); or I use a third party library that is thoroughly tested, robust, and stable (this appears to be the best option). I’ve had some experience using a library called ‘Eigen’ that appears to be my best bet. Once I get the code up and running using Eigen, say, then I could perhaps look at writing my own classes if we need to streamline the code or improve performance (which I doubt as Eigen does some weird and wonderful things that make it run quickly and accurately).

          Anyway, the point I’m making here is that because C++ has been around for nearly 3 decades(?) there are many libraries out there that will probably have solved most of the problems you will encounter, such as how to efficiently implement and manipulate multi-dimensional matrices in a user friendly manner. For example, look at Boost. However, having a firm understanding of the fundamentals of the language is absolutely necessary in being able to work with these libraries and if possible extend them to make them do what you want. It’s the reason why I’m running through these tutorials.

          • Alex

            Great points. There are benefits both to using your own code, and using code out of a library. However, having been involved in creation and maintenance of some very large apps, I’d lean towards favoring library functionality if that meets your needs, rather than recreating the wheel. It’s less likely to be buggy, is probably more optimized, and if the library gets updated, you get more functionality for “free”.

            One other option I’ve seen employed to good use is to “extend” library functionality via inheritance (or composition) -- that way you can complement the library functionality with anything you additionally need that it doesn’t provide without it being too disjoint.

  • Kattencrack Kledge

    Can you tell me what is happening in these codes below? I really do not understand what is happening:


    • Kattencrack Kledge

      Nevermind for the second  code, I managed to understand it by seeing what each thing does:

      But I still don’t understand this:

    • Alex

      The bottom case is more straightforward. Array is a single-dimensional array of size 10, with each array element being an integer pointer (these are our rows). For each of the 10 elements, we’re stepping through and dynamically allocating an array of size 5 (these are our columns). When we use array[x][y], array[x] is dereferenced to select the row, and then [y] is dereferenced to get the element within that column.

      In the top case, array is also a single-dimensional array of size 10, but each array element has type int[5]. The compiler can hook everything up for us so it works the same way as the above case, but without us having to dynamically allocate each column by hand.

  • Matt


    Under "Pointers to Pointers", you wrote:

    "Note that you can not set a pointer to a pointer directly to a value…
    int **ptrptr = &&value  // not valid…
    This is because the address of operator (operator&) requires an lvalue, but &value is an rvalue."

    Even after looking up the definitions of lvalue and rvalue, I still don’t understand what you mean by this last sentence. Could you explain it in a different way?

    Also, I found a small typo midway through "Two-dimensional dynamically allocated arrays". You wrote:
    "…because each array column is be dynamically allocated independently…".

    • Alex

      Okay, I’ll try. Let’s go back to the definition of lvalue and rvalue.
      lvalue = an object that persists beyond a single expression, like a normal variable. You can take an address of one of these.
      rvalue = a temporary value that doesn’t persists beyond a single expression (e.g. the result of 2+3). You can’t take an address of one of these because the address is meaningless outside of the expression.

      So consider something like int **ptrptr = &&value. First, the compiler evaluates &value. value is an lvalue, and you _can_ take its address using the & symbol. However, the result of &value is a temporary pointer holding the address of value -- and because it is a temporary value that doesn’t exist beyond the expression, that makes the result of that evaluation an rvalue. So when we try to take the address of THAT (the left-most ampersand), we get an error, because you can’t take the address of an rvalue.

      Make sense?

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter