(*p)++ vs *p++ in C – Which One Changes the Value?

(*p)++ and *p++ differ by nothing but a pair of parentheses — and they do completely different things. One increments the value the pointer targets; the other moves the pointer itself. This question from our C Programming Quiz App checks whether you know which is which, and the answer comes down to operator precedence.

The Quiz Question

int a = 10;
int *p = &a;
(*p)++;
printf("%d", a);

What is printed by this code?

  1. 10
  2. 11
  3. Compile error
  4. Undefined behavior

The Correct Answer: 11

The parentheses force the dereference first: (*p) is the object p points to — the variable a — and the ++ then increments that object. Since p points at a, the statement is simply a++ in disguise. Verified on gcc 13.3 and Apple clang 21, warning-free under -Wall -Wextra:

$ gcc -Wall -Wextra inc.c && ./a.out
11

Why Each Wrong Answer Is Wrong

Why not 10?

10 is what you’d see if the increment had hit the pointer instead of the value — which is exactly what happens without the parentheses. Postfix ++ binds tighter than unary *, so *p++ parses as *(p++): increment the pointer, dereference its old value. We demonstrated with an array so the moved pointer still lands somewhere valid:

int arr[] = {10, 99};
int *p = arr;
int v = *p++;                 /* v = old *p; p moves to arr[1] */
printf("%d %d %d", v, arr[0], *p);
10 10 99

The yield is 10, arr[0] is still 10 — nothing was incremented except the pointer, which now sits on 99. That’s the behavior behind idioms like while (*dst++ = *src++); for string copy.

Why not “Compile error”?

(*p) is an lvalue of type int, and applying ++ to an int lvalue is ordinary C. Both compilers accept it silently.

Why not “Undefined behavior”?

Only one modification happens in the expression, so there’s no sequence-point violation. Compare with x++ + ++x — two unsequenced modifications of the same object — which genuinely is UB, as covered in our sequence points post. (*p)++ as a standalone statement is perfectly defined.

The Four Increment Forms, Side by Side

Precedence rule: postfix operators (++ after) bind tighter than unary operators (*, ++ before). Unary operators bind right-to-left. That gives four distinct combinations:

Expression   Parses as     Effect
──────────   ──────────    ─────────────────────────────────────────
*p++         *(p++)        move pointer forward; yield OLD target's value
(*p)++       —             increment the target value; yield its old value
*++p         *(++p)        move pointer forward; yield NEW target's value
++*p         ++(*p)        increment the target value; yield the new value

Note that ++*p needs no parentheses to hit the value — both operators are unary, applied right-to-left, so the dereference happens first anyway. The parentheses in (*p)++ are needed only because postfix ++ would otherwise grab p first.

Frequently Asked Questions

What is the difference between *p++ and (*p)++?

*p++ increments the pointer and yields the value it pointed to before moving. (*p)++ leaves the pointer alone and increments the pointed-to value. The parentheses override postfix ++‘s higher precedence.

Is (*p)++ undefined behavior?

No. It performs a single modification of a single object — equivalent to a++ when p points at a. UB requires modifying the same object twice (or modifying and independently reading it) without a sequence point.

What does ++*p do?

Same target as (*p)++ — it increments the pointed-to value — but as a pre-increment it yields the new value. No parentheses needed, because unary operators apply right-to-left: dereference first, then increment.

Related Reading

Recommended Books

This question is #123 in the C Programming Quiz App — 155 questions with explanations covering operators, pointers, memory, and more.
Download on Google Play →

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>