Post-Increment in a while Condition – Why i++ < 3 Prints 1 2 3

The loop starts at 0 and the condition says “less than 3” — so it prints 0, 1, 2. Right? Wrong, and by two different one-off errors at once. This question from our C Programming Quiz App puts a post-increment inside a while condition, where its when-does-it-happen semantics decide both the first value printed and the last.

The Quiz Question

int i = 0;
while (i++ < 3)
    printf("%d ", i);

What is printed by this code?

  1. 0 1 2
  2. 1 2 3
  3. 0 1 2 3
  4. 1 2 3 4

The Correct Answer: 1 2 3

i++ yields the old value for the comparison, then increments. So each iteration: compare with the old i, bump i, and only then run the body — which prints the new i. Tracing it:

compare 0 < 3  true  → i becomes 1 → print 1
compare 1 < 3  true  → i becomes 2 → print 2
compare 2 < 3  true  → i becomes 3 → print 3
compare 3 < 3  false → i becomes 4 → loop ends

Verified on gcc 13.3 and Apple clang 21, clean under -ansi -Wall -Wextra:

$ gcc -ansi -Wall -Wextra postinc.c && ./a.out
1 2 3 | final i = 4

Note that final value — the increment ran on the failing comparison too, so after the loop i is 4, not 3. A second trap hiding behind the first.

Why Each Wrong Answer Is Wrong

Why not “0 1 2”?

That’s the output of the standard for (i = 0; i < 3; i++) pattern, where the increment happens after the body. Here the increment happens before the body (inside the condition), so the body never sees 0 — by its first run, i is already 1.

Why not “0 1 2 3”?

Four numbers would need four iterations, but the loop runs its body exactly three times — the comparisons that pass are 0<3, 1<3, 2<3. This option combines “body sees the old value” (wrong) with “runs an extra time” (also wrong).

Why not “1 2 3 4”?

Right first value, one iteration too many. When the comparison 3 < 3 fails, the loop exits without running the body — 4 exists in i after the loop, but nothing prints it. (If the condition were i++ <= 3, this would be the answer.)

Post-Increment in Conditions: One Expression, Two Moments

The confusion dissolves once you see that i++ < 3 packs two events with different timing: the comparison uses the pre-increment value, and by the time the body runs, the increment has already landed. The equivalent long-hand loop makes it explicit:

for (;;) {
    int old = i;
    i = i + 1;
    if (!(old < 3)) break;
    printf("%d ", i);
}

Swap in pre-increment and the comparison uses the new value — while (++i < 3) prints 1 2 and leaves i at 3 (we ran that too). Neither variant is “wrong”, but both make the reader do this kind of trace, which is why style guides tend to keep increments out of conditions unless the idiom is universal (like while (*dst++ = *src++); for string copy). The same yields-old-value rule drives the *p++ pointer question and, pushed into a single expression twice, becomes the x++ + ++x undefined-behavior question.

Frequently Asked Questions

Why does while (i++ < 3) print 1 2 3 and not 0 1 2?

The comparison uses the old value of i, but the increment completes before the body runs. So the body always sees the freshly incremented value: 1, 2, 3.

What is i after while (i++ < 3) ends?

4. The final comparison (3 < 3, false) still performs its increment. This “one extra increment” after the last failed test is a classic source of off-by-one bugs.

What would while (++i < 3) print instead?

1 2, leaving i at 3. Pre-increment bumps first and compares the new value, so the loop admits one fewer iteration and the body sees the same value the comparison used.

Related Reading

Recommended Books

This question is #71 in the C Programming Quiz App — 155 questions with explanations covering basics, operators, pointers, 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>