Pointer expressions: **ptr++, *++*ptr and ++**ptr use

I am trying my hands on a C pointer literature. In one of the illustrations, I encountered the following code.

# include <stdio.h>

int main()
{
     static int a[]={0,1,2,3,4};
     static int *p[]={a, a+1, a+2, a+3, a+4};

     int **ptr;

     ptr =p;

     **ptr++;
     printf("%d %d %d\n", ptr-p, *ptr-a, **ptr);

     *++*ptr; 
     printf("%d %d %d\n", ptr-p, *ptr-a, **ptr);

     ++**ptr;
     printf("%d %d %d\n", ptr-p, *ptr-a, **ptr);

     return 0;
}

I receive the output as.

1 1 1
1 2 2
1 2 3

I am facing a problem in justifying this output. I made lot of boxes on a copy for easy grasp of the problem. I am able to justify the output 1 1 1, my trouble starts with the statement, *++*ptr.

Since, a unary operators are executed from right to left. So, *ptr would be tackled first, then the value at ptr would be incremented. After this increment, I am not sure what happens, the book says that somehow p is also incremented to point to the next element in this array. The output 1 2 2 can only be achieved through the increment of p.

I am not sure that this kind of question fits exactly on stackoverflow.
I tried my best, wasted at least 10 pages with boxes drawn over them.

Any clarification would be appreciated.


Remember array name can easily decays into pointer to first element in most expressions (read some exceptions where array name not decaying into a pointer to first element? ably answered by @H2CO3).
For better understanding, consider my diagrams:

First, suppose a stored in memory as follows.

  a 
+----+----+----+----+---+
|  0 |  1 | 2  | 3  | 4 |
+----+----+----+----+---+
  ▲    ▲    ▲    ▲    ▲
  |    |    |    |    | 
  a    a+1  a+2  a+3  a+3

Declaration static int *p[] = {a, a+1, a+2, a+3, a+4}; creates a new array of pointers to integer, with following values:

p[0] == a
p[1] == a + 1
p[2] == a + 2
p[3] == a + 3
p[4] == a + 4

Now, p can also be assume to be stored in memory something like below:

  p
+----+----+----+----+-----+
| a  |a +1| a+2| a+3| a+4 | 
+----+----+----+----+-----+
  ▲    ▲    ▲    ▲    ▲
  |    |    |    |    |
  p    p+1  p+2  p+3  p+4

After assignment ptr = p; things will be something like this:

  p                              a 
+----+----+----+----+-----+    +----+----+----+----+---+
| a  |a +1| a+2| a+3| a+4 |    |  0 |  1 | 2  | 3  | 4 |
+----+----+----+----+-----+    +----+----+----+----+---+
  ▲    ▲    ▲    ▲    ▲          ▲    ▲    ▲    ▲    ▲
  |    |    |    |    |          |    |    |    |    | 
  p    p+1  p+2  p+3  p+4        a    a+1  a+2  a+3  a+3
  ptr 


Notice: ptr points to first location in pointer array p[]

Expression: **ptr++;

Now we consider expression **ptr++; before first printf statement.

  1. ptr is equals to p that is address of first element in array of pointers. Hence, ptr point to first element p[0] in array (or we can say ptr == &p[0]).

  2. *ptr means p[0] and because p[0] is a, so *ptr is a ( so *ptr == a).

  3. And because *ptr is a, then **ptr is *a == *(a + 0) == a[0] that is 0.

  4. Note in expression **ptr++;, we do not assign its value to any lhs variable.
    So effect of **ptr++; is simply same as ptr++; == ptr = ptr + 1 = p + 1
    In this way after this expression ptr pointing to p[1] (or we can say ptr == &p[1]).

Print-1:

Before first printf things become:

  p                              a 
+----+----+----+----+-----+    +----+----+----+----+---+
| a  | a+1| a+2| a+3| a+4 |    |  0 |  1 | 2  | 3  | 4 |
+----+----+----+----+-----+    +----+----+----+----+---+
  ▲    ▲    ▲    ▲    ▲          ▲    ▲    ▲    ▲    ▲
  |    |    |    |    |          |    |    |    |    | 
  p    p+1  p+2  p+3  p+4        a    a+1  a+2  a+3  a+3
       ptr 


Notice: ptr is equals to  p + 1 that means it points to p[1]

Now we can understand First printf:

  1. ptr - p output 1 because:
    ptr = p + 1, so ptr - p == p + 1 - p == 1

  2. *ptr - a output 1 because:
    ptr = p + 1, so *ptr == *(p + 1) == p[1] == a + 1
    This means: *ptr - a = a + 1 - a == 1

  3. **ptr output 1 because:
    *ptr == a + 1 from point-2
    So **ptr == *(a + 1) == a[1] == 1

Expression: *++*ptr;

After first printf we have an expression *++*ptr;.

As we know from above point-2 that *ptr == p[1]. So, ++*ptr (that is ++p[1]) will increments p[1] to a + 2

Again understand, in expression *++*ptr; we don't assign its value to any lhs variable so effect of *++*ptr; is just ++*ptr;.

Now, before second printf things become:

  p                              a 
+----+----+----+----+-----+    +----+----+----+----+---+
| a  |a+2 | a+2| a+3| a+4 |    |  0 |  1 | 2  | 3  | 4 |
+----+----+----+----+-----+    +----+----+----+----+---+
  ▲    ▲    ▲    ▲    ▲          ▲    ▲    ▲    ▲    ▲
  |    |    |    |    |          |    |    |    |    | 
  p    p+1  p+2  p+3  p+4        a    a+1  a+2  a+3  a+3
       ptr 


Notice: p[1] became a + 2 

Print-2:

Now we can understand Second printf:

  1. ptr - p output 1 because:
    ptr = p + 1, so ptr - p == p + 1 - p == 1

  2. *ptr - a output 2 because:
    ptr = p + 1 so *ptr == *(p + 1) == p[1] == a + 2
    This means: *ptr - a == a + 2 - a == 2

  3. **ptr output 2 because:
    *ptr == a + 2 from point-2
    So **ptr == *(a + 2) == a[2] == 2

Expression: ++**ptr;

Now expression ++**ptr; before third printf.

As we know from above point-3 that **ptr == a[2]. So ++**ptr == ++a[2] will increments a[2] to 3

So before third printf things become:

  p                              a 
+----+----+----+----+-----+    +----+----+----+----+---+
| a  | a+2| a+2| a+3| a+4 |    |  0 |  1 | 3  | 3  | 4 |
+----+----+----+----+-----+    +----+----+----+----+---+
  ▲    ▲    ▲    ▲    ▲          ▲    ▲    ▲    ▲    ▲
  |    |    |    |    |          |    |    |    |    | 
  p    p+1  p+2  p+3  p+4        a    a+1  a+2  a+3  a+3
       ptr 


 Notice: a[2] = 3

Print-3:

Now we can understand Third printf:

  1. ptr - p output 1 because:
    ptr = p + 1 so ptr - p == p + 1 - p == 1

  2. *ptr - a output 2 because:
    ptr = p + 1 so *ptr == *(p + 1) == p[1] == a + 2
    This means: *ptr - a = a + 2 - a == 2

  3. **ptr outputs 3 because:
    *ptr == a + 2 from point-2
    So **ptr == *(a + 2) == a[2] == 3

Edit Note: The difference of two pointers has type ptrdiff_t, and for that, the correct conversion specifier is %td, not %d.

An additional point:
I wish to add as I believe it will be helpful for new learners

Suppose we have following two lines with one more 4th printf in you code before return 0;

**++ptr;    // additional 
printf("%d %d %d\n", ptr-p, *ptr-a, **ptr);  // fourth printf

One can check this working code @Codepade , this line outputs 2 2 3.

Expression: **++ptr;

Because ptr is equals to p + 1 , after increment ++ operation ptr becomes p + 2 (or we can say ptr == &p[2]).
After that double deference operation ** ==> **(p + 2) == *p[2] == *(a + 2) == a[2] == 3.
Now, again because we don't have any assignment operation in this statement so effect of expression **++ptr; is just ++ptr;.

So thing after expression **++ptr; becomes as below in figure:

  p                              a 
+----+----+----+----+-----+    +----+----+----+----+---+
| a  | a+2| a+2| a+3| a+4 |    |  0 |  1 | 3  | 3  | 4 |
+----+----+----+----+-----+    +----+----+----+----+---+
  ▲    ▲    ▲    ▲    ▲          ▲    ▲    ▲    ▲    ▲
  |    |    |    |    |          |    |    |    |    | 
  p    p+1  p+2  p+3  p+4        a    a+1  a+2  a+3  a+3
            ptr 

 Notice: ptr is equals to  p + 2 that means it points to p[2] 

Print-4:

Considering Forth printf I added in question:

  1. ptr - p output 2 because:
    ptr = p + 2 so ptr - p == p + 2 - p == 2

  2. *ptr - a output 2 because:
    ptr = p + 2 so *ptr == *(p + 2) == p[2] == a + 2
    This means: *ptr - a = a + 2 - a == 2

  3. **ptr outputs 3 because:
    *ptr == a + 2 from above point-2
    So **ptr == *(a + 2) == a[2] == 3


If you compile with some warnings on (clang didn't even require any flags), you'll see that your program has three extraneous * operators. Simplifying your crazy-looking expressions yields:

ptr++;
++*ptr;
++**ptr;

And from that, you should be able to see what's happening pretty clearly:

  1. ptr++ just increments ptr, so it points to the second element of p. After this operation ptr - p will always be 1.

  2. ++*ptr increments whatever is pointed to by ptr. That changes the second element of p to point to the third element of a rather than the second (which it was initialized to). That makes *ptr - a equal to 2. Likewise **ptr is the 2 from a.

  3. ++**ptr increments whatever is pointed to by whatever is pointed to by ptr. That increments the third element of a, making it a 3.


The int* value at address ptr has been incremented by the statement *++*ptr; (actually by the ++*ptr portion, the leading * is an unused dereference). Thus the expansion of int *p[] should now look like this:

int *p[]={a, a+2, a+2, a+3, a+4};

The final ++**ptr; has now incremented the value at address a+2, so the original array will now look like this:

int a[]={0,1,3,3,4};