How to get and evaluate the Expressions from a string in C
char *str = "2*8-5+6";
This should give the result as 17 after evaluation.
Try by yourself. you can Use stack data structure to evaluate this string here is reference to implement (its in c++)
stack data structre for string calcualtion
You have to do it yourself, C does not provide any way to do this. C is a very low level language. Simplest way to do it would be to find a library that does it, or if that does not exist use lex + yacc to create your own interpreter.
A quick google suggests the following:
http://www.gnu.org/software/libmatheval/
http://expreval.sourceforge.net/
You should try TinyExpr. It's a single C source code file (with no dependencies) that you can add to your project.
Using it to solve your problem is just:
#include <stdio.h>
#include "tinyexpr.h"
int main()
{
double result = te_interp("2*8-5+6", 0);
printf("Result: %f\n", result);
return 0;
}
That will print out: Result: 17
C does not have a standard eval() function.
There are lots of libraries and other tools out there that can do this.
But if you'd like to learn how to write an expression evaluator yourself, it can be surprisingly easy. It is not trivial: it is actually a pretty deeply theoretical problem, because you're basically writing a miniature parser, perhaps built on a miniature lexical analyzer, just like a real compiler.
One straightforward way of writing a parser involves a technique called recursive descent. Writing a recursive descent parser has a lot in common with another great technique for solving big or hard problems, namely by breaking the big, hard problem up into smaller and hopefully easier subproblems.
So let's see what we can come up with. We're going to write a function int eval(const char * expr) that takes a string containing an expression, and returns the int result of evaluating it. But first let's write a tiny main program to test it with. We'll read a line of text typed by the user using fgets, pass it to our expr() function, and print the result.
#include <stdio.h>
int eval(const char *expr);
int main()
{
char line[100];
while(1) {
printf("Expression? ");
if(fgets(line, sizeof line, stdin) == NULL) break;
printf(" -> %d\n", eval(line));
}
}
So now we start writing eval(). The first question is, how will we keep track of how how far we've read through the string as we parse it? A simple (although mildly cryptic) way of doing this will be to pass around a pointer to a pointer to the next character. That way any function can move forwards (or occasionally backwards) through the string. So our eval() function is going to do almost nothing, except take the address of the pointer to the string to be parsed, resulting in the char ** we just decided we need, and calling a function evalexpr() to do the work. (But don't worry, I'm not procrastinating; in just a second we'll start doing something interesting.)
int evalexpr(const char **);
int eval(const char *expr)
{
return evalexpr(&expr);
}
So now it's time to write evalexpr(), which is going to start doing some actual work. Its job is to do the first, top-level parse of the expression. It's going to look for a series of "terms" being added or subtracted. So it wants to get one or more subexpressions, with + or - operators between them. That is, it's going to handle expressions like
1 + 2
or
1 + 2 - 3
or
1 + 2 - 3 + 4
Or it can read a single expression like
1
Or any of the terms being added or subtracted can be a more-complicated subexpression, so it will also be able to (indirectly) handle things like
2*3 + 4*5 - 9/3
But the bottom line is that it wants to take an expression, then maybe a + or - followed by another subexpression, then maybe a + or - followed by another subexpression, and so on, as long as it keeps seeing a + or -. Here is the code. Since it's adding up the additive "terms" of the expression, it gets subexpressions by calling a function evalterm(). It also needs to look for the + and - operators, and it does this by calling a function gettok(). Sometimes it will see an operator other than + or -, but those are not its job to handle, so if it sees one of those it "ungets" it, and returns, because it's done. All of these functions pass the pointer-to-pointer p around, because as I said earlier, that's how all of these functions keep track of how they're moving through the string as they parse it.
int evalterm(const char **);
int gettok(const char **, int *);
void ungettok(int, const char **);
int evalexpr(const char **p)
{
int r = evalterm(p);
while(1) {
int op = gettok(p, NULL);
switch(op) {
case '+': r += evalterm(p); break;
case '-': r -= evalterm(p); break;
default: ungettok(op, p); return r;
}
}
}
This is some pretty dense code, Stare at it carefully and convince yourself that it's doing what I described. It calls evalterm() once, to get the first subexpression, and assigns the result to the local variable r. Then it enters a potentially infinite loop, because it can handle an arbitrary number of added or subtracted terms. Inside the loop, it gets the next operator in the expression, and uses it to decide what to do. (Don't worry about the second, NULL argument to gettok; we'll get to that in a minute.)
If it sees a +, it gets another subexpression (another term) and adds it to the running sum. Similarly, if it sees a -, it gets another term and subtracts it from the running sum. If it gets anything else, this means it's done, so it "ungets" the operator it doesn't want to deal with, and returns the running sum -- which is literally the value it has evaluated. (The return statement also breaks the "infinite" loop.)
At this point you're probably feeling a mixture of "Okay, this is starting to make sense" but also "Wait a minute, you're playing pretty fast and loose here, this is never going to work, is it?" But it is going to work, as we'll see.
The next function we need is the one that collects the "terms" or subexpressions to be added (and subtracted) together by evalexpr(). That function is evalterm(), and it ends up being very similar -- very similar -- to evalexpr. Its job is to collect a series of one or more subexpressions joined by * and/or /, and multiply and divide them. At this point, we're going to call those subexpressions "primaries". Here is the code:
int evalpri(const char **);
int evalterm(const char **p)
{
int r = evalpri(p);
while(1) {
int op = gettok(p, NULL);
switch(op) {
case '*': r *= evalpri(p); break;
case '/': r /= evalpri(p); break;
default: ungettok(op, p); return r;
}
}
}
There's actually nothing more to say here, because the structure of evalterm ends up being exactly like evalexpr, except that it does things with * and /, and it calls evalpri to get/evaluate its subexpressions.
So now let's look at evalpri. Its job is to evaluate the three lowest-level, but highest-precedence elements of an expression: actual numbers, and parenthesized subexpressions, and the unary - operator.
int evalpri(const char **p)
{
int v;
int op = gettok(p, &v);
switch(op) {
case '1': return v;
case '-': return -evalpri(p);
case '(':
v = evalexpr(p);
op = gettok(p, NULL);
if(op != ')') {
fprintf(stderr, "missing ')'\n");
ungettok(op, p);
}
return v;
}
}
The first thing to do is call the same gettok function we used in evalexpr and evalterm. But now it's time to say a little more about it. It is actually the lexical analyzer used by our little parser. A lexical analyzer returns primitive "tokens". Tokens are the basic syntactic elements of a programming language. Tokens can be single characters, like + or -, or they can also be multi-character entities. An integer constant like 123 is considered a single token. In C, other tokens are keywords like while, and identifiers like printf, and multi-character operators like <= and ++. (Our little expression evaluator doesn't have any of those, though.)
So gettok has to return two things. First it has to return a code for what kind of token it found. For single-character tokens like + and - we're going to say that the code is just the character. For numeric constants (that is, any numeric constant), we're going to say that gettok is going to return the character 1. But we're going to need some way of knowing what the value of the numeric constant was, and that, as you may have guessed, is what the second, pointer argument to the gettok function is for. When gettok returns 1 to indicate a numeric constant, and if the caller passes a pointer to an int value, gettok will fill in the integer value there. (We'll see the definition of the gettok function in a moment.)
At any rate, with that explanation of gettok out of the way, we can understand evalpri. It gets one token, passing the address of a local variable v in which the value of the token can be returned, if necessary. If the token is a 1 indicating an integer constant, we simply return the value of that integer constant. If the token is a -, this is a unary minus sign, so we get another subexpression, negate it, and return it. Finally, if the token is a (, we get another whole expression, and return its value, checking to make sure that there's another ) token after it. And, as you may notice, inside the parentheses we make a recursive call back to the top-level evalexpr function to get the subexpression, because obviously we want to allow any subexpression, even one containing lower-precedence operators like + and -, inside the parentheses.
And we're almost done. Next we can look at gettok. As I mentioned, gettok is the lexical analyzer, inspecting individual characters and constructing full tokens from them. We're now, finally, starting to see how the passed-around pointer-to-pointer p is used.
#include <stdlib.h>
#include <ctype.h>
void skipwhite(const char **);
int gettok(const char **p, int *vp)
{
skipwhite(p);
char c = **p;
if(isdigit(c)) {
char *p2;
int v = strtoul(*p, &p2, 0);
*p = p2;
if(vp) *vp = v;
return '1';
}
(*p)++;
return c;
}
Expressions can contain arbitrary whitespace, which is ignored, so we skip over that with an auxiliary function skipwhite. And now we look at the next character. p is a pointer to pointer to that character, so the character itself is **p. If it's a digit, we call strtoul to convert it. strtoul helpfully returns a pointer to the character following the number it scans, so we use that to update p. We fill in the passed pointer vp with the actual value strtoul computed for us, and we return the code 1 indicating an integer constant.
Otherwise -- if the next character isn't a digit -- it's an ordinary character, presumably an operator like + or - or punctuation like ( ), so we simply return the character, after incrementing *p to record the fact that we've consumed it. Properly "incrementing" p is mildly tricky: it's a pointer to a pointer, and we want to increment the pointed-to pointer. If we wrote p++ or *p++ it would increment the pointer p, so we need (*p)++ to say that it's the pointed-to pointer that we want to increment. (See also C FAQ 4.3.)
Two more utility functions, and then we're done. Here's skipwhite:
void skipwhite(const char **p)
{
while(isspace(**p))
(*p)++;
}
This simply skips over zero or more whitespace characters, as determined by the isspace function from <ctype.h>. (Again, we're taking care to remember that p is a pointer-to-pointer.)
Finally, we come to ungettok. It's a hallmark of a recursive descent parser (or, indeed, almost any parser) that it has to "look ahead" in the input, making a decision based on the next token. Sometimes, however, it decides that it's not ready to deal with the next token after all, so it wants to leave it there on the input for some other part of the parser to deal with later.
Stuffing input "back on the input stream", so to speak, can be tricky. This implementation of ungettok is simple, but it's decidedly imperfect:
void ungettok(int op, const char **p)
{
(*p)--;
}
It doesn't even look at the token it's been asked to put back; it just backs the pointer up by 1. This will work if (but only if) the token it's being asked to unget is in fact the most recent token that was gotten, and if it's not an integer constant token. In fact, for the program as written, and as long as the expression it's parsing is well-formed, this will always be the case. It would be possible to write a more complicated version of gettok that explicitly checked for these assumptions, and that would be able to back up over multi-character tokens (such as integer constants) if necessary, but this post has gotten much longer than I had intended, so I'm not going to worry about that for now.
But if you're still with me, we're done! And if you haven't already, I encourage you to copy all the code I've presented into your friendly neighborhood C compiler, and try it out. You'll find, for example, that 1 + 2 * 3 gives 7 (not 9), because the parser "knows" that * and / have higher precedence than + and -. Just like in a real compiler, you can override the default precedence using parentheses: (1 + 2) * 3 gives 9. Left-to-right associativity works, too: 1 - 2 - 3 is -4, not +2. It handles plenty of complicated, and perhaps surprising (but legal) cases, too: (((((5))))) evaluates to just 5, and ----4 evaluates to just 4 (it's parsed as "negative negative negative negative four", since our simplified parser doesn't have C's -- operator).
This parser does have a pretty big limitation, however: its error handling is terrible. It will handle legal expressions, but for illegal expressions, it will either do something bizarre, or just ignore the problem. For example, it simply ignores any trailing garbage it doesn't recognize or wasn't expecting -- the expressions 4 + 5 x, 4 + 5 %, and 4 + 5 ) all evaluate to 9.
Despite being somewhat of a "toy", this is also a very real parser, and as we've seen it can parse a lot of real expressions. You can learn a lot about how expressions are parsed (and about how compilers can be written) by studying this code. (One footnote: recursive descent is not the only way to write a parser, and in fact real compilers will usually use considerably more sophisticated techniques.)
You might even want to try extending this code, to handle other operators or other "primaries" (such as settable variables). Once upon a time, in fact, I started with something like this and extended it all the way into an actual C interpreter.
Related
#include <stdio.h>
int sum(int a);
int main()
{
int a;
printf("Enter a value: ");
scanf("%d", &a);
printf("%d", sum(a));
return 0;
}
int sum(int a)
{
if (a == 1)
{
return 1;
}
return a + sum(a - 1);
}
When the input is 5 the output is 15 (which is right),
but when the return is, return a + sum(--a);
(for the same input 5) the output is 11
The behaviour of a + sum(--a) is undefined. The compiler has a lot of freedom as to when and how often it reads a, and when and how often it modifies a. Avoid both reading and modifying the same variable in an expression.
When you wrote
a + sum(a - 1)
, a rough translation of that C code into English is:
"Take a plus the result of the sum function applied to the quantity a-1."
That makes sense, and it's just what you want.
If, on the other hand, you write
a + sum(--a)
, now what you're saying is,
"Take a plus the result of the sum function applied to, hang on a minute, I want to take the variable a minus 1 and assign it back to a and then, where was I, pass it to sum()."
Is that really what you want to do? Why would you want to modify a's value in the middle of calling sum()? You wouldn't want to do that, you don't need to do that, that has nothing to do with the problem of calling sum(a - 1). So don't write it that way. It's confusing to you and me, and what's worse, it's so confusing that the compiler can't figure it out, either. It's so confusing that it's undefined behavior, meaning that the compiler isn't even required to figure out what you mean, and the compiler is explicitly allowed to fall back and punt, and compile your program into something that doesn't work — which is precisely what you discovered when you tried it.
See the canonical SO question Why are these constructs using pre and post-increment undefined behavior? for much (much!) more on undefined expressions like these.
I wrote a pretty simple left-recursive grammar in yacc, based on data types for a simple C-like language. The generated yacc parser reduces before the left recursion suffix, and I have no clue why.
Here is the source code:
%%
start: type {
printf("Reduced to start.\n");
};
type: pointer {
printf("Reduced pointer to type.\n");
}
| char {
printf("Reduced char to type.\n");
};
char: KW_CHAR {
printf("Reduced to char.\n");
};
pointer: type ASTERISK {
printf("Reduced to pointer.\n");
};
%%
Given the input char * (KW_CHAR ASTERISK):
Reduced to char.
Reduced char to type.
syntax error
You don't seem to be asking about the parse error you're receiving (which, as noted in the comments, is likely an issue with the token types being returned by yylex()), but rather why the parser reductions are performed in the order shown by your trace. That's the question I will try to address here, even though it's quite possible that it's an XY problem, because understanding reduction order is important.
In this case, the reduction order is pretty simple. If you have a production:
pointer: type ASTERISK
then type must be reduced before ASTERISK is shifted. In an LR parser, reductions must be done when the right-hand side to be reduced ends exactly at the last consumed input token. (The lookahead token has been identified by the lexical scanner but not yet consumed by the parser. So it's not part of the reduction and can be used also to identify other reductions ending at the same point.)
I hope it's more evident why with the production
type: char
char needs to be reduced before type. Until char is reduced, it's not available to be used in the reduction of type.
Really, these two examples show the same behaviour. Reductions are performed left-to-right, and from the bottom up (that is, children first). Hence the name for this kind of parsing.
So the reduction order shown by your parser (first char, then type, and only after the * is shifted, pointer) is precisely what would be expected.
I am getting an output of 24 which is the factorial for 4, but I should be getting the output for 5 factorial which is 120
#include <stdio.h>
int factorial(int number){
if(number==1){
return number;
}
return number*factorial(--number);
}
int main(){
int a=factorial(5);
printf("%d",a);
}
Your program suffers from undefined behavior.
In the first call to factorial(5), where you have
return number * factorial(--number);
you imagine that this is going to compute
5 * factorial(4);
But that's not guaranteed!
What if the compiler looks at it in a different order?
What it if works on the right-hand side first?
What if it first does the equivalent of:
temporary_result = factorial(--number);
and then does the multiplication:
return number * temporary_result;
If the compiler does it in that order, then temporary_result will be factorial(4), and it'll return 4 times that, which won't be 5!. Basically, if the compiler does it in that order -- and it might! -- then number gets decremented "too soon".
You might not have imagined that the compiler could do things this way.
You might have imagined that the expression would always be "parsed left to right".
But those imaginations are not correct.
(See also this answer for more discussion on order of evaluation.)
I said that the expression causes "undefined behavior", and this expression is a classic example. What makes this expression undefined is that there's a little too much going on inside it.
The problem with the expression
return number * factorial(--number);
is that the variable number is having its value used within it, and that same variable number is also being modified within it. And this pattern is, basically, poison.
Let's label the two spots where number appears, so that we can talk about them very clearly:
return number * factorial(--number);
/* A */ /* B */
At spot A we take the value of the variable number.
At spot B we modify the value of the variable number.
But the question is, at spot A, do we get the "old" or the "new" value of number?
Do we get it before or after spot B has modified it?
And the answer, as I already said, is: we don't know. There is no rule in C to tell us.
Again, you might have thought there was a rule about left-to-right evaluation, but there isn't. Because there's no rule that says how an expression like this should be parsed, a compiler can do anything it wants. It can parse it the "right" way, or the "wrong" way, or it can do something even more bizarre and unexpected. (And, really, there's no "right" or "wrong" way to parse an undefined expression like this in the first place.)
The solution to this problem is: Don't do that!
Don't write expressions where one variable (like number) is both used and modified.
In this case, as you've already discovered, there's a simple fix:
return number * factorial(number - 1);
Now, we're not actually trying to modify the value of the variable number (as the expression --number did), we're just subtracting 1 from it before passing the smaller value off to the recursive call.
So now, we're not breaking the rule, we're not using and modifying number in the same expression.
We're just using its value twice, and that's fine.
For more (much more!) on the subject of undefined behavior in expressions like these, see Why are these constructs using pre and post-increment undefined behavior?
How to find the factorial of a number;
function factorial(n) {
if(n == 0 || n == 1 ) {
return 1;
}else {
return n * factorial(n-1);
}
//return newnum;
}
console.log(factorial(3))
My question pertains to function calls in general, but I thought of it
while I was writing a priority queue using a heap. Just to give some context (not that it matters much) my heap stores items top to bottom left to right and I represent the heap as an array of structures. Upon inserting a new item, I just put it in the last place in the heap and then call the function "fix_up" at the bottom which will move the item to the proper place in the heap. I am wondering if instead of doing...
fix_up(pQueue->heap, pQueue->size);
pQueue->size++;
...I could just do...
fix_up(pQueue->heap, pQueue->size++);
I am unsure as to if this is ok for a few reasons.
1) Since pQueue->size is in the function call, I'm not even sure if it's actually pQueue->size or rather a copy of the integer stored in pQueue->size. If it was a copy then obviously I wouldn't be adding 1 to the actual pQueue->size so there'd be no point in doing this.
2) Since it's a function call, it is going to then go into the function fix_up and execute all the code there. I am wondering if this would have an unintended consequence of maybe when it went to fix_up it would get incremented by 1 and my index would be 1 higher than I intended while executing fix_up? Or would it do what it's supposed to do and wait until after fix_up had finished executing?
3) Even if it is ok, is it considered a good coding practice for C?
Status priority_queue_insert(PRIORITY_QUEUE hQueue, int priority_level, int data_item)
{
Priority_queue *pQueue = (Priority_queue*)hQueue;
Item *temp_heap;
int i;
/*Resize if necessary*/
if (pQueue->size >= pQueue->capacity) {
temp_heap = (Item*)malloc(sizeof(Item) * pQueue->capacity * 2);
if (temp_heap == NULL)
return FAILURE;
for (i = 0; i < pQueue->size; i++)
temp_heap[i] = pQueue->heap[i];
pQueue->capacity *= 2;
}
/*Either resizing was not necessary or it successfully resized*/
pQueue->heap[pQueue->size].key = priority_level;
pQueue->heap[pQueue->size].data = data_item;
/*Now it is placed as the last item in the heap. Fixup as necessary*/
fix_up(pQueue->heap, pQueue->size);
pQueue->size++;
//continue writing function code here
}
Yes you can.
However, you cannot do this:
foo(myStruct->size++, myStruct->size)
The reason is that the C standard does not say in which order the arguments should be evaluated. This would lead to undefined behavior.
1) Since pQueue->size is in the function call, I'm not even sure if it's actually pQueue->size or rather a copy of the integer stored in pQueue->size. If it was a copy then obviously I wouldn't be adding 1 to the actual pQueue->size so there'd be no point in doing this.
Whatever argument you're sending to a function, it will be evaluated before the function starts to execute. So
T var = expr;
foo(var);
is always equivalent to
foo(expr);
2) Since it's a function call, it is going to then go into the function fix_up and execute all the code there. I am wondering if this would have an unintended consequence of maybe when it went to fix_up it would get incremented by 1 and my index would be 1 higher than I intended while executing fix_up? Or would it do what it's supposed to do and wait until after fix_up had finished executing?
See above
3) Even if it is ok, is it considered a good coding practice for C?
Somewhat subjective, and a bit OT for this site, but I'll answer it anyway from my personal view. In general, I would try to avoid it.
Though, the other posts already answer this question, but none of them talk about role of Sequence Point, in this particular case, which can greatly help in clarifying OP's doubt.
From this [emphasis mine]:
There is a sequence point after the evaluation of all function arguments and of the function designator, and before the actual function call.
From this [emphasis mine]:
Increment operators initiate the side-effect of adding the value 1 of appropriate type to the operand. Decrement operators initiate the side-effect of subtracting the value 1 of appropriate type from the operand. As with any other side-effects, these operations complete at or before the next sequence point.
Also, the post increment operator increase the value of operand by 1 but the value of the expression is the operand's original value prior to the increment operation.
So, in this statement:
fix_up(pQueue->heap, pQueue->size++);
the value of pQueue->size will be increased by 1 before the fix_up() function call but the argument value will be the original value prior to the increment operation.
Yes you can use it directly in the expression you pass as argument.
A statement like
fix_up(pQueue->heap, pQueue->size++);
is somewhat equivalent to
{
int old_value = pQueue->size;
pQueue->size = pQueue->size + 1;
fix_up(pQueue->heap, old_value);
}
A note about the "equivalent" example above. Since the order of evaluation of arguments to function calls is not specified, the actual increment of pQueue->size could happen after the call to fix_up. And it also means that using pQueue->size more than once in the same call would lead to undefined behavior.
Yeah you can use it in function calls, but please note that your two examples are not equivalent. The pQueue->heap argument may be evaluated before or after pQueue->size++ and you can't know or rely on the order. Consider this example :
int func (void)
{
static int x = 0;
x++;
return x;
}
printf("%d %d", func(), func());
This will print 1 2 or 2 1 and we can't know which we'll get. The compiler need not evalute the function parameters consistently throughout the program. So if we add a second printf("%d %d", func(), func()); we could get something like 1 2 4 3 as output.
The importance here is to not write code which relies on order of evaluation. Which is the same reason as mixing ++ with other operations or side-effects in the same expression is bad practice. It can even lead to undefined behavior in some cases.
To answer your questions:
1) Since pQueue->size is in the function call, I'm not even sure if it's actually pQueue->size or rather a copy of the integer stored in pQueue->size. If it was a copy then obviously I wouldn't be adding 1 to the actual pQueue->size so there'd be no point in doing this.
The ++ is applied to the variable in the caller, so this isn't an issue. The local copy of the variable happens during function call, independently of the ++. However, the result of a ++ operation is not a so-called "lvalue" (addressable data), so this code is not valid:
void func (int* a);
...
func(&x++);
++ takes precedence and is evaluted first. The result is not an lvalue and cannot have its address taken.
2) Since it's a function call, it is going to then go into the function fix_up and execute all the code there. I am wondering if this would have an unintended consequence of maybe when it went to fix_up it would get incremented by 1 and my index would be 1 higher than I intended while executing fix_up? Or would it do what it's supposed to do and wait until after fix_up had finished executing?
This isn't an issue unless the function modifies the original variable through a global pointer or such. In that case you would have problems. For example
int* ptr;
void func (int a)
{
*ptr = 1;
}
int x=5;
ptr = &x;
func(x++);
This is very questionable code and x will be 1 after the line func(x++); and not 6 as one might have expected. This is because the function call expression is evaluated and finished before the function call.
3) Even if it is ok, is it considered a good coding practice for C?
It will work ok in your case but it is bad practice. Specifically, mixing the ++ or -- operators together with other operators in the same expression is bad (although common) practice, since it has a high potential for bugs and tends to make code less readable.
Your original code with pQueue->size++; on a line of it's own is superior in every way - stick with that. Contrary to popular belief, when writing C, you get no bonus points for "most operators on a single line". You may however get bugs and maintenance problems.
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.