I don't quite understand how the if statement in this case works. It evaluates the x != 0 statement and when that is not true anymore, it assigns z to y and then breaks the if statement?
int main()
{
int x, y, z, i;
x = 3;
y = 2;
z = 3;
for (i = 0; i < 10; i++) {
if ((x) || (y = z)) {
x--;
z--;
} else {
break;
}
}
printf("%d %d %d", x, y, z);
}
Let's decompose that into smaller bits.
if (x) is the same as if (x != 0). If x != 0, then you know the condition is true, so you don't do the other portion of the if.
If part 1. was false, then y = z assigns z into y and returns the final value of y.
From point 2., we can understand that if (y = z) is equivalent to y = z; if (y != 0)
Thus, from points 1. and 3., we can understand that :
if ((x) || (y = z)) {
doSomething();
}
else {
doSomethingElse();
}
Is the same as :
if (x != 0) {
doSomething();
}
else {
y = z;
if (y != 0) {
doSomething();
}
else {
doSomethingElse();
}
}
It's true it's not particularly readable code though.
No. if ((x) || (y = z)) {
in C-English is basically:
if x is nonzero, evaluate the following code.
if x is zero, set y to z.
if y is nonzero, evaluate the following code.
otherwise, break out of the loop.
If x is zero or y is zero, it breaks out of the loop.
int main()
{
int x = 3;
int y = 2;
int z = 3;
unsigned int i;
for (i = 0; i < 10; i++)
if (x != 0) {
x = x-1;
z = z-1;
}
else {
y = z;
if (y != 0) {
x = x-1;
z = z-1;
}
else {
break;
}
}
}
printf("%d %d %d", x, y, z);
}
In C, there is short-circuiting, so the statement y=z will not be evaluated until x becomes zero.
When x == 0, since z also decrements the same way, z == 0. Hence y will also be zero at that time due to the assignment. The statement y=z also returns y at this point which will be evaluated as a condition, and since that is also 0, the else break will be hit.
Hence I believe the answer should be 0 0 0.
When you use assignment in an if statement, the result of the assignment is returned. so when you write :
if (x = y)
It will be always true unless the value of y is 0, so 0 is returned as the result of assigning and the if statement is not executed.(anything except 0 is considered as true.)
So when you write :
if ( x || (x = y))
The if statement doesn't execute only if x is 0 & y is 0.
Here
if ((x) || (y = z))
there are two condition
one condition is
if ((x)) and another condition is if ((y = z))
if one of them is true then if portion is execute otherwise else condition work
only and only when both condition are false then else execute.
Related
How can I simplify below if statements?, I'm trying to achieve the possibly most efficient code.
// doSomething based on x value and y value
void doSomething(x int, y int) {
//x not zero and y not zero
if (x != 0 && y != 0) {
//do a
//do b if x greater or equal y
//else do c
if (x >= y) {
//do b
} else (x < y) {
//do c
}
return;
}
//do b if x not zero and y zero
if (x != 0 && y == 0) {
//do b
return;
}
//do e if both x and y zero
if (x == 0 && y == 0) {
//do e
return;
}
}
What is the most concise and efficient way to simplify?
As it stands, your code is equivalent to:
if (x == 0)
{
if (y == 0)
do e
}
else if (y != 0)
{
if (x < y)
do a,c
else
do a,b
}
In particular:
if x=0 && y!=0 or y=0 && x!=0, then do nothing;
the two branches //do b if x not zero and y zero and //do d if x zero and y not zero are unreachable in your code.
History:
The code in the question was changed several times. This answer is based on the original version of the code. That code is shown below, minimally modified so that it's compilable C code:
void original(int x, int y)
{
if (x == y && x != 0 && y != 0) {
// do a
// do b
return;
}
if (x < y && x != 0 && y != 0) {
// do a
// do c
return;
}
if (x > y && x != 0 && y != 0) {
// do a
// do b
return;
}
if (x != 0 && y == 0) {
// do a
// do b
return;
}
if (x == 0 && y != 0) {
// do a
// do d
return;
}
if (x == 0 && y == 0) {
// do e
return;
}
}
Motivation:
The advantage of the original code is that it clearly covers all possible input combinations.
The first three if statements handle the cases where x and y are non-zero (with x==y, x<y, and x>y handled separately). Then the remaining three if statements handle the cases where one or both are zero. That covers everything.
The disadvantages of the original code are:
Many of the comparisons are repeated several times, e.g. y != 0 is checked four times. Given that branching statements tend to be time consuming in contemporary (year 2021) processors, redundant comparisons are something to be avoided 1.
The code violates the DRY principle. Specifically, do a appears in five locations, and do b appears in three locations. So any refactoring of the code should attempt to eliminate the repetition.
1) The optimizer may be able reduce the number of comparisons. However, that's hard to test without real code.
Refactoring with nested if statements:
If we focus on the DRY principle first, we notice that a appears in 5 of 6 code blocks. Only the case for e doesn't invoke a. So the logical choice is to handle e first. This results in the following code structure:
if (x == 0 && y == 0) {
// do e
} else {
// do a
// everything else (note that either x is not zero, or y is not zero)
}
Within the "everything else", we have do b three times, do c once, and do d once. So the next step is to handle c and d, leaving only b. The refactored code looks like this:
void nestedIf(int x, int y)
{
if (x == 0 && y == 0) {
// do e
} else {
// do a
if (x == 0) {
// do d
} else {
if (y != 0 && x < y) {
// do c
} else {
// do b
}
}
}
}
Refactoring with early return statements:
Some coding standards insist that a function shall only return from one location. The nested if code meets that requirement, but at the cost of being a little messy due to nesting. Using early returns eliminates the nesting, and may allow the code for a thru e to be implemented inline without additional functions (assuming they're only a few lines each). The refactored code looks like this:
void earlyReturn(int x, int y)
{
if (x == 0 && y == 0) {
// do e
return;
}
// do a
if (x == 0) { // x is zero and y is not zero
// do d
return;
}
if (y != 0 && x < y) { // x and y are both not zero, and x < y
// do c
return;
}
// do b
}
assuming a(), b(), and e() have the same type (fxtype)
fxtype *fx[4] = { e, NULL, b, a }; // NULL when x==0, y!=0
fx[2*!!x + !!y](x, y);
Change a to include c() and b()
int a(int x, int y) {
// do previous a()
if (x < y) c(x, y); else b(x, y);
return 0;
}
#include <stdio.h>
int main()
{
int x = 2, y = 0;
int m = (y |= 10);
int z = y && m;
printf("%d\n", z);
return 0;
}
Above program gives me output as 1. Below code is giving me output 0 but what is the reason for different outputs here?
#include <stdio.h>
int main()
{
int x = 2, y = 0;
int z = y && (y |= 10);
printf("%d\n", z);
return 0;
}
In
int z = (y |= 10);
y is masked with 10 so set to 10, so y && m is a boolean worth 1 because both y and m are non-zero, assigned to z
Now, in
int z = y && (y |= 10);
y == 0 so && short-circuits, not evaluating the right hand part and not changing the value of y. Therefore, z is set to 0.
Had you used:
int z = y & (y |= 10);
this would have depended on how/in which order the compiler evaluates the operands (implementation defined behaviour to get 0 or 10)
note that && short-circuiting doesn't evaluate the second parameter if the first is zero for a very good reason:
if ((pointer != NULL) && pointer->value == 12) { do_something(); }
this condition checks if the value is 12 but only if the pointer is non-NULL. If the second expression was evaluated first, this could crash.
I'm trying to port the following C code to Go:
if (x == 0 || x-- == 0) {
// Stuff
}
This isn't legal in Go because I can't modify x inside the check clause.
What's a good way of representing this in Go without e.g. duplicating the contents of the block?
If x-- is a typo and should be --x, then I would make the changes to x explicit:
if x == 0 || x == 1 {
x = 0
// Stuff
} else {
x--
}
Otherwise, your C code has a bug. If x == 0 is false, then x-- == 0 will also be false because you're using the post-increment operator. Therefore, the code would be equivalent to:
if (x == 0) {
// Stuff
} else {
x--;
}
The Go code
if x != 0 {
x--
} else {
// Stuff
}
is equivalent to the C code
if (x == 0 || x-- == 0) {
// Stuff
}
For example, in Go,
package main
import (
"fmt"
)
func main() {
for _, x := range []int{-42, -2, -1, 0, 1, 2, 42} {
fmt.Printf("x %d:", x)
if x != 0 {
x--
} else {
fmt.Printf(" Stuff %d:", x)
}
fmt.Printf(" x %d:\n", x)
}
}
Output:
x -42: x -43:
x -2: x -3:
x -1: x -2:
x 0: Stuff 0: x 0:
x 1: x 0:
x 2: x 1:
x 42: x 41:
For example, in C,
#include <stdio.h>
int main() {
int a[] = {-42,-2,-1,0,1,2,42};
for (int i = 0; i < (sizeof a)/sizeof a[0]; i++) {
int x = a[i];
printf("x %d:", x);
if (x == 0 || x-- == 0) {
printf(" Stuff %d:", x);
}
printf(" x %d:\n", x);
}
}
Output:
x -42: x -43:
x -2: x -3:
x -1: x -2:
x 0: Stuff 0: x 0:
x 1: x 0:
x 2: x 1:
x 42: x 41:
int gcd(int x, int y) {
int t;
while (y) {
t = x;
x = y;
y = t % y;
}
return x;
}
Does it stop when y = 0? I thought the loop stops when y isn't defined.
Yes, it stops when y is 0, what you have
while (y)
is short hand for
while (y != 0)
While loops loop while a variable is not 0.
I am not understanding for loop statement and expression following it. Please do help me understand.
#include<stdio.h>
int main()
{
int x = 1;
int y = 1;
for( ; y ; printf("%d %d\n",x,y))
y = x++ <= 5;
return 0;
}
And the output I got
2 1
3 1
4 1
5 1
6 1
7 0
y = x++ <= 5; ==> y = (x++ <= 5); ==> first compare x with 5 to check whether x is small then or equals to 5 or not. Result of (x++ <= 5) is either 1, 0 assigned to y,
As x becomes > 5, (x++ <= 5) becomes 0 so y = 0 and condition false and loop break,
Basically the for syntax is:
for(StartCondition; Test; PostLoopOperation) DoWhileTestPasses;
In this case:
StartCondition == None
Test == (y != 0)
PostLoopOperation == do some printing
DoWhileTestPasses == set y to zero if x > 5 otherwise to non-zero THEN increment x.
Which is all rather bad practice because it is confusing.
Would be better written as:
int x=0;
int y=0;
for(y=0; y = (x <= 6); x++)
{
printff("%d %d\n",x,y);
}
return(0);
In y = x++ <= 5;, y stores the value that is output by the condition x++ <= 5 (here x++ is post increment). If the condition is true then y = 1 else y = 0.
for( ; y ; printf("%d %d\n",x,y))
In the for loop you are printing the values of x and y after executing the for loop body.
Initialize your variables:
int x = 1; int y = 1;
There are 3 statements for the for loop: -1. Initialize, 2. Condition, 3. Iteration:increment/decrement
In your case, you did not provide the initialize condition, however, you have the part of condition and incrementation. I do not think your for loop is used in the correct way.
You should swap the part of incrementation with your body like this:
for(; y; y = x++ <= 5;)
printf("%d %d\n", x, y)
First, you check whether the condition is true or not, y is true or not. Then, you print x and y out. Then, the part of incrementation is executed, x++ <= 5 or not. The result is assigned to y. It does so until your condition is false, y == false.
NOTE: For the good programming, you should enclose your body with a curly braces.
similar to this
int x = 1;
for( int y = 1; y!=0 ; )
{
if (x++ <= 5)
{
y = 1;
}
else
{
y = 0;
}
printf("%d %d\n",x,y);
}
Perhaps this slightly transformed (but functionally equal) code will help:
int x = 1;
int y = 1;
while (y) {
y = (x <= 5);
x = x + 1;
printf("%d %d\n", x, y)
}