Learn through the super-clean Baeldung Pro experience:
>> Membership and Baeldung Pro.
No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.
Last updated: March 18, 2024
In this tutorial, we’ll explain the difference between the pre-increment and post-increment operators in a loop.
Many programming languages such as Java or C offer specialized unary operators for the pre-increment and post-increment operations: () and (
). Both increment their argument variable by 1, but not the same way.
In particular, if x is an integer variable, and we pre-increment it as a part of a larger expression, the program will first add 1 to x and then evaluate x to the new value as the part of the evaluation of the entire expression. For example:
int x = 4;
int y = (++x) + 100;
// x = 5, y = 105
In contrast, the post-increment alternative will increment x but evaluate it to the old value inside the expression. Only after the expression has been evaluated does x have the new value:
int x = 4;
int y = (x++) + 100;
// x = 5, y = 104
As we can see, x=5 in both cases, but the final value of y is different.
Let’s analyze how to use these operations inside a loop. We’ll focus on the loops with increasing counters.
Each counter-based loop is specified by:
Schematically:
algorithm GenericLoopForm():
// This generic form demonstrates the structure of a loop
counter <- initialize_the_counter()
while termination condition is false:
body()
increment(counter)
If the termination test and the increment step are executed separately, it doesn’t matter which operator we use to increase the counter. The results will be the same.
However, if the termination condition test includes the increment operation, the two alternatives can lead to different results.
Let’s say that we want to print all the numbers between 1 and , inclusive. With the post-increment operator, we can try something like this:
algorithm PrintNumbersPostIncrement():
// This algorithm prints numbers from 1 to 10
// using post-increment in the condition
i <- 0
while i++ <= 10:
print(i)
How does this loop unfold?
First, we set to 0. Then, we check the condition
by testing if
and updating
to
right after. Following the update, we execute the loop’s body.
Then, we repeat the iteration. We test the condition . Since
, we set
to
and move on to the print statement.
We go on like this until right before the test
. Since we’re working with the post-increment operator, we use the current value of
to check the condition and then add 1 to it. So, since
before the check, and
,
passes the test, which means we’ll execute the loop’s body. Because we use the updated counter after the test, we print
. Then, we go back to the condition
. Since
, we stop the loop.
The problem is that we’re printing even though we wanted only the numbers
.
Therefore, we need to change the condition to or
. Unfortunately, that’s a bit counter-intuitive. If we test with
or
, it isn’t clear straight away that we want to include the number 10 in the loop. The condition with
would make more sense.
Let’s rewrite the loop to use the pre-increment operator. For instance:
algorithm PrintNumbersPreIncrement():
// This algorithm prints numbers from 1 to 10
// using pre-increment in the condition
i <- 0
while ++i <= 10:
print(i)
Will this loop include ? Well, since we first increment
and then check if its new value is
, the last number we print will be
. In the very next iteration,
evaluates to
, which is false, so we end the loop.
Coupling the increment steps with the termination checks is a bad idea because the code gets less readable. Even though we made both loops work in the previous examples, we still needed to think about the last number and the correct formulation of the stopping criterion.
Also, although correct, the above loops don’t have an intuitive initialization step. Both initialize the counter as . Until thoroughly analyzing the loops, most people would think that they print 0. In contrast, there’s no confusion with a loop with decoupled test and increment steps:
algorithm PrintNumbersWithSeparatedTestAndIncrement():
// This algorithm prints numbers from 1 to 10,
// separating the test and increment steps.
i <- 1
while i <= 10:
print(i)
i++ // ++i would also work here
Its meaning is immediately apparent. In general, we should strive for such a level of readability.
As we said before, the pre-increment and post-increment operators don’t affect the semantics and correctness of our loop when we use them to increase its counter.
However, some object-oriented languages, such as C++, allow us to implement the operators in our classes. Using such an object as our loop’s counter, we may see that the post-increment alternative runs slower than the pre-increment one.
The reason is that increments
but returns the old value. So, we need to store the new value until we evaluate the entire expression that
participates in. The loop’s complexity won’t change, but if
is a complex object, it can run slower because of copying the content of
in each increment step.
In this article, we covered the difference between the pre-increment and post-increment operators inside a loop’s termination condition.
As a rule of thumb, we should decouple the increment step from the termination condition test to make our code more readable.