0

Why does *p++ first assign the value to i and then increment the p pointer, even though ++ post-increment has a higher precedence, and associativity is from Right-to-Left?

int main()
{
    int a[]={55,66,25,35,45};
    int i;
    int *p=&a;
    printf("%u \n",p);
    i=*p++;
    printf(" %u  %d",p,i);
    printf("\n %d",*p);

    return 0;
}
4056
4060 55
66
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
gokul goku
  • 35
  • 5
  • That code shouldn't compile. The line `int *p=&a;` is not correctly typed. – Brian Bi Jun 05 '19 at 19:01
  • 1
    If you want to print a pointer, you need format specifier `%p`, otherwise you invoke undefined behaviour. Until fixed, *anything* could happen... – Aconcagua Jun 05 '19 at 19:03
  • the code is giving me the following output ...it runs @Brian – gokul goku Jun 05 '19 at 19:05
  • 1
    `int *p=a;` Why? `&a` is a *pointer-to-int* `[5]`, not *pointer-to-int*. See: [C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3)](http://port70.net/~nsz/c/c11/n1570.html#6.3.2.1p3) – David C. Rankin Jun 05 '19 at 19:05
  • 4
    @gokulgoku: just because it runs with no *apparent* errors doesn't mean it's correct. You should have gotten at least a couple of warnings. – John Bode Jun 05 '19 at 19:06
  • Still it contains undefined behaviour. On modern systems, it is pretty likely that pointer size is larger than unsigned int – so in best case, you're just cutting off part of address. In worst case, some part of the address might be interpreted as next argument. As said already, you invoke UB, anything could happen, your programme might crash, give bad output or even silently ignore and go on. – Aconcagua Jun 05 '19 at 19:07
  • 2
    Arrays decay automatically to pointers when needed: `int* p = a;` is all you need. Taking the address of `a` results in another pointer type: `int(*p)[5] = &a;` would be the correct one... – Aconcagua Jun 05 '19 at 19:11
  • @Aconcagua i just cut off some part of the address for simplicity ...i didn't know there can some logic there too ...:) – gokul goku Jun 05 '19 at 19:13
  • @gokulgoku If you *want* to cut off, then do a cast: `printf("%u", (unsigned int)p);` and you are on the safe side. – Aconcagua Jun 05 '19 at 19:15
  • Rolled back. Changing `int *p=&a;` to `int *p=a;` defeats the comments and attempts to answer your own question. – Weather Vane Jun 05 '19 at 19:26
  • @Aconcagua thanks i got it...i have another doubt when we had 1 to &a we reach to address after the end of the array ..so &a+1 gives an address after the array a but why *(&a+1) also give the same address – gokul goku Jun 05 '19 at 19:31
  • @WeatherVane actually i wanted answer for *p=a; .. but i didn't notice that i wrote the code wrong until i got answers related to it ....that's why i edited it – gokul goku Jun 05 '19 at 19:34
  • See also https://stackoverflow.com/questions/31087537/why-does-a-b-have-the-same-behavior-as-a-b/31088592#31088592 . – Steve Summit Jun 05 '19 at 20:00
  • @gokulgoku `&a + 1` results in the same address as `(char*)a + sizeof(a)`, just because this is the nature of incrementing a pointer by 1. Then with `&a+1`, you get a pointer to an array of size 5. If you now dereference this pointer, you get (as the array decays!) a pointer to this arrays' first element. But the address of the array itself and the address of its first element are always the same (similarly as in C – but not in C++ – the first member of a struct has always the same address as the struct itself). – Aconcagua Jun 05 '19 at 20:50
  • Possible duplicate of [Post-increment and Pre-increment concept?](https://stackoverflow.com/questions/4445706/post-increment-and-pre-increment-concept) – GBlodgett Jun 05 '19 at 22:55

2 Answers2

8

The semantics of the postfix ++ operator are that the expression p++ evaluates to the current value of p, and as a side effect p is incremented. Effectively, i = *p++; is the same as

i = *p;
p++;

The semantics of the prefix ++ operator are that the expression evaluates to the current value of p plus one, and as a side effect p is incremented. i = *++p; would effectively be the same as

i = *(p + 1);
p++;

Precedence does not control order of evaluation - it only controls parsing (which operators are grouped with which operands).

John Bode
  • 119,563
  • 19
  • 122
  • 198
4

There seems to be some misunderstanding in how pointers and arrays work together.

The expression &a is a pointer to the array itself, and has the type int (*)[5].

What you seem to expect is to get a pointer to the first element, which would be &a[0], or plain a (as that decays to a pointer to the arrays first element):

int *p = a;

That it works is not a coincidence, because a pointer to the array just happens to point to the same address as the location of the first element. The addresses are equal, but the types of &a and &a[0] are different. This semantic difference really is crucial.


Regarding the issue about the ++ operator, it's simply how it works.

The result of the suffix increase or decrease operators is the old value. So when you do p++ you get the old pointer, before the increase.

If we take

i = *p++;

it's (somewhat simplified) equivalent to

int *temporary_old_p = p;
p = p + 1;
i = *temporary_old_p;

Furthermore, the "%u" format for a pointer is invalid. To print a void * pointer (a cast is really needed to be correct) you should use the "%p" format specifier.

Mismatching format-specifier and argument type leads to undefined behavior.


Regarding the problem with *(&a + 1), lets draw the array a how it looks in memory, with a few arrows to show pointers:

+------+------+------+------+------+------
| a[0] | a[1] | a[2] | a[3] | a[4] | ....
+------+------+------+------+------+------
^                                  ^
|                                  |
&a[0]                              |
|                                  |
&a                                 &a + 1

Since the type of &a is int (*)[5], then it follows that the type of &a + 1 should also be int (*)[5].

If we dereference the pointer &a (as in *(&a)) then we get the actual array a. Arrays, like a, decay to a pointer to its first element, &a[0]. This pointer is pointing to the same location as &a (as shown in the "drawing" above).

If we change &a to &a + 1, then we get *(&a + 1) in the dereference. It's the "second" array (is it existed). Just like *(&a) is an array of five int, so is *(&a + 1). This array decays to a pointer to its first element &(*(&a + 1))[0].

Or perhaps think that &a is equal to &a + 0. Then it would be easy to see that *(&a) would be equal to *(&a + 0). And we know that *(&a) is equal to a which is equal to &a[0], which also means that *(&a + 0) have to be equal to &(*(&a + 0))[0]. That should make it easy to see what &(*(&a + 1))[0] might be.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • even if i change it to int *p=a; why am i getting the same output? – gokul goku Jun 05 '19 at 19:07
  • @gokulgoku Added a paragraph in the answer explaining it. – Some programmer dude Jun 05 '19 at 19:10
  • thanks i got it...i have another doubt when we had 1 to &a we reach to address after the end of the array ..so &a+1 gives an address after the array a but why *(&a+1) also give the same address – gokul goku Jun 05 '19 at 19:27
  • @gokulgoku That's because `*(&a + 1)` is equal to `(&a)[1]`, and the type of that is an array (of five `int`). And as any array it *decay* to a pointer to its first element. It's the same decay that happens for `a`. – Some programmer dude Jun 05 '19 at 19:31
  • well i tried hard but i couldn't understand it can you please help me to understand it better ...thanks!! – gokul goku Jun 05 '19 at 19:48
  • @gokulgoku I feel it's starting to get off-topic for this question now, but I've updated with more information that hopefully should help you understand what's going on. – Some programmer dude Jun 05 '19 at 20:04