Can we assign a value inside the if statement? - c

#include <stdio.h>
void main()
{
int x = 0;
if (x = 0)
printf("It's zero\n");
else
printf("It's not zero\n");
}
Why is the statement if (x = 0) not an error? Can we assign a value like that in an if statement? Why is it not generating an error, and why is the else statement getting executed?

Yes, it is allowed to assign the value inside the if statement. This is very handy, among other things, when you want to call the function and check it's return for error:
int rc;
if ((rc = check())) {
// here rc is non-zero, often an indication of a failure
}
Note how I've put an extra pair of parenthesis around my assignment - since it is such an omnipresent source of confusion, compilers are usually warning about assignement in the if block, assuming you might have made a typo. Extra pair of parenthesis makes it clear for compiler that this is what I intended.
By the way, there is no special exception crafted here, validity of this syntax stems from general C grammar - an assignment operator evaluates to assigned value.

Yes, this is a perfectly valid syntax, there is no reason to disallow this.
Quoting C11,
[...] An
assignment expression has the value of the left operand after the assignment. [...]
So, the value which is stored in the LHS operand, would be used for the if statement condition evaluation.
In your case, the variable x holds the value 0 after the assignment, and if (0) is FALSY, that's why the else block gets executed.
However, most of the time, this syntax is used wrongly, instead of the comparison. That's why most of the compilers emit a warning message on this construct.
warning: suggest parentheses around assignment used as truth value [-Wparentheses]
if (x = 0)
^
If you're sure what you're doing, you can wrap the if condition with an assignment expression in an additional pair of parenthesis, and you'll be good to go.

In C, the only requirement for an if statement is that it contains an expression. The truth of the statement is based on whether or not the expression evaluates to zero.
The assignment operator also evaluates to the assigned value, so if(a = 0) would be false, whereas if(a = x) where x != 0 would be true.
Since the assignment operator is an expression, it is acceptable to place in an if statement, though a frequent beginner mistake is to use the assignment operator where they intended to use the equality test operator ==.
One way you can avoid this is mistake is, if either side of the comparison is an r-value, put that on the left, so that if you ever accidentally use = where you meant ==, you will get a compilation error. Compare:
if(p = NULL) // Valid syntax
...
if(NULL = p) // Syntax error
...

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;

C error:lvalue required as left operand of assignment

#include<stdio.h>
int hailstone(int n){
int length=1;
while(1<n){(n%2)?n=3*n+1:n/=2;length++;}//error
//while(1<n){(n%2)?n=3*n+1:(n/=2);length++;} right
return length;
}
int main()
{
int n;
scanf("%d",&n);
printf("%d\n",hailstone(n));
}
There is an error in line four,the gcc compiler said lvalue required as left operand of assignment,but if i add brackets it will be right.like line five,and i don not know why.
Despite shoving all the logic into one line, the problem is actually in one expression (pardon me for adding spaces):
(n%2) ? n=3*n+1 : n/=2
The precedence rules for C expressions are like that. Assignment (and that includes compound assignment) binds less tightly than ?:. So the compiler has to interpret what you wrote as:
((n%2) ? n=3*n+1 : n) /=2
Since ?: doesn't produce an lvalue (something that can appear on the left of an assignment), you get an error. Your use of parentheses forces the precedence to match what you wanted.
But an even better way to write that is to not be "clever" and think there is some "elegance" in using as much tokens as possible in a single expression. Here's another version, which is far more readable, and easier to verify as correct:
if (n%2) {
n = 3*n+1;
} else {
n /= 2;
}
And it's no less efficient than using a conditional expression.
Here the compiler takes l value as
((n%2) ? n=3*n+1 : n) /
and r value as
2
Since ((n%2) ? n=3*n+1 : n) / = 2 is an invalid statement and l value is not a variable, compiler throws error. You can provide the precedence of execution to the compiler by adding brackets.

Comma operator in condition of loop in C

#include <stdio.h>
main()
{
int i;
for(i=0; i<0, 5; i++)
printf("%d\n", i);
}
I am unable to understand the i<0, 5 part in the condition of the for loop.
Even if I make it i>0, 5, there's no change in output.
How does this work?
On topic
The comma operator will always yield the last value in the comma separated list.
Basically it's a binary operator that evaluates the left hand value but discards it, then evaluates the right hand value and returns it.
If you chain multiple of these they will eventually yield the last value in the chain.
As per anatolyg's comment, this is useful if you want to evaluate the left hand value before the right hand value (if the left hand evaluation has a desirable side effect).
For example i < (x++, x/2) would be a sane way to use that operator because you're affecting the right hand value with the repercussions of the left hand value evaluation.
http://en.wikipedia.org/wiki/Comma_operator
Sidenote: did you ever hear of this curious operator?
int x = 100;
while(x --> 0) {
// do stuff with x
}
It's just another way of writing x-- > 0.
Comma operator evaluates i<0 Or i>0 and ignores. Hence, it's always the 5 that's present in the condition.
So it's equivalent to:
for(i=0;5;i++)
The coma operator is done to the initialization and to the increment part, to do something like for(i=0,j=20;i<j;i++,j--), if you do it in the comparation part it will evaluate the last one (as it was already answered before)
i<0,5 will always evaluate to 5, as always the right expression will be returned for ex1,ex2 .
The comma operator is intended for cases where the first operand has some side effects. It's just an idiom, meant to make your code more readable. It has no effect on the evaluation of the conditional.
For example,
for (i = 0; i<(i++, 5); i++) {
// something
}
will increment i, and then check if i<5.

if statement with equal sign "=" and not "==" in expression

I found a bug in code (the if statement should have had "==" instad of "=") and I have few questions.
Example code:
int i = 5;
if (i = MyFunction()) // MyFunction() returns an int; this is where bug was made
{
// call A()
}
else
{
// call B()
}
From what I gather it should always call A().
1. Is my assumption correct()?
2. Is this case for all/most compilers (any exceptions)?
No, it will only call A() if the assignment is considered true, i.e. non-zero.
Yes, this is standard. It's not a very good way to write the code since the risk of confusion is large.
Some people flip comparisons, writing the constant to the left, to avoid the risk:
if( 12 == x )
but of course this wouldn't have worked in your case, since it really is an assignment. Most compilers can give you a warning when this code is detected, since it's so often a cause of bugs.
If MyFunction() returns zero (0) it will call B(); otherwise it will call A(). The value of an assignment expression is the value that is assigned to the left hand side; in an if statement 0 is treated as false and all other values as true.
This is perfectly legitimate code, although many compilers will issue a warning. The reason it is valid is that in C and similar languages, assignment is an expression (rather than a statement).
If you intended to assign to i and test the return value you should write if ((i = MyFunction())); the extra parentheses signal to the compiler (and to the reader) that the assignment is intended.
If instead you intend to test against the value of i you should write if (MyFunction() == i); by putting the function call on the left you ensure that if you miss out the double equals sign the code will fail to compile (MyFunction() = i is not usually a valid expression).
This statement is an assignment:
i = MyFunction()
The if statement is in effect checking the value of i. If MyFunction() returns 0, i is assigned 0 and it becomes equivalent to:
if(0)
This evaluates to false, and A() will not be called in this case
It will take the true branch (i.e. call A) if the function return is non-zero. Zero is treated as false so if MyFunction() returns zero it will call B instead.
In practice, yes this is correct for most / all compilers. I think 0=false was just a convention; I wouldn't be surprised if it is now formalised in C99 or later but I don't have a copy handy to refer you to the right section.
Your assumption is incorrect.
The expression in the if-condition is evaluated like any other expression, in your case the result of (i = MyFunction()) is the return value of MyFunction().
You code will evaluate
(i = MyFunction())
and if MyFunction() returns a non zero value, the expression will be evaluated as true and call A(). Otherwise B()

lvalue required as left operand of assignment

Why am I getting
lvalue required as left operand of assignment
with a single string comparison? How can I fix this in C?
if (strcmp("hello", "hello") = 0)
Thanks!
You need to compare, not assign:
if (strcmp("hello", "hello") == 0)
^
Because you want to check if the result of strcmp("hello", "hello") equals to 0.
About the error:
lvalue required as left operand of
assignment
lvalue means an assignable value (variable), and in assignment the left value to the = has to be lvalue (pretty clear).
Both function results and constants are not assignable (rvalues), so they are rvalues. so the order doesn't matter and if you forget to use == you will get this error. (edit:)I consider it a good practice in comparison to put the constant in the left side, so if you write = instead of ==, you will get a compilation error. for example:
int a = 5;
if (a = 0) // Always evaluated as false, no error.
{
//...
}
vs.
int a = 5;
if (0 = a) // Generates compilation error, you cannot assign a to 0 (rvalue)
{
//...
}
(see first answer to this question: https://stackoverflow.com/questions/2349378/new-programming-jargon-you-coined)
You cannot assign an rvalue to an rvalue.
if (strcmp("hello", "hello") = 0)
is wrong. Suggestions:
if (strcmp("hello", "hello") == 0)
^
= is the assign operator.
== is the equal to operator.
I know many new programmers are confused with this fact.
Change = to ==
i.e
if (strcmp("hello", "hello") == 0)
You want to compare the result of strcmp() to 0. So you need ==. Assigning it to 0 won't work because rvalues cannot be assigned to.
You are trying to assign a value to a function, which is not possible in C. Try the comparison operator instead:
if (strcmp("hello", "hello") == 0)
I found that an answer to this issue when dealing with math is that the operator on the left hand side must be the variable you are trying to change. The logic cannot come first.
coin1 + coin2 + coin3 = coinTotal; // Wrong
coinTotal = coin1 + coin2 + coin3; // Right
This isn't a direct answer to your question but it might be helpful to future people who google the same thing I googled.
if (strcmp("hello", "hello") = 0)
Is trying to assign 0 to function return value which isn't lvalue.
Function return values are not lvalue (no storage for it), so any attempt to assign value to something that is not lvalue result in error.
Best practice to avoid such mistakes in if conditions is to use constant value on left side of comparison, so even if you use "=" instead "==", constant being not lvalue will immediately give error and avoid accidental value assignment and causing false positive if condition.

Resources