Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pointer Arithmetic: ++*ptr or *ptr++?

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?

like image 236
ipkiss Avatar asked Mar 06 '11 09:03

ipkiss


3 Answers

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!

like image 191
templatetypedef Avatar answered Sep 26 '22 10:09

templatetypedef


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.

like image 37
verbose Avatar answered Sep 23 '22 10:09

verbose


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.

like image 40
Morten Kristensen Avatar answered Sep 24 '22 10:09

Morten Kristensen