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

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

  • Benur21

    >" 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)."

    Doesn't ++ have a higher precedence level than =? So it is applied first than assignment.

    • Alex

      This is a bit of weirdness in C++ involving a concept called a sequence point. A sequence point is a point where it is guaranteed all side effects have been resolved.

      Here's what we know: postfix ++ will always evaluate before = (based on the rules of precedence). x++ will also always return the value of x as the result of operator++ being evaluated.

      Here's where we get into trouble: The increment of x is considered a side effect. Therefore, we can only say for sure that the increment happens after we hit the next sequence point. You can read about where C++ defines sequence points to be here: https://en.wikipedia.org/wiki/Sequence_point

      Unfortunately (if my understanding is correct) the next sequence point only occurs at the end of the entire statement being evaluated. We can't be assured as to when the increment will occur before then.

  • Benur21

    > "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."

    Why doesn't it just first evaluates x, then increments or decrements it? No need for a copy.

  • Martian

    Hi, Alex.
    One of the things I like from your lessons is the rules you establish after the explanations; even if you don't get all the reasoning that leads to it, you still get an unequivocal and practical way to approach code.
    All this said, this is the first time I don't get a rule. I still don't really get what is a side effect (or rather, what isn't one). Up until now I think every line we wrote has a side effect.
    And the wording of the rule makes it even more confusing:
    "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."
    If by "use" you mean returning or printing or copying the value of said variable, then I can't think of any other thing to do with a variable. And I wonder if it would be maybe better to just state "Don't apply more than one side effect to a variable in the same statement". Otherwise it seems that it's ok to do this if you don't use the variable later (and why would you do that?). Maybe I'm reading it wrong, but I still feel that the sentence is not totally clear.

    Also I wanted to thank you so much for this great course. I'm learning a lot!

    • Alex

      In the context of C++, a side effect is basically any operation that results in modified state for an object (variable) or system (e.g. the output streams).

      Put another way, "A side effect is a result of an operator, expression, statement, or function that persists even after the operator, expression, statement, or function has finished being evaluated." When we talk about applying side effects to variables, we really mean "doing anything that changes the variable's value".

      Notable things that aren't side effects: Temporary values, such as the result of expressions (including evaluating a variable's value, or a function's return value).

      Side effects are generally useful -- almost every expression we write exists to generate a value that we want to do something with -- either store somewhere, or send somewhere (to the console, a file, etc...).

      Saying "Don't apply more than one side effect to a variable in the same statement" isn't quite strict enough, because even taking the value of a variable (which isn't a side effect) in the same statement where a side effect is applied to that variable is dangerous. We see this in the following example:

      There's only one side effect applied to x in this statement, but it's still dangerous because we're not sure when the side effect will be applied.

      Perhaps an alternative wording could be, "if you modify a variable's value in a statement, don't use that variable again in the same statement, otherwise undefined behavior may result".

      Is that clearer? If not, what points of confusion still exist?

      • Martian

        Thank you, Alex! That makes it a lot more clear to me, at least I will know to avoid using variables in that way.
        I partially get your explanation about side effects but it's still a little too abstract to me and I struggle to see it in the actual code. Please correct me if I'm wrong, I know I'm probably simplifying it:
        A side effect is always a value. Not any value, but one that is a result of an operation and is stored in a variable. So if we use that variable in the same statement as the side effect we can't know in which order the values will be evaluated.

        • Alex

          A side effect isn't a value, a side effect is anything that modifies the permanent state of something else. But the remainder is true: if we use a variable with a side effect applied more than once in a statement, we can't be sure when the side effect will be applied in all cases -- so it's better to just avoid this case altogether.

  • Fateh Chadha

    Is there any difference between if and else if?? Because they seem to do the same exact thing!

    • Matthis

      Well from my understanding "else if" will only be executed if your previous "if" statement was false.
      Take a look :

  • prince

    hi Alex
    these are two function used in stack implementation by many sites such as geeksforgeeks
    shouldn't they be used as they contain pre increment(side effects) and assignment operator in same given statement.
    void push(struct Stack* stack, int item)
    {
    if (isFull(stack))
    return;
    stack->array[++stack->top] = item;
    printf("%d pushed to stack\n", item);
    }

    second question
    on codeblocks it evaluates to 13 if x=5 intially.
    x=++x + x++;

    • nascardriver

      Hi prince!

      The push function is not a problem, because you're not assigning a new value to @stack, you're only modifying it's members. Think of it like this

      This obviously isn't problematic.

  • Ujjwal pratap

    #include "stdafx.h"
    #include <iostream>
    int main()
    {
        int x;
        std::cout << "enter :";
        std::cin >> x;
        ++x;                            or when we use x++, then results are same. Why??
        std::cout << x;
        return 0;
    }

    • nascardriver

      Hi Ujjwal!

      The only difference between ++prefix and postfix++ is their return value.
      ++prefix increments and then reads the value to be returned.
      postfix++ reads the value to be returned, then increments, then returns the value which was stored prior to the increment.
      When you're not using the return value of the oparator++, use ++prefix.

  • Nux

    I don't understand this exemple.

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

    From the lesson 3.1 (http://www.learncpp.com/cpp-tutorial/31-precedence-and-associativity/)

    I have learn than the Pre-increment operator ++ have an operator precedence of 3 and the operator = an operator precedence of 15

    So this is a define situation. Pre-increment should be resolve first like this: x = (x++);
    and the Incrematation of x should be resolve before the assignement of the x's copy to x

    Or am I missunderstanding something ?

    • Alex

      It seems like it should be as you say (which is why this gets so many C++ programmers into trouble). C++ actually gives the compiler a LOT of leeway in determining the order of evaluation. For example, although you might code a() + b(), either a() or b() could be evaluated first.

      With side effects, this gets a bit weird. We know that x++ both returns the value of x (which happens immediately upon evaluation), and applies a side effect to x that will increment its value. However, the compiler is given a lot of leeway to determine when to schedule the ++ part of the operation. In practice, the ++ could happen before the assignment, or after. If you (or anyone else) want to do more reading, look up the concept of "sequence points" (or sequencing, as of C++11).

  • Nux

    I think the std:: is missing here.

    Here is a version with std:: added

  • Samira Ferdi

    Which is the better or best practices? using x++ or x+=1 for using in a function?

    • nascardriver

      Hi Samira!

      There's no difference. I use ++x unless the 1 is variable and I might change it in the future.

    • Eric

      Hi Samira,

      Logically the two statements are the same (apart from the side affect) but there *could* be a difference in the machine code generated by the compiler.

      The unusual syntax of ++n (or —n) was included in the original C language because the statement would likely result in a single machine code operation often called INC (or DEC) for increment/decrement.  This would presumably perform much better than having to load 2 registers and using an ADD operation.

      But this is highly dependent on the compiler and the CPU instruction set.  And a good compiler/optimizer should be able to reduce n += 1 to an INC instruction anyway.

      Intel x86 CPUs have the INC/DEC instructions but Raspberry Pi computers do not, for example.

      I like to use ++n where it makes sense in case my code is compiled on a CPU that supports the faster increment/decrement operations.

  • Samira Ferdi

    Can we use increment/decrement that adding in real number like adding/subtract 0.1 or 0.001?

    Is there in C++ that implementing other operators in expression like increment/decrement?

    • nascardriver

      Hi Samira!

      The default increment and decrement operators are fixed at 1. Later on you'll learn about defining own data types and own operators which you could use to implement such behavior.

  • Byron

    Hi Alex,
    I wanted to check whether my compiler evaluates the left or right argument first, using the code you provided in this lesson. In theory, one of the two values should have been 11 and the other 12, no? In fact both return 12. Am I understanding things incorrectly here?

    • Alex

      You're seeing unexpected results because you're breaking one of the most broken rules in C++: Don't use a variable with side effects applied more than once in an expression. Operator++ applies a side effect, so you're running afoul of this rule, and the result you're seeing is the result of undefined behavior.

      Here's a program I whipped up that will tell you your evaluation order:

      gen() returns 9 the first time it's called, and 8 the second time. By looking whether left is 8 and right is 9 or vice-versa, we can determine which operand got evaluated first.

      • Byron

        Thanks! And apologies for forcing you to repeat the same thing again.
        I thought I was not using it twice in an argument actually as I was using the operator only once. I guess it's the variable that I should count and not how many times I am using the operator.

      • Rohit

        Hi Alex.

        I'm failing to understand your program. The way I see it, the function "gen()" is called two times with its own local scope each time, so it would return 9 every time. Getting called once wouldn't have any effect on any subsequent calls. This is especially true considering "x" is a static integer.

        Well that's what I had initially thought, anyway. What am I understanding incorrectly? How do the 2 calls to gen() provide different results?

        • nascardriver

          Hi Rohit!

          @x is in the scope of @get, but @x's lifetime begins with the first call to @gen and ends with the program's exit, not with the end of @gen. You can treat @x as a global variable with limited scope.

          References
          Lesson 4.3 — Static duration variables

          • Rohit

            I see, thanks!

            So it's because of the static variable, which comes in the future. I was thinking "static" was another way of having a constant variable but that's where the English language messed me up, haha.

  • Michael

    Hi Alex,
    The post increment operator has a higher precedence than assignment operator. Doesn't it mean that

    will be executed in the same way as

    which has a defined behavior?

    • Alex

      No. The higher precedence means x++ is evaluated first. That evaluation means x++ will be evaluated to produce the value x. The actual increment part is not guaranteed to happen immediately (think of post-increment as "increment at some point in the future"). So it could be the assignment happens first, or the ++ happens first.

      This was probably originally done for performance reasons, but is one of those annoying quirks of the language that you have to learn not to do.

  • Aditya

    So, is it best if we don't use the increment/decrement operators at all?

    • Alex

      You should feel free to use the increment and decrement operators. Just don't use the variables you're using those operators on more than once in a given statement.

  • The Perplexed Programmer

    Reminds me of a joke.

    "Hey, how to increment a variable C?"
    "C++..."

  • 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 all code inside code tags: [code]your code here[/code]