22

I am learning C language and quite confused the differences between ++*ptr and *ptr++.

For example:

int x = 19;
int *ptr = &x;

I know ++*ptr and *ptr++ produce different results but I am not sure why is that?

ipkiss
  • 13,311
  • 33
  • 88
  • 123

3 Answers3

54

These statements produce different results because of the way in which the operators bind. In particular, the prefix ++ operator has the same precedence as *, and they associate right-to-left. Thus

++*ptr

is parsed as

++(*ptr)

meaning "increment the value pointed at by ptr,". On the other hand, the postfix ++ operator has higher precedence than the dereferrence operator *. Thefore

*ptr++

means

*(ptr++)

which means "increment ptr to go to the element after the one it points at, then dereference its old value" (since postfix ++ hands back the value the pointer used to have).

In the context you described, you probably want to write ++*ptr, which would increment x indirectly through ptr. Writing *ptr++ would be dangerous because it would march ptr forward past x, and since x isn't part of an array the pointer would be dangling somewhere in memory (perhaps on top of itself!)

Hope this helps!

bruno
  • 105
  • 5
templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • @templatetypedef If you would do printf("%d",*ptr++) .It would first print the value at the location contained in ptr and then would increase ptr. – Algorithmist Mar 06 '11 at 09:15
  • @Algorithmist- That's correct; I think my answer covers this. Should I clarify it to make it more explicit? – templatetypedef Mar 06 '11 at 09:15
  • @templatetypedef i think * and ++ have the same priority but since their associativity is from L to R this is happening.Do you mean the same when you say ++ binds tighter than *. – Algorithmist Mar 06 '11 at 09:19
  • @Algorithmist- Thanks for pointing that out; you're absolutely correct. I will correct this. – templatetypedef Mar 06 '11 at 09:24
  • `*ptr++` is equivalent to `*(ptr++)` equivalent to `*(ptr = ptr + sizeof(datatype))` – instinct Jun 26 '14 at 14:47
  • `*ptr++` will be useful , if your ptr is pointing to a string and you want to jump to next char in the string. – jAYANT YADAV Aug 23 '16 at 17:45
  • 3
    @instinct: No, the latter form is not even remotely equivalent to `*(ptr++)`. – AnT stands with Russia Jan 10 '17 at 21:29
  • 1
    @instinct Pointer arithmetic accomodates for the size of the pointed-to type, so `ptr + sizeof(datatype)` will actually move past `sizeof(datatype) * sizeof(datatype)` bytes. See [this example](http://coliru.stacked-crooked.com/a/b2abb8be0ecfed2f). \[Note: Example is compiled as C instead of C++, due to `-xc` command-line option.\] – Justin Time - Reinstate Monica Jan 10 '17 at 22:07
  • As @AnT suggested `ptr++` is the same as `ptr = ptr + 1` meaning `ptr` will jump to the next address (that is what adding 1 means in the context of pointers), in particular jump to an address that is `sizeof(datatype)` bytes away from the starting address. As @Justin Time - Reinstate Monica explained, something like `ptr = ptr + 3` would mean to jump to the address which is `3*sizeof(datatype)` bytes away. So indeed `ptr = ptr + sizeof(datatype)` means to jump to the address which is `sizeof(datatype) * sizeof(datatype)` bytes away – bruno Mar 20 '20 at 16:02
14

The accepted answer is not correct. It's not the case that the postfix ++ operator has the same precedence as dereference/indirection *. The prefix and postfix operators have different precedence, and only the prefix operator has the same precedence as dereference/indirection.

As the precedence table shows, postfix ++ has a higher precedence than dereference/indirection *. So *ptr++ gets evaluated as *(ptr++). ptr++ evaluates to the current value of ptr; it increments ptr only as a side effect. The value of the expression is the same as the current value of ptr. So it won't have any effect on the value stored at the pointer. It will merely dereference the pointer (i.e., get the current value stored there, which is 19), then advance the pointer. In your example there is no defined value stored at the new position of ptr, so the pointer is pointing to garbage. Dereferencing it now would be dangerous.

Also as the table shows, prefix ++ has the same precedence as dereference/indirection *, but because of right-left associativity, it gets evaluated as ++(*ptr). This will first dereference the pointer (i.e., get the value stored at the address pointed to) and then increment that value. I.e., the value will now be 20.

The accepted answer is correct about the effects of the two, but the actual mechanism is different from the one given there.

verbose
  • 7,827
  • 1
  • 25
  • 40
  • This is a better answer than the selected one. Also, **Note 2** in [precedence table](http://www.difranco.net/compsci/C_Operator_Precedence_Table.htm) explains why `ptr++` evaluates to `ptr`. – fnisi Nov 16 '16 at 22:08
  • `*ptr` returns an l-value. So `++*ptr` will absolutely modify the value of the object pointed by `ptr` (`x`). – giusti Jan 10 '17 at 21:29
  • Obligatory [Linux kernel demonstration](https://github.com/torvalds/linux/blob/master/net/ipv4/route.c#L208) – giusti Jan 10 '17 at 21:37
  • @giusti Oops you're right, of course. Sorry and thanks. Edited. Sleepy brain introduced an error into what was a perfectly accurate answer for several months. – verbose Jan 10 '17 at 21:39
4

As templatetypedef says, but you should provide the parenthesis around *ptr to ensure the outcome. For instance, the following yields 1606415888 using GCC and 0 using CLang on my computer:

int x = 19;
int *ptr = &x;
printf("%d\n", *ptr++);
printf("%d\n", *ptr);

And you expected x to be 20. So use (*ptr)++ instead.

Morten Kristensen
  • 7,412
  • 4
  • 32
  • 52