C programming Increment logical error [duplicate] - c

This question already has answers here:
Is short-circuiting logical operators mandated? And evaluation order?
(7 answers)
Closed 5 years ago.
#include <stdio.h>
main()
{
int x = 1, y = 0, z = 5;
int a = x && y || z++;
printf("%d", z);
}
This code gives me output : 6
#include <stdio.h>
main()
{
int x = 1, y = 0, z = 5;
int a = x && y && z++;
printf("%d", z);
}
This code gives me output : 5
Why the second program gives ouput as 5 even though z was incremented same like in first program?

The && operator (as well as the || operator) is a short-circuit operator. That means that if the left operand evaluates false, the result is false regardless of the right operand, so the right operand is not evaluated.
From section 6.5.13 of the C standard:
4 Unlike the bitwise binary & operator, the && operator guarantees left-to-right evaluation; if the second operand is
evaluated, there is a sequence point between the evaluations
of the first and second operands. If the first operand
compares equal to 0, the second operand is not evaluated.
So in the case of this expression:
x && y && z++;
x && y is evaluated first. Since x is 1, y is evaluated and found to be 0, so the result of the first && is 0. Now we have:
0 && z++
Since the left operand is 0, the right operand is not evaluated. This means that z is not incremented.
This is in contrast to expression in the first piece of code:
x && y || z++
As before, x && y evaluates to 0, leaving us with:
0 || z++
Since the left operand is 0, the right operand needs to be evaluated. This results in z getting incremented.

Evaluation of x && y && z++ stops after y because y==0. z++ is not executed.

The initializer in this declaration
int a = x && y || z++;
is equivalent to
int a = ( x && y ) || ( z++ );
According to the C Standard relative to the logical OR operator (6.5.14 Logical OR operator)
4 ... If the first operand compares unequal to 0, the second operand is
not evaluated.
However the first operand that is ( x && y ) compares equal to 0 (due to the variable y is equal to 0). So the second operand ( z++ ) is evaluated.
The initializer in this declaration
int a = x && y && z++;
is equivalent to
int a = ( x && y ) && ( z++ );
According to the C Standard relative to the logical AND operator (6.5.13 Logical AND operator)
4 ...If the first operand compares equal to 0, the second operand is
not evaluated
So as the first operand ( x && y ) compares equal to 0 then the second operand ( z++ ) is not evaluated.

Related

How do you evaluate z = x- - == y + 1;

given that
int w = 1;
int x = 6;
int y = 5;
int z = 0;
z = !z || !x && !y;
printf("%d\n", z);
z = x-- == y + 1;
printf("%d\n", z);
Could someone explain how the line below would evaluate to 1 if x-- is 5 and y+1 is 6?
z = x-- == y + 1;
The expression x-- evaluated to the value of x before being decremented.
So x-- == y + 1 is the same as 6 == 5 + 1 which is true, then the value 1 is assigned to z.
The expression
z = x-- == y + 1
will be parsed as
z = ((x--) == (y + 1))
IOW, you are comparing the result of x-- to the result of y + 1, and assigning the result of that comparison to z.
The result of x-- is the current value of x; the side effect is that x is decremented. So, given
x == 6
y == 5
then
x-- == 6
y + 1 == 6
(x-- == y + 1) == 1
so 1 is assigned to z; after this evaluation, x will equal 5.
Note that C does not force left-to-right evaluation in this case - y + 1 may be evaluated before x--. Also be aware that the side effect of the -- operator on x does not have to be applied immediately after evaluation - the whole thing could be evaluated as
t1 <- y + 1
t2 <- x
z <- t2 == t1
x <- x - 1
or
t1 <- x
t2 <- y + 1
x <- x - 1
z <- t1 == t2
or any other order. The update to x and the assignment to z can happen in any order, even simultaneously (either interleaved or in parallel).
While idiomatic C is often a little head-scratchy, this takes things a bit too far. As an academic exercise for learning about operator precedence and side effects it's okay (not great), but anyone who did this in production code could expect some grief over it in a code review. If nothing else it doesn't scan well - just adding some parens (like I did above) would greatly help with readability.
From the C Standard (6.5.2.4 Postfix increment and decrement operators)
2 The result of the postfix ++ operator is the value of the operand.
As a side effect, the value of the operand object is incremented (that
is, the value 1 of the appropriate type is added to it).
3 The postfix -- operator is analogous to the postfix ++ operator,
except that the value of the operand is decremented (that is, the
value 1 of the appropriate type is subtracted from it)
Thus in this expression statement
z = x-- == y + 1;
that may be equivalently rewritten like
z = ( x-- ) == ( y + 1 );
the value of the postfix decrement expression x-- is the value of the variable x before decrementing. That is the value of the expression is equal to 6.
The value of the expression y + 1 is also equal to 6 because the value of y is equal to 5.
And at last (the C Standard, 6.5.9 Equality operators)
3 The == (equal to) and != (not equal to) operators are analogous to
the relational operators except for their lower precedence.108) Each
of the operators yields 1 if the specified relation is true and 0 if
it is false. The result has type int. For any pair of operands,
exactly one of the relations is true
So as the value of the expression x-- is equal to the value of the expression y + 1 then the variable z gets the value 1.
You could get the expected by you result keeping the postfix decrement operator the following way
z = ( x--, x == y + 1 );
by inserting the comma operator. In this case after the comma operator there is a sequence point that means that in second operand of the comma operator x == y + 1 x will be already equal to 5.
On the other hand, if you will write for example the expression like this
z = --x == y + 1;
where instead of the postfix decrement operator there is used unary decrement operator -- then the value of the expression --x will be equal to 5 (the value of the unary decrement operator is the value of its operand after decrementing). In this case the variable z gets the value 0 because 5 is not equal to 6 (the value of the expression y + 1).

Prefix operators are not working as expected in C [duplicate]

This question already has answers here:
Is short-circuiting logical operators mandated? And evaluation order?
(7 answers)
Closed 2 years ago.
#include <stdio.h>
int main()
{
int a = 1;
int b = 1;
int c = a || --b;
int d = a-- && --b;
printf("a=%d, b= %d, c= %d, d= %d",a,b,c,d);
return 0;
}
In th above code, I expected output to be a=0, b= -1, c= 1, d= 0 but the output was a=0, b= 0, c= 1, d= 0
Screenshot_VS Code
In the expression used as an initializer in this declaration
int c = a || --b;
as the operand a is not equal to 0 then the expression --b is not evaluated.
So the variable c is initialized by 1.
From the C Standard (6.5.14 Logical OR operator)
4 Unlike the bitwise | operator, the || operator guarantees
left-to-right evaluation; if the second operand is evaluated, there is
a sequence point between the evaluations of the first and second
operands. If the first operand compares unequal to 0, the second
operand is not evaluated.
In the expression used as an initializer in tjis declaration
int d = a-- && --b;
the operand a-- is not equal to 0 (the value of the postfix operator is the value of its operand before decrementing). So the operand --b is evaluated.
As its value is equal to 0 then the variable d is initialized by 0.
From the C Standard (6.5.13 Logical AND operator)
4 Unlike the bitwise binary & operator, the && operator guarantees
left-to-right evaluation; if the second operand is evaluated, there is
a sequence point between the evaluations of the first and second
operands. If the first operand compares equal to 0, the second
operand is not evaluated.
As a result a and b will be equal 0 after this declaration.

What should be the value of b in the following code snippet and why? '-6' or '-7' [duplicate]

This question already has answers here:
C operator precedence, logical vs unary in a++ && b++ || ++c
(1 answer)
Require explanation for the output
(4 answers)
Precedence of && over || [duplicate]
(4 answers)
Closed 3 years ago.
I want so see the values of the four variables (Basically checking the precedence order of logical operators).
#include<stdio.h>
int main()
{
int a=0, b=-7, c=0, d;
d = ++c || ++a && ++b ;
printf("\n %d %d %d %d",a,b,c,d);
}
I expect the result to be '0 -6 1 1', but the actual output is '0 -7 1 1'. Can anyone please give an explanation behind the output shown?
First have a look at Operator Precedence.
Then, regarding the working of logical OR operator, from C11, chapter §6.5.14 (emphasis mine)
[...] the || operator guarantees left-to-right evaluation; if the
second operand is evaluated, there is a sequence point between the evaluations of the first
and second operands. If the first operand compares unequal to 0, the second operand is
not evaluated.
and regarding the result:
The || operator shall yield 1 if either of its operands compare unequal to 0; otherwise, it
yields 0. The result has type int.
So, in your code
d = ++c || ++a && ++b ;
is the same as
d = (++c) || (++a && ++b);
which evaluates to
d = 1 || (++a && ++b); // short circuit, RHS not evaluated
which is finally same as
d = 1; // 1 is not the value computation of `++c`, rather result of the `||` operation.

how will this expression will evaluate in C?

I can't figure out how will this expression be evaluated in C?
I'm a bit confused with the evaluation of an expression inside printf?
If an expression inside printf evaluates from right to left then the evaluation of expression should've stopped after encountering (c>10), but it printed '1' to the output screen?
This is not exact syntax of C, but a question that was asked to me.
integer a = 50, b = 25, c = 0;
printf( a > 45 || b > 50 && c > 10 );
This expression
a > 45 || b > 50 && c > 10
is equivalent to expression
( a > 45 ) || ( b > 50 && c > 10 )
Thus if this subexpression ( a > 45 ) evaluates to true then the second subexpression will not evaluate and the result is equal 1 (of type int).
Otherwise this sub expression
( b > 50 && c > 10 )
is equivalent to
( b > 50 ) && ( c > 10 )
if ( b > 50 ) evaluates to false then the whole result is false (0 in C) and the second subexpression will not evaluate. Otherwise the result is the value of
the subexpression c > 10. If c > 10 then the result is an object of type int with value 1 or if not ( c > 10 ) then the value of the result is 0.
If the variables have values as it is shown in your question
int a = 50, b = 25, c = 0;
then the first subexpression
a > 45
evaluates to true and the result is 1 of type int. The second subexpression
b > 50 && c > 10
will not even evaluate.
Consider the following demonstrative program
#include <stdio.h>
int f( int x )
{
printf( "f is called for %d\n", x );
return x;
}
int main( void )
{
int a = 50, b = 25, c = 0;
f( f( a ) > 45 || f( b ) > 50 && f( c ) > 10 );
return 0;
}
Its output is
f is called for 50
f is called for 1
As you can see it was enough to calculate the expression f( a ) > 45 to get the result equal to 1.
It would be undefined behaviour. The first argument to printf must be a format string. Most likely it will crash. What saves you is that "integer" is not a type, so it's not going to compile.
Both the || and && operators force left-to-right evaluation. The left-hand operand will be fully evaluated (and all side effects applied) before the right-hand operand is evaluated.
Furthermore, both operators short-circuit - depending on the value of the left-hand operand, the right-hand operand may not be evaluated at all.
For
a || b
if a is true, then the entire expression is true regardless of the value of b, so b isn't evaluated.
Similarly, for
a && b
if a is false, then the entire expression is false regardless of the value of b, so b isn't evaluated.
&& has higher precedence than ||, so
a || b && c
will be parsed as
a || (b && c)
and
a && b || c
will be parsed as
(a && b) || c
So...
a > 45 || b > 50 && c > 10
is parsed as
a > 45 || (b > 50 && c > 10 )
Since a == 50, a > 45 is true. Since a > 45 is the left-hand operand of the || operator, the whole expression is true regardless of the right-hand operand, so b > 50 && c > 10 isn't evaluated at all.
The result of expression is 1 (true).
Unfortunately, printf expects its first argument to point to a character string (the format string), and 1 is most likely not a valid address on your platform, so the result of this code will most likely be a segfault. The easy fix would be to write
printf( "%d\n", a > 45 || b > 50 && c > 10 );
The context in which an expression appears affects whether it is evaluated, but not how. The order in which subexpressions of a larger expression are evaluated is controlled by operator precedence and associativity.
Among the operators in your expression, > has greatest precedence, then &&, then ||. All associate from left to right. Therefore, your expression is evaluated exactly the same as if it were written like so:
(a > 45) || ((b > 50) && (c > 10))
Furthermore, the && and || operators perform short-circuit evaluation. This seems to be a point of confusion for you. Short-circuit evaluation means that if the result of an && or || operation is determined by the value of the left-hand operand, then the right-hand operand of that operation is not evaluated. That does not affect whether or how other operations are evaluated, except to the extent that the result of the short-circuited operation is used as an operand.
In this case, however, because || associates left-to-right, a > 45 is evaluated first, producing 1 (true). Because this determines the result of the || operation, its right-hand operand is not evaluated. Relative operator precedence yields the right-hand operand being the remainder of the overall expression, as shown above, so none of that will be evaluated. Even if it were evaluated, however, the result of the overall expression would still be 1, because the left-hand operand evaluates to 1, regardless of the right-hand sub-expression. That's why the right-hand side of the || does not need to be evaluated.

Basic programming exercise about logical operators

I have a problem with a question in my book:
#include<stdio.h>
void main()
{
int a=5, b=-7, c=0, d;
d = ++a && ++b || ++c;
printf("\n%d%d%d%d",a,b,c,d);
}
The question asks me what is the output of the code. I ran it and the result on the screen is 6-601. I understand why a=6 and b=-6, but I don't understand why c=0 and d=1?
I believe you already got your answer, but just to elaborate a bit step-by-step, let me add one more clarification here. Firstly, to quote the properties of the && and || operators, from C11 standard, chapter §6.5.13 and §6.5.13, respectively,
(I)
The && operator shall yield 1 if both of its operands compare unequal to 0; otherwise, it
yields 0. [...] If the first operand compares equal to 0, the second
operand is not evaluated.
and
(II)
The || operator shall yield 1 if either of its operands compare unequal to 0; otherwise, it
yields 0. [...]. If the first operand compares unequal to 0, the second operand is
not evaluated.
and they both guarantee left-to-right evaluation. So, comparing your code,
d = ++a && ++b || ++c;
it happens like
d = ((++a && ++b) || ++c );
which evaluates to
d = (( 6 && ++b ) || ++c);
and then
d = ( ( 6 && (-6) ) || ++c);
Now in above stage, (I) is fulfilled and it comes down to
d = ( 1 || ++c);
Now, following the emphasis, which already meets the (II), so no further evaluation of the RHS operand of || is performed (i.e., ++c is not evaluated), and it appears to be d = 1 and the final result, 1, is stored into d.
That's how, a == 6, b == -6, c == 0 and d ==1.
Having said that, void main() should be changed to int main(void), at least to conform with the standard.
The || OR operator is short-circuiting, which means that if the left side is true then the right side is not evaluated. In this case ++a && ++b evaluates to true, so ++c is never run and c keeps its value of zero.
Also since it evaluates to true, this is denoted with 1 which is stored in d.
Any non-zero value is considered to be true and the result of boolean operations is defined to be 0 or 1 as an integer.

Resources