Basic logical operator question - c

#include <stdio.h>
int main()
{
int k=5;
if(++k < 5 && k++ / 5 || ++k <= 8)
{
printf("%d",k);
}
return 0;
}
Why is the output 7 and not 8?(I am a beginner in programming so please bear with me.)

Operator precedence and logical expression short circuit evaluation.
The && in your logical condition binds more tightly than ||, so your conditional is equivalent to:
((++k<5 && k++/5) || ++k<=8)
It's easier to read code when it is presented in a structured way, like this:
int main() {
int k=5;
if ((++k<5 && k++/5) || ++k<=8) {
printf("%d",k);
}
return 0;
}
And now a blow-by-blow of the execution.
k starts at 5.
++k<5 advances k to 6, which is not <5.
The second half of the && expression is never evaluated, because 0 && ANYTHING == 0.
Because the left hand side of the || is 0, the right hand side is not short circuited. It must be evaluated.
++k<=8 advances k to 7, which is <=8.
Total conditional evaluates to 1 because right hand side of || is 1.
The "then" clause of the if statement is executed.
Current value of k, which is 7, is printed.
The program returns 0, and terminates.
It's also worth noting that the second half of your && clause is perhaps not doing what you intended. k++/5 is integer division, and since k>5 at all times, k++/5 will always be >=1 and thus always true.

Related

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".

Multiple conditions in a C 'for' loop

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));

"--" operator in while ( ) loop

I am reading K&R book, on page 63 there is a line
while (--lim > 0 && (c=getchar()) != EOF && c != '\n')
where lim is int equal to 1000
My question, why is lim is not decreasing after consequential runs of while loop ?
As I see it, --lim is equivalent to "lim = lim - 1"
===================================================================
Thanks for all the answers !
--lim means "take one from the value of lim and use the result".
The alternative lim-- would be "use the value of lim and then take one away".
So if lim starts at 1000 the first time the loop executes it will have the value 999 before it is checked to see if it's greater than 0. If it were lim-- then the value that would be checked would be 1000, but it would still have the value of 999 at the end of the iteration through the loop. This is important at the start and end of the loop.
The MSDN as a page on this Prefix Increment and Decrement Operators
When the operator appears before its operand, the operand is incremented or decremented and its new value is the result of the expression.
Are you sure?
#include <stdio.h>
int main()
{
int lim = 10;
while (--lim > 0 && printf("%d\n",lim));
}
ouput:
9
8
7
6
5
4
3
2
1
Lim is decreasing, you probably made a mistake elsewhere. However, --lim is not quite equal to lim = lim - 1.
There are two operators to perform increment/decrement of a variable: pre-increment(or decrement), and post-increment(or decrement).
++x (pre-inc) and x++ (post-inc) both modify the value of x by +1. So what's the difference?
When you use x++ in an expression, the expression will consider x to have it's current value and after evaluating everything accordingly, increment that value by one. So...
int x = 5;
printf("%d", x++);
... will print out 5. HOWEVER, after the printf() line, the value of x will be 6.
Pre-increment works the other way round: the value of x it's first incremented, and then considered to evaluate the expression surrounding it. So...
int x = 5;
printf("%d", ++x);
... will print out 6 and, of course, the value of x will be 6 after that.
Of course, the same applies to the decrement operators.
Now, the assignment operation (x = x + 1) evaluates to the value assigned, after the assignment happened, so its behavior is actually similar to ++x, not x++.
Try to compile and run this code. It should be somewhat enlightening.
#include <stdio.h>
int main()
{
int lim = 10;
while (--lim > 0 && 1 > 32)
printf("I should never get here\n");
printf("%d\n",lim); // lim is now 9
}
Oh look, lim is now 9 even though I never actually entered the loop because 1 isn't greater than 32.
--lim or lim-- is a short hand of lim = lim - 1, So maybe author want to use this syntax to better clarify!
Excluding David's example (where the initial test of 'c' causes the loop body to never be executed, and thus lim is not decremented), and the possibility that lim is initially less than or equal to 1 (in which case the getchar() would not be executed), the code is equivalent to the following:
c=getchar();
while (lim > 1 && c != EOF && c != '\n')
{
lim = lim - 1;
/* Original body of loop */
c=getchar();
}
Both exceptions are rather unlikely and probably inconsequential, so you could use the above code if it's easier to understand.

Assigning value in while loop condition

I found this piece of code on Wikipedia.
#include <stdio.h>
int main(void)
{
int c;
while (c = getchar(), c != EOF && c != 'x')
{
switch (c)
{
case '\n':
case '\r':
printf ("Newline\n");
break;
default:
printf ("%c",c);
}
}
return 0;
}
I'm curious about expression used as condition for while loop:
while (c = getchar(), c != EOF && c != 'x')
It's quite obvious what it does, but I've never seen this construction before. Is this specific to while loop? If not, how does parser/compiler determine which side of comma-separated expression returns boolean value for while loop?
The comma operator is a binary operator that evaluates its first operand and discards the result, it then evaluates the second operand and returns this value.
It is also a "sequence point", which means that all side effects will be calculated before the next part of the code is executed.
The comma operator is a weird beastie until you get to understand it, and it's not specific to while.
The expression:
exp1, exp2
evaluates exp1 then evaluates exp2 and returns exp2.
You see it frequently, though you may not realize it:
for (i = j = 0; i < 100; i++, j += 2)
You're not actually using the return value from "i++, j += 2" but it's there nonetheless. The comma operator evaluates both bits to modify both i and j.
You can pretty well use it anywhere a normal expression can be used (that comma inside your function calls is not a comma operator, for example) and it's very useful in writing compact source code, if that's what you like. In that way, it's part of the family that allows things like:
while ((c= getchar()) != EOF) {...}
i = j = k = 0;
and so on.
For your specific example:
while (c = getchar(), c != EOF && c != 'x')
the following occurs:
c = getchar() is executed fully (the comma operator is a sequence point).
c != EOF && c != 'x' is executed.
the comma operator throws away the first value (c) and "returns" the second.
the while uses that return value to control the loop.
In many languages the comma is an operator that always results in the value of the second operand. The operands are evaluated sequentially from left to right.
Pseudo-code:
a = 10
print a = 7 + 8, a * 2
Note: print is considered a statement that does not take arguments, so what comes after is considered the single expression a = 7 + 8, a * 2.
Executed like this:
First line
put 10 in a
Second line
evaluate 7 + 8 (15)
put evaluated value (15) in a
evaluate a * 2 (30)
evaluate , operator with operands 15 and 30:
always value of second operand (30)
print evaluated value (30)
To expand a bit on the other answers, in this code:
EXPRESSION_1 , EXPRESSION_2
EXPRESSION_1 is first evaluated, then there is a sequence point, then EXPRESSION_2 is evaluated, and the value of the whole thing is the value of EXPRESSION_2.
The order of operation guarantee and the sequence point are both important to the code you quoted. Together, they mean that we can be certain that the getchar() function gets called and the value of variable c is fully updated before the value of c is tested.
The comma is an operator. It returns the value of the right hand expression by default. The order of evaluation is guaranteed to be left first and then right.
UPDATE (reply to Pax's comment):
Just like most operators, it can be overloaded for user defined types:
#include <iostream>
#include <string>
using namespace std;
enum EntryType { Home, Cell, Address };
class AddressBookEntryReference {
public:
AddressBookEntryReference(const string& name, const EntryType &entry)
: Name(name), Entry(entry) { }
string Name;
EntryType Entry;
};
AddressBookEntryReference operator,(const string& name, const EntryType &type) {
return AddressBookEntryReference(name, type);
}
class AddressBook {
string test;
public:
string& operator[](const AddressBookEntryReference item) {
// return something based on item.Name and item.Entry.
// just to test:
test = item.Name;
return test;
}
};
int main() {
// demo:
AddressBook book;
cout << book["Name", Cell] // cool syntax!
<< endl;
}

Resources