Search

3.3 — Increment/decrement operators, and side effects

Incrementing (adding 1 to) and decrementing (subtracting 1 from) a variable are so common that they have their own operators in C. There are actually two versions of each operator -- a prefix version and a postfix version.

Operator Symbol Form Operation
Prefix increment (pre-increment) ++ ++x Increment x, then evaluate x
Prefix decrement (pre-decrement) –– ––x Decrement x, then evaluate x
Postfix increment (post-increment) ++ x++ Evaluate x, then increment x
Postfix decrement (post-decrement) –– x–– Evaluate x, then decrement x

The prefix increment/decrement operators are very straightforward. The value of x is incremented or decremented, and then x is evaluated. For example:

The postfix increment/decrement operators are a little more tricky. The compiler makes a temporary copy of x, increments or decrements the original x (not the copy), and then evaluates the temporary copy of x. The temporary copy of x is then discarded.

Let’s examine how this last line works in more detail. First, the compiler makes a temporary copy of x that starts with the same value as x (5). Then it increments the original x from 5 to 6. Then the compiler evaluates the temporary copy, which evaluates to 5, and assigns that value to y. Then the temporary copy is discarded.

Consequently, y ends up with the value of 5, and x ends up with the value 6.

Here is another example showing the difference between the prefix and postfix versions:

This produces the output:

5 5
6 4
6 4
6 4
7 3

On the third line, x and y are incremented/decremented before they are evaluated, so their new values are printed by cout. On the fifth line, a temporary copy of the original values (x=6, y=4) is sent to cout, and then the original x and y are incremented. That is why the changes from the postfix operators don’t show up until the next line.

Rule: Favor pre-increment and pre-decrement over post-increment and post-decrement. The prefix versions are not only more performant, you’re less likely to run into strange issues with them.

Side effects

A function or expression is said to have a side effect if it modifies some state (e.g. any stored information in memory), does input or output, or calls other functions that have side effects.

Most of the time, side effects are useful:

The assignment operator in the above example has the side effect of changing the value of x permanently. Even after the statement has finished executing, x will have the value 5. Operator++ has the side effect of incrementing x. The outputting of x has the side effect of modifying the console.

However, side effects can also lead to unexpected results:

C++ does not define the order in which function arguments are evaluated. If the left argument is evaluated first, this becomes a call to add(5, 6), which equals 11. If the right argument is evaluated first, this becomes a call to add(6, 6), which equals 12! Note that this is only a problem because one of the argument to function add() has a side effect.

Here’s another popular example:

What value does this program print? The answer is: it’s undefined.

If the ++ is applied to x before the assignment, the answer will be 1 (postfix operator++ increments x from 1 to 2, but it evaluates to 1, so the expression becomes x = 1).

If the ++ is applied to x after the assignment, the answer will be 2 (this evaluates as x = x, then postfix operator++ is applied, incrementing x from 1 to 2).

There are other cases where C++ does not specify the order in which certain things are evaluated, so different compilers will make different assumptions. Even when C++ does make it clear how things should be evaluated, some compilers implement behaviors involving variables with side-effects incorrectly. These problems can generally all be avoided by ensuring that any variable that has a side-effect applied is used no more than once in a given statement.

Rule: Don’t use a variable that has a side effect applied to it more than once in a given statement. If you do, the result may be undefined.

Please don’t ask why your programs that violate the above rule produce results that don’t seem to make sense. That’s what happens when you write programs that have “undefined behavior”. 🙂

For more information on undefined behaviors, revisit the “Undefined Behavior” section of lesson 1.3 -- A first look at variables, initialization, and assignment.

3.4 -- Sizeof, comma, and conditional operators
Index
3.2 -- Arithmetic operators

112 comments to 3.3 — Increment/decrement operators, and side effects

  • Lim Che Ling

    Hi, Alex,

    I am very confused about prefix and postfix ++ and the explanation term "evaluates and increment" as well as the rvalue and lvalue in this context.

    int x = 5;
    int y = x++;  //postfix ++ will Evaluate x, then increment x

    In this e.g., I understand in this way "First, a memory location x with value 5 is made a temporary copy with temp copy which has value 5. Then ‘Evaluate x’ means ‘assign value of temp copy 5 to y’, discard temp copy, incrementing x from 5 to 6."

    So with same token,

    int x = 5;
    ++x++; //This evaluates to ++(x++) due to postfix has higher precedence than prefix
    So on the postfix x++, it will Evaluate x, then increment x.

    In this case, "First, a memory location x with value 5 is made a temporary copy with temp copy which has value 5(now has two memory locations with value 5). Then ‘Evaluate x’ means ‘working on ++x’ which would evaluate to temporary copy increased to 6 then discard temporary copy, then incrementing original x from 5 to 6.

    Somehow, my understanding lacks of incorporation of r-value and l-value concept inside and so it seems compiler should compile though I think something is amiss.

    • Alex

      Don’t worry about r-values and l-values in this context. int x = 5 is just memory location x being initialized with value 5. x++ evaluates to 5 means that the compiler reduces that expression to the singular value 5. So even though x is incremented to 6 (as a side effect), the value 5 is assigned to y, since that’s what x++ evaluated to.

  • P8yan

    "If the ++ is applied to x before the assignment, the answer will be 1 (prefix operator++ increments x from 1 to 2, but it evaluates to 1, so the expression becomes x = 1)."

    I believe "prefix" above was meant to be "postfix".

  • Stephane

    Hi Alex, What do you mean by te outputting of x modifying the console?
    Great tutorial, thanks

    • Alex

      Outputting the value x to the console changes the state of the console such that it now displays the value of x, whereas before it did not.

  • Hi Alex. Can you please explain this program. This is the same program given in example in this chapter but I made a change in the line where the add function is called. I added pre-decrement operator. When I executed your example without any change, the output was 12, which means that my compiler (code blocks) first operates on the right argument. If it is so, then this program should have given 11 as output but the output given is 10.

    Thanks in advance

    • Alex

      Rule: Don’t use a variable that has a side effect applied to it more than once in a given statement. If you do, the result is undefined.

  • John

    Hi! Great tutorials!
    I have a bit of a question…
    I wrote a code that finds the prime numbers up to 100. It works fine, but I can’t figure it out how to deal with the first prime number, witch is 2.
    I put there a separate if statement, just to output 2, and after that it goes normal for the rest of the numbers.
    But I would like to make the code more generic, without working separately just for 2.

    Here’s the code:

    If I exclude this part:

    the code outputs prime numbers starting from 3…
    I have tried to change the initial values of dividend and divisor but without any success.

    • Alex

      I’d probably just move this part:

      inside the while loop. That way your while loop logic will work for the number 2. I can’t think of a way to not special-case it.

    • Liam

      I edited your code slightly (and used it as a means of practice) to give the user the ability to set their own limit.

  • MJ

    Great content, as always.

    Minor clarification point: Since x++ evaluates first, then assigns, I think this line in your second example should be changed from:

    to

    This would help the reader and is (I think) more in line with the definition provided.

  • Pritam Das

    #include<iostream>
    void main()
    {

       int x =5, y;
       y =x++ + ++x;
       cout<<++y<<" "<<y++;
    }
    the output is
    14 12

    dear alex ,plz tell me the logic behind the output,

    • Alex

      Rule: Don’t use a variable that has a side effect applied to it more than once in a given statement. If you do, the result is undefined.

  • John

    "C++ does not define the order in which function arguments are evaluated."

    In the example below, does this mean that it is not guaranteed that line 11, i.e. array[x++], will be evaluated to 10 for every compiler?

    x = 1
    10
    x = 2

    Is it correct wording to say that array[x++] evaluates to 10 in this example?

    • Alex

      Your program doesn’t call any functions with multiple arguments, so the order of evaluation issue isn’t applicable here.

      array[x++] will always evaluate to 10 here.

      • John

        So, looking at line 11 i the code above, i.e.

        From the Table in section 3.1 we find the precedence and the associativity for the post-increment (x++) and the array subscript operators [], respectively

        2 L->R    ++    Post-increment    (x++)
        2 L->R    []    Array subscript

        They have the same precedence level 2, and the same associativity L->R. How is the rule applied now? It’s not evaluated L->R, more from inside and out, how does the compiler read the code array[x++] (what rules are applied)?

        Just a note, the pre-increment operator (++x) has a lower order of precedence, and associative R->L, i.e.

        3 R->L    ++    Pre-increment    (++x)

        Replacing line 11 in the code with

        20

        • Alex

          In the post-increment case, the subscript operator is evaluated first (because it’s to the left of the postfix-++), and a function named operator[] is called with x++ as a parameter. At this point, x++ gets evaluated to the value of x, which is passed into operator[], which uses that value to subscript the array.

          It works the same way in the pre-increment case, except ++x evaluates to x+1, which is the value that gets passed into the subscript function and used to subscript the array.

  • Bernat

    I don’t see the problem in the last one, I mean, if ++ is evaluated first then x will be 2 and then the = will be evaluated which will make x be 2. If the = is evaluated first x = x which is one, and then the ++ will be evaluated which will cause x to be 2, right? I guess I’m doing it wrong in some part, but I don’t know how.

    • Alex

      I’ve updated the lesson with a little more detail about how these expressions evaluate. Have a re-read and let me know if you have additional questions.

      • Vlad

        I think I might know the cause of his confusion cause as I’ve scratched my head for a few seconds as well.

        "If the ++ is applied to x before the assignment, the answer will be 1 (postfix operator++ increments x from 1 to 2, but it evaluates to 1, so the expression becomes x = 1).

        If the ++ is applied to x after the assignment, the answer will be 2 (this evaluates as x = x, then postfix operator++ is applied, incrementing x from 1 to 2)."

        In the first paragraph, I think it should be prefix operator instead of postfix. Thanks for the awesome tutorials!

  • Arsala

    #include <iostream>

    using namespace std;

    int main()
    {
        int a=5;
        cout<<a++<<" "<<a++<<" "<<++a<<" "<<a++<<" "<<++a<<endl;
        return 0;
    }

    I have problem with this code , I am not understanding the output result that is 9 8 10 6 10 rather according to me it should 5 6 8 8 10
    please reply

  • Andreas

    question 1:

    question 2:

    question 3:

    right?

  • int main()
    {
        int x = 1;
        x = x++;
        std::cout << x;

        return 0;
    }

    What value does this program print? The answer is: it’s undefined. If the ++ is applied to x before the assignment, the answer will be 1. If the ++ is applied to x after the assignment, the answer will be 2.

    Could you explain this to me more????

    • Alex

      Unfortunately, the answer is somewhat complicated, and has to do with something called sequence points. A sequence point is a point in the program where it’s guaranteed that all side effects from previous evaluations have been performed. Between sequence points, the order of side effects resolution is indeterminate.

      The challenge with this particular program is that the side effects from postfix operator++ and the assignment operator aren’t separated by a sequence point, so the compiler is free to apply those side effects in either order.

      If the ++ is applied after the assignment: First x++ evaluates to 1. That 1 is assigned to x. Then the ++ is applied to x, which increments it to 2.
      If the ++ is applied to x before the assignment: First x++ evaluates to 1. The ++ is then applied, changing the value of x to 2. The value of 1 from the previous evaluation is then assigned to x, leaving x with the final value of 1.

      Both of these are valid interpretations of how to resolve the expression in C++, and different compilers may choose to do it differently.

  • Max Payne

    Hello Alex !
    I have a problem !
    #include <iostream>

    int main()
    {
        int x = 10;
        int z = (++x) + (x++);
        std::cout << z;
        return 0;
    }

    Why This code is producing the result 23 ?
    I think it should produce the result 22….
    PLEASE HELP ME !!

    • Alex

      When you use a variable with a side effect applied more than in a single statement, the result is undefined.

      On your compiler, it produces 23. On another compiler, it may produce 22. On a third compiler, it may produce something else.

  • saratha

    Hi

    int ch=20;
    cout<<ch<<++ch<<ch<<"\n";

    output I got was 21 21 20.somewhere I read calculations takes place from right to left.Printing takes place from left to right.kindly explain

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter