Multiple conditions in a C 'for' loop - c

I came across this piece of code. I generally use '&&' or '||' to separate multiple conditions in a for loop, but this code uses commas to do that.
Surprisingly, if I change the order of the conditions the output varies.
#include<stdio.h>
int main() {
int i, j=2;
for(i=0; j>=0,i<=5; i++)
{
printf("%d ", i+j);
j--;
}
return 0;
}
Output = 2 2 2 2 2 2
#include<stdio.h>
int main(){
int i, j=2;
for(i=0; i<=5,j>=0; i++)
{
printf("%d ", i+j);
j--;
}
return 0;
}
Output = 2 2 2
Can somebody explain the reason? It seems to be checking only the last comma-separated condition.

The comma operator evaluates all its operands and yields the value of the last one. So basically whichever condition you write first, it will be disregarded, and the second one will be significant only.
for (i = 0; j >= 0, i <= 5; i++)
is thus equivalent with
for (i = 0; i <= 5; i++)
which may or may not be what the author of the code intended, depending on his intents - I hope this is not production code, because if the programmer having written this wanted to express an AND relation between the conditions, then this is incorrect and the && operator should have been used instead.

Of course it is right what you say at the beginning, and C logical operator && and || are what you usually use to "connect" conditions (expressions that can be evaluated as true or false); the comma operator is not a logical operator and its use in that example makes no sense, as explained by other users. You can use it e.g. to "concatenate" statements in the for itself: you can initialize and update j altogether with i; or use the comma operator in other ways
#include <stdio.h>
int main(void) // as std wants
{
int i, j;
// init both i and j; condition, we suppose && is the "original"
// intention; update i and j
for(i=0, j=2; j>=0 && i<=5; i++, j--)
{
printf("%d ", i+j);
}
return 0;
}

The comma expression takes on the value of the last (eg. right-most) expression.
So in your first loop, the only controlling expression is i<=5; and j>=0 is ignored.
In the second loop, j>=0 controls the loop, and i<=5 is ignored.
As for a reason... there is no reason. This code is just wrong. The first part of the comma-expressions does nothing except confuse programmers. If a serious programmer wrote this, they should be ashamed of themselves and have their keyboard revoked.

Do not use this code; whoever wrote it clearly has a fundamental misunderstanding of the language and is not trustworthy. The expression:
j >= 0, i <= 5
evaluates "j >= 0", then throws it away and does nothing with it. Then it evaluates "i <= 5" and uses that, and only that, as the condition for ending the loop. The comma operator can be used meaningfully in a loop condition when the left operand has side effects; you'll often see things like:
for (i = 0, j = 0; i < 10; ++i, ++j) . . .
in which the comma is used to sneak in extra initialization and increment statements. But the code shown is not doing that, or anything else meaningful.

Wikipedia tells what comma operator does:
"In the C and C++ programming languages, the comma operator (represented by the token ,) is a binary operator that evaluates its first operand and discards the result, and then evaluates the second operand and returns this value (and type)."

There is an operator in C called the comma operator. It executes each expression in order and returns the value of the last statement. It's also a sequence point, meaning each expression is guaranteed to execute in completely and in order before the next expression in the series executes, similar to && or ||.

Completing Mr. Crocker's answer, be careful about ++ or -- operators or I don't know maybe other operators.
They can affect the loop. for example I saw a code similar to this one in a course:
for(int i=0; i++*i<-1, i<3; printf(" %d", i));
The result would be $ 1 2$. So the first statement has affected the loop while the outcome of the following is lots of zeros.
for(int i=0; i<3; printf(" %d", i));

Related

Could you please explain why the value of i variable is 3 here after getting executed?

The semicolon has been added after the first while loop, but why is the value of the i variable 3 here, where j is 2?
#include<stdio.h>
int main()
{
int i=1;
while(i++<=1);
printf("%d",i);
int j=1;
while(j++<=1)
printf("%d",j);
return 0;
}
Both while loops run once (and once only); the difference is that, in the second case (the j loop) you are printing the 'control variable' inside the loop but, for the first case, you are printing it after the loop condition has evaluated to false. Also note that, in the first case, the semicolon immediately following the while statement defines the body of that loop as empty1.
Let's break down the first loop into steps:
On the first test of the condition, i++ evaluates to 1 and then i is incremented – so the loop runs.
On the second test, i++ evaluates to 2 (so the loop doesn't run) but i is still (post-)incremented, leaving it with the value of 3 (as shown in the output).
The same thing happens with j in the second loop but, in that case, as previously mentioned, you are displaying the value in the body of the loop (on its only run), so you see the value after the first (post-)increment.
As noted in the comments, if you add another printf("%d", j); after the body of the loop (which, in that case, consists of a single statement), you will see that j, too, has the value 3 when that loop has finished.
1 More precisely, the semicolon (on its own) defines a null statement, which forms the body of the while loop.
It is often helpful to clarify such 'null loops' by putting the semicolon on a line by itself (some compilers, with full warnings or static analysis enabled, may even suggest you do this):
#include<stdio.h>
int main()
{
int i = 1;
while (i++ <= 1)
; // Body of loop - Null Statement
printf("%d", i); // Loop has finished
int j = 1;
while (j++ <= 1)
printf("%d", j); // Body of loop
// Loop has finished
return 0;
}
For starters let;s consider how the postfix increment operator works. 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).
Now consider this while loop
int i=1;
while(i++<=1);
In the first iteration of the loop the value of the expression i++ as the value of its operand that is 1. So the loop will iterate a second time, Due to applying the side effect to the variable i it will be equal already to 2 when the expression i++<=1 will evaluate the second time.
Now the value of i is equal to 2 and is greater than 1. so the loop will be interrupted. Again due to applying the side effect of the postfix increment operator to the variable i it will be equal to 3. This value is outputted in the following call of printf.
In simplest terms,
consider three things for each iteration of first while loop:
first iteration:
int i = 1;//initialization
while(i++<=1); //1. i evaluated as 1,
//2. loop condition is true causing loop to iterate again.
//3. ...but not before ++ causes i==2.
second iteration:
while(i++<=1); //1. i evaluated as 2,
//2. loop condition is false causing loop to eventually exit
//3. ...but not before ++ causes i==3.
printf is not included in the while loop (because of the semicolon) but
when program flow finally reaches printf("%d",i); the value of i is output as 3
In the second loop, because printf is included in the while construct, it will output the value of j for each iteration. For the same reasons as in loop one, it will also iterate only twice, and its values at time of output will be 2 & 3.
Using a debugger to set break points, and a watch on i, you can step through code such as this to see the sequence of these effects as they happen.
For explanation porpouses look at this example:
int main()
{
int i=1;
while(i++<=1)
printf("%d",i);
printf("%d",i);
}
The Output is:
2
3
Ok let's dive into the programm procedure:
Declaring i (i = 1)
while checking Condition and it's true because i++ returns 1(old Value). That's because the ++ are after the i. If you would code it like this ++i than it returns 2(new Value) (i = 2)
execute printf (i = 2)
while checking Condition and it's false because i++ returns 2 and 2 is not <= 1 (i = 3)
execute printf (i = 3)
Do you understand?
If it solved your thoughts jumble ;) mark it as answer.
You've got many answers already so I won't try to explain it in words but with an illustration in code. I've added two functions:
One that acts like a prefix increment operator (++i)
One that acts like a postfix increment operator (i++)
I'm only using the postfix version in the program though. I've added logging to the function so you can see how it works.
#include <stdio.h>
// this acts as if you put ++ before the variable
int preinc(int* p) {
++*p;
return *p;
}
// this acts as if you put ++ after the variable
int postinc(int* p) {
int rv = *p;
++*p;
printf("returning %d but incremented to %d\n", rv, *p);
return rv;
}
int main() {
int i=1;
while(postinc(&i) <= 1);
printf("end result: %d\n---\n", i);
int j=1;
while(postinc(&j) <= 1)
printf("in loop: %d\n", j);
printf("end result: %d\n", j);
}
Output:
returning 1 but incremented to 2
returning 2 but incremented to 3
end result: 3
---
returning 1 but incremented to 2
in loop: 2
returning 2 but incremented to 3
end result: 3
If you add the semicolon in the end of the while you will take: i = 3 and j = 3(IN THE OUTPUT).
If you add the semicolon only in the end of the printf and not to the while you will take i = 2 and j = 2(IN THE OUTPUT), but in the end you will, also, have the values
i = 3 and j = 3.
This happens because the "i" variable is incremented only after the first iteration of the loop, in which the empty statement (terminated by the semicolon) is evaluated.
that is why it is highly recommended to do "++i" rather than "i++", because then the incrementation is performed prior to the evaluation.
if you flip it here, you will see that i will be equal to 2 as well, regardless of the presence of the semicolon

Why does this loop run infinite times? Comma separated conditions in for loop [duplicate]

This question already has answers here:
How does the Comma Operator work
(9 answers)
Closed 3 years ago.
Program code :
int main()
{
int i;
for (i = 0; i < 0, 5; i++)
printf("%d ", i);
return 0;
}
The loop above is executed infinite times.
What does i<0,5 mean, and how it is evaluated?
Based on operator precedence, this is interpreted as (i < 0), 5. The comma operator evaluates all statements, but discards their values except the last. So for practical purposes the loop reads as
for (int i = 0; 5; ++i) {...}
Because a non-zero value is interpreted as true in C/C++, this is equivalent to:
for (int i = 0; true; ++i) {...}
which is an infinite loop.
why i<0,5 how it is evaluated?
Because the value of a comma expression is its last value. The values in this comma expression arei < 0 and 5. This first is evaluated to false and thrown away! The second (and last) is 5 which is true. That is used as the for loop condition expression.
A for loop runs until its condition expression is false, so this loop run forever.
In the condition of the loop there is used the comma operator
for (i = 0; i < 0, 5; i++)
printf("%d ", i);
From the C Standard (6.5.17 Comma operator)
2 The left operand of a comma operator is evaluated as a void
expression; there is a sequence point between its evaluation and that
of the right operand. Then the right operand is evaluated; the result
has its type and value
So this expression with the comma operator
i < 0, 5
has two operands and can be rewritten for clarity like
( i < 0 ), ( 5 )
So the value of the expression according to the quote from the C Standard is the value of the second operand that is 5.
As 5 is not equal to 0 then the condition always evaluates to logical true and you have an infinite loop.
From the C Standard (6.8.5 Iteration statements)
4 An iteration statement causes a statement called the loop body to
be executed repeatedly until the controlling expression compares equal
to 0. The repetition occurs regardless of whether the loop body is
entered from the iteration statement or by a jump.155
It is very easy to check yourself. Try:
int main()
{
int i, y;
for (i = 0; i < 0, 5; i++)
{
y = (i < 0, 5);
printf("%d ", y);
}
return 0;
}
And you know that second expression in your list is the value of the comma expression.

C loop with two conditions - difference [duplicate]

This question already has answers here:
C comma operator
(4 answers)
Closed 5 years ago.
Whats the difference between:
int i;
for( i=0;i<5 && i<3;i++)
{
printf("stackoverflow.com");
}
and
int i;
for( i=0;i<5 , i<3;i++)
{
printf("stackoverflow.com");
}
I mean use of && instead of ','
Regards
In the second code block, only i < 3 is actually used to evaluate whether the loop should exit. The i < 5 expression is evaluated, but its value is discarded. See the comma operator for more info.
There is functionally no difference between your examples because i < 3 is the limiting expression and appears second. Both loops will exit when i reaches 3. However, if you switched the terms so that you have i < 3, i < 5, then the second kicks out when it reaches 5 because only the value of i < 5 is considered.
In this case they will do exactly the same.
The thing that differs is that in the first case i<3 will not be evaluated every time. A statement on the form A && B will only execute B if the return value of A is true. The reason is that the logical value of && is true if both operands are true. If one of them are false, the whole expression is false, so if the left operand evaluates to false, there's no need to evaluate the right operand.
The comma operator on the other hand evaluates both operands, but the result of the left operand is discarded.
When using the comma operator , in a statement like the:
( <expression1>, <expression2> )
the <expression1> is evaluated and discarded, then the <expression2> is evaluated and its value is returned. In summary the right most expression is evaluated and its value returned. Other expressions are evaluated and discarded. So your statement of:
for(i=0; i<5 , i<3; i++)
is equivalent to:
for(i=0; i<3; i++)
As for the first statement, this expression:
(i<5 && i<3)
is a simple AND boolean evaluation. A funny one because it is enough to say:
(i<3)
Long story short, who ever made this example probably expects you to say "both conditions evaluate to second expression".

Is writing 3 instructions separated by comma `,` undefined behaviour?

I think that I saw somewhere that writing more than 1 instruction separated by a comma , is undefined behavior.
So does the following code generate undefined behavior?
for (i=0, j=3, k=1; i<3 && j<9 && k<5; i++, j++, k++) {
printf("%d %d %d\n", i, j, k);
}
because there are 3 instructions separated by a comma , :
i++, j++, k++
writing more than 1 instruction separated by comma , is undefined behaviour.
Nope, it's not the general case.
In your case, i++, j++, k++ is perfectly valid.
FWIW, as per C11, chapter §6.5.17, Comma operator (emphasis mine)
The left operand of a comma operator is evaluated as a void expression; there is a
sequence point between its evaluation and that of the right operand. Then the right
operand is evaluated; [...]
[Note]: You might have got confused by seeing something along the line of
printf("%d %d %d", i++, ++i, i);
kind of statement, but do note, there the , is not a comma operator altogether (rather, a separator for supplied arguments) and the sequencing does not happen. So, those kind of statements are UB.
Again, referring to the standard, footnote 3 for the same chapter
As indicated by the syntax, the comma operator (as described in this subclause) cannot appear in contexts where a comma is used to separate items in a list (such as arguments to functions or lists of initializers).
Your example is perfectly fine C code.
There are instances where the comma has a different meaning, for example in declaration statements. In declaration statements, comma is used to separate the declaration of several variables.
int a;
a = 1,2,3; // Ok. a is assigned the value 3.
int a = 1,2,3; // Not ok!
int a = 1, b = 2; // Ok! a is assigned the value 1.

left to right evaluation of statements inside of a for loop separated by comma

Are these both codes same? These statements inside of for loop are written in same line separated by comma. Will they be evaluated for left to right?
Also i wanted to ask can i use as many as statements inside of for loop separated by comma. Like for(i=0, j=0, k=0; .......) ?
for(i=0, j= strlen(s)-1; i<j; i++, j--){
c=s[i];
s[i]=s[j];
s[j]=c;
}
and
for(i=0, j= strlen(s)-1; i<j; i++, j--)
c=s[i],s[i]=s[j],s[j]=c;
The C comma operator evaluates each of the two operands, discarding the result of the first and returning the second. With more than one comma, the operator is left associative so the effect is an evaluation from left to right.
Your second example will thus do the same thing as your first example. However it is poor style because there is no reason to use the comma operator, unlike i=0, j-strlen(s)-1 within the body of the for statement, where a semicolon could not have been used.
, operator is evaluated left to right and there is a sequence point between the evaluation of the left and the right operand, so it means both codes are equivalent.

Resources