Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
318 views
in Technique[技术] by (71.8m points)

c - 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
", ptr-p, *ptr-a, **ptr);

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

     ++**ptr;
     printf("%d %d %d
", 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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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
", 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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...