Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

arrays

c

pointers

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.

like image 641
Paras Avatar asked Jul 19 '13 17:07

Paras


1 Answers

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

like image 147
Grijesh Chauhan Avatar answered Sep 28 '22 08:09

Grijesh Chauhan