The answer is in 6.8.5.3 of the C standard:
1774 The statement
for ( clause-1 ; expression-2 ; expression-3 ) statement
behaves as follows:
1775 The expression >expression-2 is the controlling expression that
is evaluated before each execution of the loop body.
1776 The expression expression-3 is evaluated as a void expression
after each execution of the loop body.
1777 If clause-1 is a declaration, the scope of any
identifiers it declares is the remainder of the declaration and the
entire loop, including the other two expressions;
1778 it is reached in the order of execution before the first
evaluation of the controlling expression.
1779 If clause-1 is an expression, it is evaluated as a void
expression before the first evaluation of the controlling
expression.134)
1780 Both clause-1 and expression-3 can be omitted.
1781 An omitted expression-2 is replaced by a nonzero constant.
There is a sequence point established between execution of the printf statement and then the incrementing of i
. The printf
statement and i
is expression-3
in this case, not a conditional, so the statement is valid though not best practice.