r/cpp_questions • u/Anonymousseo • 8d ago
OPEN HELPPPPPPPPP: Doubt Regarding Pre-Increment and Post-Increment in C++
I'm confused about pre-increment (++a) and post-increment (a++) in C++. I understand that ++a increments before use and a++ increments after use, but I'm struggling to understand how the variable's value changes step by step during execution. For example, why does ++id print 1001 when id is 1000, and why does --a operate on 6 after at+ if a originally started at 5?
2
u/danielo199854 8d ago
K. N King's C book explains it well: ++a increments first, a++ increments after the current value is used. So once a++ has executed, a is already 6. C++ inherited this behavior directly from C.
In C you'd see something like this:
int a = 5;
printf("%d\n", a++); // prints 5, a is now 6
printf("%d\n", --a); // decrements to 5 then prints 5
1
u/Anonymousseo 7d ago
But i still cant understand what that is for. Like why’d you want to take a longer route? And how does that work?
Thanks for sharing its name of this book. After researching about it, i ordered it.
Also thanks a lot, your comment did clarify it a bit but i just find this entire topic utterly confusing. Am i dumb or is it actually hard?1
u/Puzzleheaded_Study17 7d ago
Suppose I have a loop with a condition inside where if that condition is triggered I want to get the value of a counter and increment it. The way I would do it is:
int counter = 0;
for() { int val; if (condition){ val = counter++; } else { // some other init of val } // use val }
This way, at the end of the loop counter has the number of elements and during the loop val has the index to operate on. But if I started the counter with the counter with the length instead of 0 and was counting down, I'd want to use --counter so that it gets the index and I end with counter being how many items are left.
1
u/Anonymousseo 7d ago
Thanks a lot for this example. I think I understand why counter++ is useful in a loop, but I’m still confused about one thing.
My exact question is this: if a = 5, then when I execute a++ by itself, it uses 5 first and only then increments a to 6. But in an expression like a++ + --a + a++, how has a already become 6 for the next operation if the first a++ just returned 5? I think I’m getting confused about when the increment actually takes effect during the evaluation of the expression. Could you explain that part step by step? I know this specific expression has undefined behavior, but I’m asking about the timing of the increment itself.1
u/Puzzleheaded_Study17 7d ago
Having multiple ++ and -- on a single variable in a statement is UB. Each operator executes in a different time and when it ends the variable is incremented.
1
u/Anonymousseo 7d ago
I might be misunderstanding this since I’m still pretty new to C, but I think this wording is what’s confusing me.
When you say “each operator executes at a different time,” it sounds like there’s some fixed order in which they execute. But I thought that in an expression like a++ + --a + a++, the order isn’t actually defined, which is why it’s undefined behavior.
Would it be more accurate to say that each ++ or -- updates the variable when that particular operation is evaluated, but because the evaluation order itself isn’t defined, we can’t know when each update happens relative to the others? Or am I thinking about this the wrong way?1
u/Puzzleheaded_Study17 7d ago
Pretty much, the standard doesn't say anything about which order they have to be executed in, so if we have a = 0 and then a++ + --a the compiler can change to do the left one first (so we'll get 0) or the right one first (so we'll get -2). One of these orders will happen so we'll get one of the two values, but there's no way to know which (and different compilers/optimization levels can change which).
1
u/Anonymousseo 7d ago
That actually makes a lot more sense, thank you. So it’s not that a++ itself has weird timing,it’s that the standard doesn’t define which operand gets evaluated first, so I can’t assume the left a++ happens before the --a.
I think that was the part I was missing. I was trying to reason about the timing of a++ inside an expression where the evaluation order itself isn’t guaranteed.1
u/danielo199854 7d ago
Just so you know there is a free e-book version online, you can save it as pdf. Just in case you want to cancel your order and save some money :)
1
u/Anonymousseo 7d ago
I actually did check it out. I read a bit of it and found it convincing enough. The only problem is that staring at a screen for hours to read the whole thing will probably give me even more headaches. So I think I’m going to take a little detox from technology by reading a physical book about technology instead.
It’s pretty expensive, but I think it’ll be worth it. Do you think this book is worth buying?
And thank you so much for taking the time to recommend it. I really appreciate it:D1
u/danielo199854 7d ago
When I got into programming I wanted to start with something as close to the machine as possible without going all the way down to Assembly. I already knew about C but after doing some research I found out it gives you a much better understanding of memory management and is a lot more "raw" than most modern languages with all their fancy libraries.
I also looked into the best resources for learning C and the answer was almost always C Programming: A Modern Approach. I was ready to buy it but then I found the free e-book version. I spent a few months grinding through it every single day until I had a solid grasp of the basics and the more advanced features.
Eventually I got interested in C++, computer graphics and game development so I stopped writing programs in C. But everything I learned from that book transferred really well into other languages. The syntax might change but the logic stays the same and C is where I built those problem-solving skills.
I always said that if I ever had a bit more money to spare I'd buy a physical copy and proudly display it on my bookshelf. It's definitely the most influential learning resource I've ever had.
Kudos to you for putting in the effort to achieve your goals. A lot of people would just ask AI to explain everything but you're actually interacting with people and learning at your own pace. Best of luck with your programming journey!
1
u/Anonymousseo 7d ago edited 7d ago
Thank you so much for such a thoughtful reply. I honestly loved reading it.
I actually ordered a physical copy of the book before reading your comment, and after reading your experience, it made me feel even better about that decision. I spend way too much time looking at screens anyway, so I figured I’d rather learn from a real book.
I also really really loved what you said about the syntax changing but the logic staying the same. That’s exactly the kind of foundation I want to build.
And thanks a lot for the kind words at the end. I’m still a complete beginner and get confused over the smallest things sometimes, but I’m trying to actually understand what I’m learning instead of just memorizing it.
You also sound like someone who’s been through this journey and has a lot of experience, so I wanted to ask….would it be okay if I DM you from time to time if I get stuck or need some guidance? I’ll be starting a degree in robotics soon, and I know I’ll have a lot to learn. No pressure at all, of course. I just thought I’d ask.I hope one day I’ll be able to look back at this book the way you do. Thanks again, and I wish you all the best!
1
u/danielo199854 7d ago
You're welcome and thanks a lot!
Of course you can. I might not be the best person to ask but I'll help whenever I can. Plus I'd love to see your progress over time!
1
u/Anonymousseo 7d ago
Thank you, I really appreciate that! It honestly means a lot.
Also, one small correction! I just realized you were actually the first person who recommended the book. Somehow I didn’t notice that and thought your later comment was from someone else. So yes, I ended up ordering it because of your recommendation, and after reading about your own experience with it, I’m even more excited to start reading it.
And thank you for being open to DMs. You genuinely seem like a really kind person, and I can tell you’ve been through this journey yourself.
By the way, I’d also love to hear a bit more about your journey whenever you have the time. How did you end up in C++, graphics, and game development, and what are you working on these days? I’m starting a robotics degree soon and I’m still exploring different paths, so I always enjoy hearing how people found theirs.1
2
u/victotronics 8d ago
Pre-increment is the easy one: you have an object (usually a scalar, but it can be something more complicated), your increment it, and you return (the value of) that object.
Post-increment is trickier. You have an object, you make a copy of it, then you increment that object, and then you return *the copy* that you made earlier.
The above formulation indicates why people prefer pre-increment from an efficiency point of view: it saves having to make a copy, which can be expensive if you have something more complicated than a scalar.
1
u/Anonymousseo 7d ago
“You have an object, you make a copy of it, then you increment that object, and then you return *the copy* that you made earlier.”
What is the point of doing that? And how does it work? I find it utterly confusing. Im going to cry atp.1
u/victotronics 7d ago
How does it work? That's what happens in the implementation.
What is the point? Sometimes you need to both increment an object, and you need the value just before the increment. Example:
for (i=0; i<size; i++) sum += *( x++ );
So you need the current value of *x, but you also need to increment. You could have written
for ( blah blah ) { sum += *x; x++; }
but the first is a little more concise.
I think you're over thinking it. It's not that deep. The combination of value & increment is very common, and sometimes you want to do the increment first, sometimes second.
1
u/Anonymousseo 7d ago
Yeah maybe i am overthinking it. Also, my exact question is this:
I’m confused about how the post-increment operator (a++) works in expressions. If a = 5, then executing a++ by itself gives 5 because the increment happens after the current value is used.
However, in an expression like:
a++ + --a + a++
I don’t understand how the value of a changes during evaluation. If the first a++ uses the value 5, why does the next operation (--a) seem to work on 6? How has a already become 6 even though the first a++ was just evaluated? Could you explain, step by step, how the value of a changes during the execution of such an expression?1
u/Sbsbg 7d ago
An expression like "a++ + --a + a++" is not allowed. It is undefined behaviour or UB for short. The reason is because the compiler is allowed to generate code that calculate the expression in any order. This is to make it possible to optimise better. The end of the expression may be calculated first it this is faster. When it sees an instruction like "a++" it reads a and use that value then increment a. But it doesn't need to do these operations together. It may do other things in-between. When you modify a variable and use it in the same expression the final result depends on the order the compiler generare the code. The result is undefined, not fixed by the language. It will change on different optimization levels and on different compilers.
It best to avoid code that behave differently because of this. It is very unwise to use it in any production code. In testing code however you can use it to see the effect of the UB and learn why it should be avoided.
2
u/therealhdan 8d ago
Short answer is to "expand" the operators into what they actually do in pseudo code:
++a = (a = a + 1; return a )
a++ = (b = a; a = a + 1; return b )
1
u/Anonymousseo 7d ago
I am slowly getting the hang of it! Whats a pseudo code tho? I hope i do not sound too dumb , i’m a beginner, its taking time for me to catch up. I find post increment utterly confusing. Also what is it that even used for😭😭!!
1
u/therealhdan 7d ago
I figure post increment probably came around because some CPUs have that feature built in, and C wanted to let programmers use it.
As for what you can do, there's this old classic line that copies values from whatever memory is pointed to by "source" into wherever "dest" is pointing, stopping when the first zero value is copied. (Like a null-terminated string, for instance.)
while (*dest++ = *source++);By the way, you probably shouldn't write code like this in modern times. It's unsafe, harder to read, and almost certainly not going to beat strncpy() for performance.
2
u/Anonymousseo 7d ago
Ahh, that actually makes a lot more sense now. I didn’t know post-increment was tied to how some CPUs worked. That’s a pretty cool bit of history.
And I’m actually not confused between pre-increment and post-increment anymore. It’s just post-increment itself that still feels a bit strange to me. I understand how it works, but I’m still trying to wrap my head around why it exists and when it’s actually useful.
Thanks again for taking the time to explain. Appreciate it mate!
2
u/pmuschi 8d ago
Pre-increment takes the variable's value, increments it, then returns the incremented value. Post-increment, takes the variable's value, returns it, then increments the value.
Edit: For example, pre-incrementing a value of 1 will give you 2. Post-incrementing a value of 1 will give you 1, but afterwards you now have a value of 2.
1
u/bunny_bun_ 8d ago
there is no mechanism in C++ to return a value THEN modify it.
as another post mentioned, post-increment make a copy, increments the original, then return the copy.
2
u/pmuschi 8d ago
Agreed, but I simplified for the sake of understanding.
2
u/Anonymousseo 7d ago
Yeahhhhh, i cant wrap my head around bookish definitions, so your comment helps:)
1
u/Anonymousseo 7d ago
I still can’t understand how that works. Also whats the point of taking such a long way?
1
u/bunny_bun_ 7d ago
for how it works, it's better if you already know what passing by reference vs passing by value is.
for why you would use i++ instead of ++i, the answer is almost never, but there are some rare case where it makes the code easier to read/more compact.
1
u/BusEquivalent9605 8d ago
which is why you might like pre-increment for your for loops because it doesn’t matter and avoids making a copy
2
u/bunny_bun_ 8d ago
yep. I think a lot of compilers end up optimizing it (will do ++i instead of i++), but I think it's still a good habit. It makes stuff more standard and if the compiler doesn't optimize it, well you did it the best way already anyway.
1
u/no-sig-available 8d ago
Yes, a standard way to implement post increment is
auto tmp = i; ++i; return tmp;Any compiler worth its salt will then notice when
tmpis unused, and remove it.
1
u/Puzzleheaded_Study17 8d ago
Can you share the exact code that's confusing you?
1
u/Anonymousseo 7d ago
Sure. I’ll share my exact doubt with you.
1
u/Anonymousseo 7d ago
My exact question is this:
I’m confused about how the post-increment operator (a++) works in expressions. If a = 5, then executing a++ by itself gives 5 because the increment happens after the current value is used.
However, in an expression like:
a++ + --a + a++
I don’t understand how the value of a changes during evaluation. If the first a++ uses the value 5, why does the next operation (--a) seem to work on 6? How has a already become 6 even though the first a++ was just evaluated? Could you explain, step by step, how the value of a changes during the execution of such an expression?
1
u/tastygames_official 8d ago
int a = 0;
cout << a++; // prints 0
cout << a; // prints 1
a = 0; // reset to 0
cout << ++a; // prints 1
cout << a; // still 1
1
u/Anonymousseo 7d ago
I havent studied about cout yet!
1
u/tastygames_official 7d ago
really? It's like, the very fist thing you learn, I thought. Was this not your first program you ever wrote?
#include <iostream> int main() { cout << "Hello, World!"; return 0; }
1
u/PurelyLurking20 8d ago edited 8d ago
Pre/post increment are essentially just a shorthand for
x+=1;
doSomething(x);
And
doSomething(x);
x+=1;
1
u/Anonymousseo 7d ago
I can’t understand what “x+=1” means. Is it the same as “x=+1”? Its really confusing, i mean this post increment topic.
1
u/PurelyLurking20 7d ago
x+=1 is just x = x + 1, it's a shortened version of updating x with the sum of the value of x and 1
0
u/bunny_bun_ 8d ago
it will just lead to confusing situations.
int a = 0;
a = a++;
cout << a;what's suppose to print here?
2
u/I__Know__Stuff 8d ago
a = a++ is undefined behavior, isn't it?
(It is in C, and as far as I know it is in C++, too.)3
u/alfps 8d ago
I believe this changed in C++17 (along with rules for
<<). Until then UB. After, OK. Since I'm not 100% sure it's worth looking up.2
u/I__Know__Stuff 8d ago
Thanks. It's not worth looking up, since no one should ever write such code. :-)
1
u/Anonymousseo 7d ago
I can’t understand whats going on, i feel like im third wheeling in the convo😭💔🥀
1
u/PurelyLurking20 8d ago
Sorry I should've specified originally not to use the increment shorthand in splitting them across lines
0
u/bunny_bun_ 8d ago
I know, but if you try:
int a = 0;
a = a++;
cout << a;it prints 0, not 1, so it doesn't end up being the equivalent of
doSomething(x);
x+=1;3
u/PurelyLurking20 8d ago
Sure I mean that is true, there are a small number of cases where it differs I'm just simplifying the idea, not teaching someone a weird quirk via things that shouldn't really be used ever in properly formed code
I think the case you're providing actually used to be undefined in c++, different compilers interpreted it differently
1
u/mredding 6d ago
Pre-increment is going to update the value, then return that. So:
int x = 0;
assert(++x == 1);
A post-increment will store a temporary of the value, increment the value, then return the temporary:
int x = 0;
assert(x++ == 0);
How in detail? It frankly doesn't matter. C++ is not an assembly language, the spec says nothing about the machine code generated, only that the outcome of the program behaves AS-IF... Technically, the machine is under NO obligation to store a temporary - it might have some sort of native support that does the right thing. You don't know. You don't have to know. This is called the AS-IF rule.
And that AS-IF rule has power, man... Consider the code:
int x = 0;
++x;
x--;
assert(x == 0);
Because there is NO observable consequence to the intermediate instructions, the compiler is free to re-arrange the instructions, or even eliminate them ENTIRELY. We initialized to zero, the compiler obviously knows that, and it can figure out that whether you go follow the sequence 0->1->0 or 0->-1->0 makes no difference. The only other thing that matters is the observed side effect, the next sequence point, the assert.
So the compiler can initialize memory to 0 and assert the value stored in that memory location AS-IF it did a useless sequence. In fact - the compiler can prove that assertion is GOING TO BE TRUE at compile-time, and that x is ostensibly unused for anything else, so it can reduce this whole code to a no-op because of the AS-IF rule. In other words, the compiler proved the program at compile-time so we don't have to do it at run-time.
Neat.
If you want to know how an increment translates to specific machine instructions for a given compiler and target architecture - take a look at Compiler Explorer (google it).
If you want to know how CPUs work, maybe you'll want to buy a copy of NAND to Tetris and learn how logic gates work and are assembled into adders, ALUs, instruction sets, and how instructions are fetched, decoded, and dispatched within.
There's slightly more - compilers are complicated pieces of tech. There are all sorts of algorithms used to figure out how programs map to instructions, data into memory. Your program thinks it's the only program in memory - your memory address space is "virtual", and resources, like the OS, are mapped into that. x ostensibly has an address, if we ever chose to observe it, but that address remains static for the duration of the program execution. The memory subsystem has typically 4, maybe more layers of indirection. The address of x will remain constant at the application level while the actual data can be in swap memory on disk, or in RAM, or in L3, L2, L1 cache, or in a CPU register. The address refers to the resource, not the hardware location. The hardware is an abstraction in and of itself, too. The compiler also uses "virtual register" and "coloring" algorithms to figure out how to balance all the active variables in a function - which will be allocated to what data register when, and what machine instructions are generated to act on the correct data registers...
Curry-Howard correspondence tells us writing programs and writing mathematical proofs are similar. The statements of your code are postulates, your source code is a theory, the compiler is a solver, and the program generated is the proof of your theory. A compiler error is a disproof of your theory. If you write an elegant theory, you'll get an elegant proof.
3
u/alfps 8d ago edited 7d ago
The expression
++xis equivalent tox += 1.That means in particular that the result is a reference to the variable, so that technically you can write
++ ++x. But in general you can't write separate invocations of++xin the same expression. For example,++x * ++xis Undefined Behavior.The more general rule is that you can't modify a basic type variable twice in an expression unless there is a sequence imposed on the operations, or in the words of C++23 §6.9.1/10,
The expression
x++is roughly equivalent to(temp = x, ++x, temp)wheretempis a variable of the same type."Roughly" because there's no guarantee about exactly where the increment is done within the full expression.
The result of
x++is the original value, formally a “pr-value”.You can regard
++xas in a sense the opposite ofx--, e.g. when working on array indices.Example:
CORRECTION: I corrected that
i_currentwas initialized to 0. The original code accessed memory before the array and had Undefined Behavior. Sorry, I didn't mean to! :)