C pointer arithmetic snippet - c

I have a program that I'm trying to decode. It is translated to C from another language (whose name is not spoken here), and as I want to understand how it works, I am slowly rewriting the code and simplifying it to use all the nice logical constructs C has to offer.
The following little bit keeps popping up in my code, with varying values of X and Y:
ptr[X]--;
while(ptr[X])
{
ptr[X]--;
ptr += Y;
}
ptr is of type char *, and I can't really make assumptions about the state of the array at any point because it's pretty deeply embedded in loops and dependent on input and output. I can successfully "simplify" that to:
for(ptr[X]--; ptr[X]; ptr[X]--, ptr += Y);
But that's just awful. Ever so slightly better is:
for(ptr[X]--; ptr[X]; ptr += Y) ptr[X]--;
I want to know if anyone can come up with a better simplification of the above code, I would greatly appreciate it. This occurs in no less than five places, and is impairing my ability to simplify and understand the flow control, so if anyone can provide a more consise/readable version, that would be awesome. If anyone can just offer any sort of fancy insight into that code, that would be awesome too, although I basically understand what it does.
Insight into the code for a specific X and/or Y can also help. Y tends to be between -2 and 2, and X is usually 1, for what its worth.

ptr[X] is equivalent to *(ptr + X), so we can rewrite it as follows:
for((*(ptr + X))--; *(ptr + X); (*(ptr + X))--, ptr += Y);
Now there's a lot of redundancy here, so we can simplify this to:
char *ptr_plus_x = ptr + X;
for((*ptr_plus_x)--; *ptr_plus_x; (*ptr_plus_x)--, ptr_plus_x += Y);
Then we can get rid of ptr_plus_x entirely:
ptr += X;
for((*ptr)--; *ptr; (*ptr)--, ptr += Y);
In English, we visit the memory locations at offsets X, X+Y, X+2Y, X+3Y, ..., decrementing each memory location, until we find a memory location that is 0. But, the test for 0 always occurs after the decrement, so we're really looking for the first memory location in that sequence with a value of 1. Once we find that, we decrement it to 0 and quit.
If Y is 1, then we decrement a string of consecutive memory locations going forwards, up to and including the first 1. If Y is -1, the same thing happens, but searching backwards from offset X. If Y is 0, an infinite loop occurs. If Y is any other value, the search pattern skips various entries.
It's not a very intuitive function, so I can see why you're confused.

I'll throw in:
ptr[X]--
while (ptr[X]--) ptr+=Y;
first evaluate, then decrement (for while condition, that is)
Edit: OK, i'll hate myself in the morning. Goto's are ok at this level, right?
dec: ptr[x]--
while (ptr[X]){
ptr+=Y;
goto dec;
}
(i honestly dont know whether to leave this or not.)
EDIT2: so, how about this one? (tcc didn't complain)
while (ptr[X]--?ptr[X]--,ptr+=Y:0){}
EDIT 2 1/2;
//longshot
while (ptr[X]--?ptr[X]--,ptr+=Y, ptr[X]:0){}
If all else fails..
EDIT3: Last one for tonight.
while (ptr[X]--?ptr[X]--,ptr+=Y:0){
if (!ptr[X]) break;
}//good luck with this, it has been very amusing.

The website for it-which-shall-not-be-named states:
The semantics of the it-which-shall-not-be-named states commands can also
be succinctly expressed in terms of C, as follows (assuming that p has
been previously defined as a char*):
> becomes ++p;
< becomes --p;
+ becomes ++*p;
- becomes --*p;
. becomes putchar(*p);
, becomes *p = getchar();
[ becomes while (*p) {
] becomes }
So it seems like it should be fairly easy to convert it over to C.
EDIT: Here is the Hello World BF converted to C++.

It's quite simple as is, already. Instead of trying to write less statements, I would rather try to grasp the intent and add some comment.
An example of 'a' meaning of the snippet: decrease all elements of a column (X) of a matrix of Y columns. You would need that to draw a vertical line of +'ses, for instance, in a language that has no direct assignment.
You could clarify this meaning by showing the indices directly:
// set elements of column to cGoal
for( int decrementsToGoal = cGoal; decrementsToGoal != 0; --decrementsToGoal ) {
// decrease all elements of column X
for( int row = cMaxRows; M[ row*matrixsizeY + columnX ]; --row ) {
--M[ row*matrixsizeY + columnX ];
}
}
Good luck :)

Related

Can someone explain how this works? [duplicate]

I saw this code:
if (cond) {
perror("an error occurred"), exit(1);
}
Why would you do that? Why not just:
if (cond) {
perror("an error occurred");
exit(1);
}
In your example it serves no reason at all. It is on occasion useful when written as
if(cond)
perror("an error occured"), exit(1) ;
-- then you don't need curly braces. But it's an invitation to disaster.
The comma operator is to put two or more expressions in a position where the reference only allows one. In your case, there is no need to use it; in other cases, such as in a while loop, it may be useful:
while (a = b, c < d)
...
where the actual "evaluation" of the while loop is governed solely on the last expression.
Legitimate cases of the comma operator are rare, but they do exist. One example is when you want to have something happen inside of a conditional evaluation. For instance:
std::wstring example;
auto it = example.begin();
while (it = std::find(it, example.end(), L'\\'), it != example.end())
{
// Do something to each backslash in `example`
}
It can also be used in places where you can only place a single expression, but want two things to happen. For instance, the following loop increments x and decrements y in the for loop's third component:
int x = 0;
int y = some_number;
for(; x < y; ++x, --y)
{
// Do something which uses a converging x and y
}
Don't go looking for uses of it, but if it is appropriate, don't be afraid to use it, and don't be thrown for a loop if you see someone else using it. If you have two things which have no reason not to be separate statements, make them separate statements instead of using the comma operator.
The main use of the comma operator is obfuscation; it permits doing two
things where the reader only expects one. One of the most frequent
uses—adding side effects to a condition, falls under this
category. There are a few cases which might be considered valid,
however:
The one which was used to present it in K&R: incrementing two
variables in a for loop. In modern code, this might occur in a
function like std::transform, or std::copy, where an output iterator
is incremented symultaneously with the input iterator. (More often, of
course, these functions will contain a while loop, with the
incrementations in separate statements at the end of the loop. In such
cases, there's no point in using a comma rather than two statements.)
Another case which comes to mind is data validation of input parameters
in an initializer list:
MyClass::MyClass( T const& param )
: member( (validate( param ), param) )
{
}
(This assumes that validate( param ) will throw an exception if
something is wrong.) This use isn't particularly attractive, especially
as it needs the extra parentheses, but there aren't many alternatives.
Finally, I've sometimes seen the convention:
ScopedLock( myMutex ), protectedFunction();
, which avoids having to invent a name for the ScopedLock. To tell
the truth, I don't like it, but I have seen it used, and the alternative
of adding extra braces to ensure that the ScopedLock is immediately
destructed isn't very pretty either.
This can be better understood by taking some examples:
First:
Consider an expression:
x = ++j;
But for time being, if we need to assign a temporarily debug value, then we can write.
x = DEBUG_VALUE, ++j;
Second:
Comma , operators are frequently used in for() -loop e.g.:
for(i = 0, j = 10; i < N; j--, i++)
// ^ ^ here we can't use ;
Third:
One more example(actually one may find doing this interesting):
if (x = 16 / 4), if remainder is zero then print x = x - 1;
if (x = 16 / 5), if remainder is zero then print x = x + 1;
It can also be done in a single step;
if(x = n / d, n % d) // == x = n / d; if(n % d)
printf("Remainder not zero, x + 1 = %d", (x + 1));
else
printf("Remainder is zero, x - 1 = %d", (x - 1));
PS: It may also be interesting to know that sometimes it is disastrous to use , operator. For example in the question Strtok usage, code not working, by mistake, OP forgot to write name of the function and instead of writing tokens = strtok(NULL, ",'");, he wrote tokens = (NULL, ",'"); and he was not getting compilation error --but its a valid expression that tokens = ",'"; caused an infinite loop in his program.
The comma operator allows grouping expression where one is expected.
For example it can be useful in some case :
// In a loop
while ( a--, a < d ) ...
But in you case there is no reason to use it. It will be confusing... that's it...
In your case, it is just to avoid curly braces :
if(cond)
perror("an error occurred"), exit(1);
// =>
if (cond)
{
perror("an error occurred");
exit(1);
}
A link to a comma operator documentation.
There appear to be few practical uses of operator,().
Bjarne Stroustrup, The Design and Evolution of C++
Most of the oft usage of comma can be found out in the wikipedia article Comma_operator#Uses.
One interesting usage I have found out when using the boost::assign, where it had judiciously overloaded the operator to make it behave as a comma separated list of values which can be pushed to the end of a vector object
#include <boost/assign/std/vector.hpp> // for 'operator+=()'
using namespace std;
using namespace boost::assign; // bring 'operator+=()' into scope
{
vector<int> values;
values += 1,2,3,4,5,6,7,8,9; // insert values at the end of the container
}
Unfortunately, the above usage which was popular for prototyping would now look archaic once compilers start supporting Uniform Initialization
So that leaves us back to
There appear to be few practical uses of operator,().
Bjarne Stroustrup, The Design and Evolution of C++
In your case, the comma operator is useless since it could have been used to avoid curly braces, but it's not the case since the writer has already put them. Therefore it's useless and may be confusing.
It could be useful for the itinerary operator if you want to execute two or more instructions when the condition is true or false. but keep in mind that the return value will be the most right expression due to the comma operator left to right evalutaion rule (I mean inside the parentheses)
For instance:
a<b?(x=5,b=6,d=i):exit(1);
The boost::assign overloads the comma operator heavily to achieve this kind of syntax:
vector<int> v;
v += 1,2,3,4,5,6,7,8,9;

How does the C expression s[i ++] = t[j ++] exactly work in order?

I'm new in C, stuck in understanding the expression s[i ++] = t[j ++], I don't know how it's possible that an array element gets accessed with a variable and then the variable increase itself and then the array element just accessed is again accessed with the original variable and then gets assigned to another array's element, I'm confused, I think to understand the exact process might involve some low-level knowledges, but I don't want to digress too far away, is there any way to understand it easily and clearly?
In C language, the expression i++ causes i to be incremented, but the expression i++ itself evaluates to the value i had before being incremented. So the expression s[i++] = t[j++] has the same behaviour as:
s[i] = t[j];
i = i + 1;
j = j + 1;
except that the precise order is not specified. For that last reason, the rule is that a variable should only be modified once: s[i++] = t[i++] would invoke Undefined Behaviour.
Like any other complicated-looking expression, it's easier to understand this if you break it down into parts.
The key is that innermost part (or "subexpression") i++. I assume you know what i++ does by itself, although in this example, we're hopefully going to get a deeper appreciation of what i++ is actually good for. Why would you want to "increment i, but return the old value"? What's the use of this? Well, the main use is that it's super useful for moving along an array.
Lets look at a simpler example. Suppose we have an array a that we want to store some numbers in. The most basic way is
int a[10];
a[0] = 12;
a[1] = 34;
a[2] = 5678;
Another very good way is to use a second variable like i to keep track of where we're storing:
i = 0;
a[i] = 12;
i = i + 1;
a[i] = 34;
i = i + 1;
a[i] = 5678;
i = i + 1;
I've written this out in "longhand", but of course in C, you would almost never write it this way, because the "C way" is the much more concise
i = 0;
a[i++] = 12;
a[i++] = 34;
a[i++] = 5678;
So first, make sure you understand that the "shorthand" and "longhand" forms work exactly the same way. Make sure you understand that when we say something like
a[i++] = 34;
what this means is "store 34 into the slot in array a indicated by i, and then update i to be one more than is used to be, so that it indicates the next slot."
In other words, we use an expression like a[i++] whenever we want to move along an array and do something with its elements, one by one, in order.
So far we were storing values into the array, but the idiom works just as well for fetching values out of an array. For example, this code prints those three elements, again one at a time, in order:
i = 0;
printf("%d\n", a[i++]);
printf("%d\n", a[i++]);
printf("%d\n", a[i++]);
My point is, again, that any time you see an expression like a[i++], you should think "we're moving along the array".
So now, finally, we can look at the expression you initially asked about:
s[i++] = t[j++];
Here we have two instances of the idiom. We're using i to move along the array s, and we're using j to move along the array t. We're fetching from t as we move along, and we're storing the values into s.
I don't know whether s and t are arrays of characters, or integers, or what. Also I don't know that s and t are truly arrays -- they might actually be pointers, pointing into some arrays. But I don't really have to know those things to know that the essential meaning of s[i++] = t[j++] is "copy elements from array t to array s, using j to keep where we are in t, and i to keep track of where we are in s".
[The above is an answer to your original question. The rest of this answer isn't directly related, but is essential to avoid inadvertently writing incorrect programs using ++ and --.]
As I said, the subexpression i++ and the idiom a[i++] are super useful for moving through arrays. But there are a couple things to beware of. (Actually it's just one thing, but it crops up in lots of different ways.)
Earlier I wrote the code
i = 0;
printf("%d\n", a[i++]);
printf("%d\n", a[i++]);
printf("%d\n", a[i++]);
to print the first three elements of the array a. But it prints them as bare, isolated numbers. What if I want to always see which array index each number comes from? That is, what if I'm tempted to write something like this:
i = 0;
printf("%d: %d\n", i, a[i++]); /* WRONG */
printf("%d: %d\n", i, a[i++]); /* WRONG */
printf("%d: %d\n", i, a[i++]); /* WRONG */
If I wrote this, my intent would be that I would see the obvious display
0: 12
1: 34
2: 56788
But when I actually tried it just now, I got this instead:
1: 12
2: 34
3: 5678
The numbers 12 and 34 and 5678 are right, but the indices 1, 2, and 3 are all wrong -- they're off by one! How did that happen?
And the answer is that although i++ is, as I said, "super useful", it turns out that there's a fine line between "super useful" and what's called undefined behavior.
That printf call
printf("%d: %d\n", i, a[i++]); /* WRONG */
looks fine, but it's not actually well-defined, because the compiler does not necessarily evaluate everything left-to-right, so it's not actually guaranteed that it will use the old value of i for the %d: part. The compiler might evaluate things from right to left, meaning that a[i++] will happen first, meaning that %d: will print the new value, instead -- which appears to be what happened when I tried it.
Here's another potential issue. Your original question was about
s[i++] = t[j++];
which, as we've seen, copies elements from t to s based on two possibly-different indices i and j. But what if we know we always want to copy t[1] to s[1], t[2] to s[2], t[3] to s[3], etc.? That is, what if we know that i and j will always be the same, so we don't even need separate i and j variables? How would we write that? Our first try might be
s[i++] = t[i++]; /* WRONG */
but that can't be right, because now we're incrementing i twice, and we'll probably do something totally broken like copying t[1] to s[2] and t[3] to s[4]. But if we want to only increment i once, should it be
s[i++] = t[i]; /* WRONG */
or
s[i] = t[i++]; /* WRONG */
But the answer is that neither of these will work. In expressions like these, which have i in one place and i++ in the other place, there's no way to tell whether i gets the old value or the new value. (In particular, there's no left-to-right or right-to-left rule that would tell us.)
So although expressions like i++ and a[i++] are indeed super useful, you have to be careful when you use them, to make sure you don't go over the edge and have too much happening at once, such that the evaluation order becomes undefined. Sometimes this means you have to back off, and not use the "super useful" idiom, after all. For example, a safe way to print those values would be
printf("%d: %d\n", i, a[i]); i++;
printf("%d: %d\n", i, a[i]); i++;
printf("%d: %d\n", i, a[i]); i++;
and a safe way to copy from t[1] to s[i] would be
s[i] = t[i]; i++;
You can read more in this answer about how to recognize well-defined expressions involving ++ and --, and how to avoid the undefined ones.
The evaluations of s[i++] and t[j++] are unsequenced relative to each other. Semantically, it's equivalent to:
t1 = i;
t2 = j;
s[t1] = t[t2];
i = i + 1;
j = j + 1;
with the caveat that the last three assignments can happen in any order, even simultaneously (either in parallel or interleaved)1. The compiler doesn't have to create temporaries, either - the whole thing can be evaluated as
s[i] = t[j];
i = i + 1;
j = j + 1;
Alternately, the side effects of i++ and j++ can be applied before the update to s:
t1 = j;
j = j + 1;
t2 = i;
i = i + 1;
s[t2] = t[t1];
The current values of i and j must be known before you can index into the arrays, and the value of t[j] must be known before it can be assigned to s[i], but beyond that there's no fixed order of evaluation or of the application of side effects.
This is why expressions like x = x++ or a = b++ * b++ or a[i] = i++ all invoke undefined behavior - there's no fixed order for evaluating or applying side effects, so the results can vary by compiler, compiler settings, even by the surrounding code, and the results don't have to be consistent from run to run.

+(+k--) expression in C

I saw this question in a test in which we have to tell the output of the following code.
#include<stdio.h>
int main(){
int k = 0;
while(+(+k--)!=0)
k=k++;
printf("%d\n", k);
return 0;
}
The output is -1. I am unsure why this is the answer, though.
What does the expression +(+k--) mean in C?
This code is deeply, perhaps deliberately, confusing. It contains a narrowly-averted instance of the dread undefined behavior. It's hard to know whether the person who constructed this question was being very, very clever or very, very stupid. And the "lesson" this code might purport to teach or quiz you about -- namely, that the unary plus operator doesn't do much -- is not one that's important enough, I would think, to deserve this kind of subversive misdirection.
There are two confusing aspects of the code, the strange condition:
while(+(+k--)!=0)
and the demented statement it controls:
k=k++;
I'm going to cover the second part first.
If you have a variable like k that you want to increment by 1, C gives you not one, not two, not three, but four different ways to do it:
k = k + 1
k += 1
++k
k++
Despite this bounty (or perhaps because of it), some programmers get confused and cough out contortions like
k = k++;
If you can't figure out what this is supposed to do, don't worry: no one can. This expression contains two different attempts to alter k's value (the k = part, and the k++ part), and because there's no rule in C to say which of the attempted modifications "wins", an expression like this is formally undefined, meaning not only that it has no defined meaning, but that the whole program containing it is suspect.
Now, if you look very carefully, you'll see that in this particular program, the line k = k++ doesn't actually get executed, because (as we're about to see) the controlling condition is initially false, so the loop runs 0 times. So this particular program might not actually be undefined -- but it's still pathologically confusing.
See also these canonical SO answers to all questions concerning Undefined Behavior of this sort.
But you didn't ask about the k=k++ part. You asked about the first confusing part, the +(+k--)!=0 condition. This looks strange, because it is strange. No one would ever write such code in a real program. So there's not much reason to learn how to understand it. (Yes, it's true, exploring the boundaries of a system can help you learn about its fine points, but there's a line in my book between imaginative, thought-provoking explorations versus dunderheaded, abusive explorations, and this expression is pretty clearly on the wrong side of that line.)
Anyway, let's examine +(+k--)!=0. (And after doing so, let's forget all about it.) Any expression like this has to be understood from the inside out. I presume you know what
k--
does. It takes k's current value and "returns" it to the rest of the expression, and it more or less simultaneously decrements k, that is, it stores the quantity k-1 back into k.
But then what does the + do? This is unary plus, not binary plus. It's just like unary minus. You know that binary minus does subtraction: the expression
a - b
subtracts b from a. And you know that unary minus negates things: the expression
-a
gives you the negative of a. What unary + does is... basically nothing. +a gives you a's value, after changing positive values to positive and negative values to negative. So the expression
+k--
gives you whatever k-- gave you, that is, k's old value.
But we're not done, because we have
+(+k--)
This just takes whatever +k-- gave you, and applies unary + to it again. So it gives you whatever +k-- gave you, which was whatever k-- gave you, which was k's old value.
So in the end, the condition
while(+(+k--)!=0)
does exactly the same thing as the much more ordinary condition
while(k-- != 0)
would have done. (It also does the same thing as the even more complicated-looking condition while(+(+(+(+k--)))!=0) would have done. And those parentheses aren't really necessary; it also does the same thing as while(+ +k--!=0) would have done.)
Even figuring out what the "normal" condition
while(k-- != 0)
does is kind of tricky. There are sort of two things going on in this loop: As the loop runs potentially multiple times, we're going to:
keep doing k--, to make k smaller and smaller, but also
keep doing the body of the loop, whatever that does.
But we do the k-- part right away, before (or in the process of) deciding whether to take another trip through the loop. And remember that k-- "returns" the old value of k, before decrementing it. In this program, the initial value of k is 0. So k-- is going to "return" the old value 0, then update k to -1. But then the rest of the condition is != 0 -- and it's not true that 0 != 0. That is, 0 is equal to 0, so we won't make any trips through the loop, so we won't try to execute the problematic statement k=k++ at all.
In other words, in this particular loop, although I said that "there are sort of two things going on", it turns out that thing 1 happens one time, but thing 2 happens zero times.
At any rate, I hope it's now adequately clear why this poor excuse for a program ends up printing -1 as the final value of k. Normally, I don't like to answer quiz questions like this -- it feels like cheating -- but in this case, since I fundamentally disagree with the whole point of the exercise, I don't mind.
At first glance it looks like this code invokes undefined behavior however that is not the case.
First let's format the code correctly:
#include<stdio.h>
int main(){
int k = 0;
while(+(+k--)!=0)
k=k++;
printf("%d\n", k);
return 0;
}
So now we can see that the statement k=k++; is inside of the loop.
Now let's trace the program:
When the loop condition is first evaluated, k has the value 0. The expression k-- has the current value of k, which is 0, and k is decremented as a side effect. So after this statement the value of k is -1.
The leading + on this expression has no effect on the value, so +k-- evaluated to 0 and similarly +(+k--) evaluates to 0.
Then the != operator is evaluated. Since 0!=0 is false, the body of the loop is not entered. Had the body been entered, you would invoke undefined behavior because k=k++ both reads and writes k without a sequence point. But the loop is not entered, so no UB.
Finally the value of k is printed which is -1.
Here's a version of this that shows operator precedence:
+(+(k--))
The two unary + operators don't do anything, so this expression is exactly equivalent to k--. The person that wrote this most likely was trying to mess with your mind.

Multiplying by i** is it possible in C? Like i++ why i**doesn't work in C?

Is it possible to multiply using i** in C?
For example, I can increment i using i++. Why doesn't i** work in C?
#include <stdio.h>
int main(void)
{
int result;
for (int i = 2; i < 100; i**){
result = i + 1;
printf("%i\n", result);
}
return 0;
}
No, it's not possible. There is no operator like ** in C unlike unary increment (++) and decrement (--) operators. You should have try i *= i.
"i++" is shorthand for "i = i + 1".
If there were an "i**" it would, by extension, mean "i = i * 1" and be incredibly useless. So they never implemented it.
Even after editing to clarify grammar, it still isn't clear from your question that you expect "i**" to perform as "i = i * i". I'm guessing that is what you meant from the answer you accepted. If you learn to explain things clearly to others you will find that you think more clearly and can work out the answer to many questions for yourself.
Possible, but instead of i** which doesn't work, you need to use:
for (int i = 2; i < 100; i *= i)
Generally, multiplication operation does not use in for loop increment/decrement part because suppose our variable(i) start from 0, then every time multiplication become 0.
Multiplying by i** is it possible in C? Like i++ why i**doesn't work in C?
No,it's not possible. for your second quesition answer is explained like,
Basically , increment and decrement have exceptional usage as pre increment and post increment and a language cannot be extended just if someone needs an additional functionality as it would slow down because of extending its grammer.
So most used ++i,i++,--i,i-- are present and not others
You can use some codes like this for your task:
i*=i;
=i*i;

Prefix and postfix operators necessity

What is the necessity of both prefix and postfix increment operators? Is not one enough?
To the point, there exists like a similar while/do-while necessity problem, yet, there is not so much confusion (in understanding and usage) in having them both. But with having both prefix and postfix (like priority of these operators, their association, usage, working).
And do anyone been through a situation where you said "Hey, I am going to use postfix increment. Its useful here."
POSTFIX and PREFIX are not the same. POSTFIX increments/decrements only after the current statement/instruction is over. Whereas PREFIX increments/decrements and then executes the current step. Example, To run a loop n times,
while(n--)
{ }
works perfectly. But,
while(--n)
{
}
will run only n-1 times
Or for example:
x = n--; different then x = --n; (in second form value of x and n will be same). Off-course we can do same thing with binary operator - in multiple steps.
Point is suppose if there is only post -- then we have to write x = --n in two steps.
There can be other better reasons, But this is one I suppose a benefit to keep both prefix and postfix operator.
[edit to answer OP's first part]
Clearly i++ and ++i both affect i the same but return different values. The operations are different. Thus much code takes advantage of these differences.
The most obvious need to have both operators is the 40 year code base for C. Once a feature in a language is used extensively, very difficult to remove.
Certainly a new language could be defined with only one or none. But will it play in Peoria? We could get rid of the - operator too, just use a + -b, but I think it is a tough sell.
Need both?
The prefix operator is easy to mimic with alternate code for ++i is pretty much the same as i += 1. Other than operator precedence, which parens solves, I see no difference.
The postfix operator is cumbersome to mimic - as in this failed attempt if(i++) vs. if(i += 1).
If C of the future moved to depreciate one of these, I suspect it would be to depreciate the prefix operator for its functionality, as discussed above, is easier to replace.
Forward looking thought: the >> and << operators were appropriated in C++ to do something quite different from integer bit shifting. Maybe the ++pre and post++ will generate expanded meaning in another language.
[Original follows]
Answer to the trailing OP question "do anyone been through a situation where you saidd "Hey, I am going to use postfix increment. Its useful here"?
Various array processing, like with char[], benefit. Array indexing, starting at 0, lends itself to a postfix increment. For after fetching/setting the array element, the only thing to do with the index before the next array access is to increment the index. Might as well do so immediately.
With prefix increment, one may need to have one type of fetch for the 0th element and another type of fetch for the rest.
size_t j = 0;
for (size_t i = 0, (ch = inbuffer[i]) != '\0'; i++) {
if (condition(ch)) {
outbuffer[j++] = ch; // prefer this over below
}
}
outbuffer[j] = '\0';
vs.
for (size_t i = 0, (ch = inbuffer[i]) != '\0'; ++i) {
if (condition(ch)) {
outbuffer[j] = ch;
++j;
}
}
outbuffer[j] = '\0';
I think the only fair answer to which one to keep would be to do away with them both.
If, for example, you were to do away with postfix operators, then where code was once compactly expressed using n++, you would now have to refer to (++n - 1), or you would have to rearrange other terms.
If you broke the increment or decrement out onto its own line before or after the expression which referred to n, above, then it's not really relevant which you use, but in that case you could just as easily use neither, and replace that line with n = n + 1;
So perhaps the real issue, here, is expressions with side effects. If you like compact code then you'll see that both pre and post are necessary for different situations. Otherwise there doesn't seem to be much point in keeping either of them.
Example usage of each:
char array[10];
char * const end = array + sizeof(array) / sizeof(*array);
char *p = end;
int i = 0;
/* set array to { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 } */
while (p > array)
*--p = i++;
p = array;
i = 0;
/* set array to { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } */
while (p < end)
*p++ = i++;
They are necessary because they are already used in lots of code, so if they were removed then lots of code would fail to compile.
As to why they ever existed in the first place, older compilers could generate more efficient code for ++i and i++ than they could for i+=1 and (i+=1)-1. For newer compilers this is generally not an issue.
The postfix version is something of an anomaly, as nowhere else in C is there an operator that modifies its operand but evaluates to the prior value of its operand.
One could certainly get by using only one or other of prefix or postfix increment operators. It would be a little more difficult to get by using only one or other of while or do while, as the difference between them is greater than the difference between prefix and postfix increment in my view.
And one could of course get by without using either prefix or postfix increment, or while or do while. But where do you draw the line between what's needless cruft and what's useful abstraction?
Here's a quickie example that uses both; an array-based stack, where the stack grows towards 0:
#define STACKSIZE ...
typedef ... T;
T stack[STACKSIZE];
size_t stackptr = STACKSIZE;
// push operation
if ( stackptr )
stack[ --stackptr ] = value;
// pop operation
if ( stackptr < STACKSIZE )
value = stack[ stackptr++ ];
Now we could accomplish the exact same thing without the ++ and -- operators, but it wouldn't scan as cleanly.
As for any other obscure mechanism in the C language, there are various historical reasons for it. In ancient times when dinosaurs walked the earth, compilers would make more efficient code out of i++ than i+=1. In some cases, compilers would generate less efficient code for i++ than for ++i, because i++ needed to save away the value to increment later. Unless you have a dinosaur compiler, none of this matters the slightest in terms of efficiency.
As for any other obscure mechanism in the C language, if it exists, people will start to use it. I'll use the common expression *p++ as an example (it means: p is a pointer, take the contents of p, use that as the result of the expression, then increment the pointer). It must use postfix and never prefix, or it would mean something completely different.
Some dinosaur once started writing needlessly complex expressions such as the *p++ and because they did, it has became common and today we regard such code as something trivial. Not because it is, but because we are so used at reading it.
But in modern programming, there is absolutely no reason to ever write *p++. For example, if we look at the implementation of the memcpy function, which has these prerequisites:
void* memcpy (void* restrict s1, const void* restrict s2, size_t n)
{
uint8_t* p1 = (uint8_t*)s1;
const uint8_t* p2 = (const uint8_t*)s2;
Then one popular way to implement the actual copying is:
while(n--)
{
*p1++ = *p2++;
}
Now some people will cheer, because we used so few lines of code. But few lines of code is not necessarily a measure of good code. Often it is the opposite: consider replacing it with a single line while(n--)*p1++=*p2++; and you see why this is true.
I don't think either case is very readable, you have to be a somewhat experienced C programmer to grasp it without scratching your head for five minutes. And you could write the same code like this:
while(n != 0)
{
*p1 = *p2;
p1++;
p2++;
n--;
}
Far clearer, and most importantly it yields exactly the same machine code as the first example.
And now see what happened: because we decided not to write obscure code with lots of operands in one expression, we might as well have used ++p1 and ++p2. It would give the same machine code. Prefix or postfix does not matter. But in the first example with obscure code, *++p1 = *++p2 would have completely changed the meaning.
To sum it up:
There exist prefix and postfix increment operators for historical reasons.
In modern programming, having two different such operators is completely superfluous, unless you write obscure code with several operators in the same expression.
If you write obscure code, will find ways to motivate the use of both prefix and postfix. However, all such code can always be rewritten.
You can use this as a quality measure of your code: if you ever find yourself writing code where it matters whether you are using prefix or postfix, you are writing bad code. Stop it, rewrite the code.
Prefix operator first increments value then its uses in the expression. Postfix operator,first uses the value in the expression and increments the value
The basic use of prefix/postfix operators are assembler replaces it with single increment/decrement instruction. If we use arithmetic operators instead of increment or decrement operators, assembler replaces it with two or three instructions. that's why we use increment/decrement operators.
You don't need both.
It is useful for implementing a stack, so it exists in some machine languages. From there it has been inherited indirectly to C (In which this redundancy is still somewhat useful, and some C programmers seems to like the idea of combining two unrelated operations in a single expression), and from C to any other C-like lagnuages.

Resources