What will the following code evaluate? - c

I had the following code in a test.I am confused about what (i,j) evaluates,while reading about the "," operator i found that it just evaluates the variables or functions but what does it do here?
main()
{
int i = 10, j = 20;
j = i ? (i, j) ? i : j : j;
printf("%d %d", i, j);
}

(i,j) is exactly the same as just j, because i is just a variable and evaluating it doesn't cause any side effect.
So basically it's just obfuscation here.

in (i,j), the , operator does nothing because the left-hand side expression does not have side-effects.
The assignment is thus equivalent to:
j = i? (j? i : j) : j;
And since i and j are non-zero, to j = i;

The comma operator can be used to link the related expressions together. A comma-linked list of expressions is evaluated left-to-right and the value of the rightmost expression is the value of the combined expression. It acts as a sequence point.
A sequence point guarantees that all side effects of previous evaluations will have been performed, and no side effects from subsequent evaluations have yet been performed.
So, any expression/assignment will be completed & only then will the next expression to the right be evaluated.
For example,
b=(a=4,a=5);
gives,
a=5
b=5
Also, note that the comma operator ranks last in the precedence list of operators in C.

It will print:
10 10
This is because you can break the expression down like:
j = i ? ((i, j) ? i : j) : j;
The comma operator evaluates to the last expression - so (i, j) == j. That is non-zero, so the center expression evaluates to i. 'i' being non-zero, the outer expression evaluates to i, so j is assigned to the value of i.

This is equivalent to:
int main() {
int i = 10, j = 20;
if (i != 0) {
(void)i; // Do nothing with i.
if (j != 0) {
j = i;
} else {
j = j; // Assign j to itself.
}
} else {
j = j; // Assign j to itself.
}
printf("%d %d", j);
}

Looks like typical software written test question. It is used to confuse candidates. As suggested by sepp2k above it is same as j. One more interview question
i = 10; j = 20;
1) k = i,j;
2) k = (i,j);
Answer for 1 will be 10 and answer for 2 will be 20. As coma operator doesnt do anything. I hope this will clear more.

It's not really doing anyting. It's evaluating the expression i, discards the result, evaluates the expression j and returns the result.
As evaluating the expression i has no side effects, (i,j) has the same meaning as just j.

main()
{
int i = 10, j = 20; // i=10, j=20
j = i ? /*if i */ ( (i, j) ? /* if j (1) */ i : /* else */ j ) : /* else */ j; // Added parenthesis and see (2)
printf("%d %d", i, j); // Will therefore print 10 10
}
it is equivallent to if(j) because (i,j) evaluate to j because i has no side effect.
all ifs evaluate to true because i and j are ints and are non zero

Related

How the following relational expression written in if-else statement is understood by the C Compiler?

I am unable to understand why this code is displaying 20 30 40 as output. Can anyone explain how the relational expression written in if statement is understood by the C Compiler ?
This is the image of code of the C Program
#include <stdio.h>
int main()
{
int i = 20, j = 30, k = 40;
if (i > j == k)
{
printf("%d %d %d ",--i,j++,++k);
}
else
{
printf("%d %d %d ",i,j,k );
}
return 0;
}
Output:
20 30 40
first thing to consider is operator precedence. the operator > is evaluated before the operator == and it returns a value. in this case, i > j is wrong so it returns zero. then it checks if zero equals to k which is 40 and it isn't. so it goes to else branch.
According operator precedence i > j == k is executed as (i > j) == k
So i > j is executed first, returning a boolean (here, false, ie 0)
And result is compared to k, which is not equal to 0. Condition is than false, so else part of condition is executed

Found 2 liner C solution with ',' operator in for loop, can someone explain given comma operator statement?

Explanation:
I've following problem statement at hand, I came across an interesting 2 liner, C solution for it under leedcode discussion section. I tried to decompose it to understand what it means, and except one small line, I understood the rest. My question is at the end.
Leetcode Problem Statement:
Given an array arr of positive integers sorted in a strictly increasing order, and an integer k.
Find the kth positive integer that is missing from this array.
Example 1: Input: arr = [2,3,4,7,11], k = 5
Output: 9
Explanation: The missing positive integers are
[1,5,6,8,9,10,12,13,...]. The 5th missing >>positive integer is 9.
Example 2:
Input: arr = [1,2,3,4], k = 2
Output: 6
Explanation: The missing positive integers are [5,6,7,...].
The 2nd missing positive integer is 6.
Constraints:
1 <= arr.length <= 1000
1 <= arr[i] <= 1000
1 <= k <= 1000
arr[i] < arr[j] for 1 <= i < j <= arr.length
Two liner C solution:
int findKthPositive(int* arr, int arrSize, int k){
for (int arrCurrIndex = 0, counter = 1 ; (k && (arrCurrIndex < arrSize) ? ((arr[arrCurrIndex] != counter) ? k-- : ++arrCurrIndex) : k--) || (k = counter-1, 0) ; counter++);
return k;
}
For reference: Following is a similar algorithm that's being deployed, but its just cleaner to understand.
int findKthPositive(int* arr, int arrSize, int k){
for (int counter=1, arrCurrIndex=0; counter<10000; counter++) {
// exceed arr limits
if (arrCurrIndex < arrSize) {
if (counter == arr[arrCurrIndex]) { // found element in array
index++;
continue;
}
}
// missing element
k--;
if (k==0) {
return counter;
}
}
return 0;
}
My question:
What does following line in solution #1 means exactly?
(k = counter-1, 0)
======UPDATE ON ANSWER=======
I modified solution #1 in question slightly to make it more readable. It highlights what is going on with the given statement in question.
Here is the modified solution:
int findKthPositive(int* arr, int arrSize, int k){
// move counter out of the foor loop
int counter=1;
for (int arrCurrIndex = 0;
(k && (arrCurrIndex < arrSize) ?
((arr[arrCurrIndex] != counter) ? k-- : ++arrCurrIndex)
: k--); counter++);
return counter-1;
}
The binary comma operator , evaluates the first operand, discards the result and then evaluates the second one.
In the expression you posted we have
... || (k = counter-1, 0) ;
so counter-1 is actually assigned to k but its evaluation (k itself) is discarded so that 0 is used. Why 0? Because it is the neutral operand for logic or operator ||. In fact
X || 0 ==> X
In other words we have the expression
stuff_at_the_left || (k = counter-1, 0 )
that is evaluated as
stuff_at_the_left || 0
And since 0 is the neutral operand in logical or, the final evaluation is stuff_at_the_left.
The purpose of this weird expression is to cheat: the author at some point needed to assign that value to k but without adding more lines "ruining" the one liner. So they included the assignment in the logical expression making it neutral with comma operator combined with or operator's neutral operand.We also have to say that the assignment k=counter-1, 0 is performed only if all stuff_at_the_left is evaluated as 0 (due to the short circuiting nature of logical operators in C). The resulting expanded code is
if (!stuff_at_the_left)
k= counter-1;
Note: the comma operator has the lowest precedence among all the operators in C, and that's why the assignment is performed at first.

Are multiple conditions allowed in a 'for' loop?

The following code runs without giving any errors or warnings:
#include <stdio.h>
int main(){
int i, j;
int p = 0, q = 2;
for(i = 0, j = 0; i < p, j < q; i++, j++){
printf("Hello, World!\n");
}
return 0;
}
However, the book Let Us C (Yashwant Kanetkar) says that only one expression is allowed in the test expression of a for loop (see page 115 of the book).
I am not sure of the standard. Are multiple expressions allowed in the test expression of a for loop?
I surely can join the two expressions, but I was dumbstruck when I found the above code on this website. Is this valid C code or not?
The condition
i < p, j < q
is allowed but probably isn't what was intended as it discards the result of the first expression and returns the result of j < q only. The comma operator evaluates the expression on the left of the comma, discards it then evaluates the expression on the right and returns it.
If you want to test for multiple conditions use the logical AND operator && instead
i < p && j < q
You can link them together with boolean and (&&)
for(i = 0, j = 0; (i < p) && (j < q); i++, j++){
The above won't print out anything in the loop because the (i < p) condition fails immediately as i & p are both the same value (0).
Update: Your example is valid (but silly) C because if you start i=30 your loop will still execute 2 times, because the first result in a comma separated list is ignored.
If you want to test both conditions, use the && operator.
What is happening in your code is related to how the comma operator , works.
Both i < p and j < q are evaluated, but only the result of the 2nd expression j < q is checked by the for loop.
for(i = 0, j = 0; i < p && j < q; i++, j++){
Even I have read That Book by Mr Yashwant Kanetkar. It do says that only one condition is allowed in a for loop, however you can add multiple conditions in for loop by using logical operators to connect them. In other books that I have Read Along time Ago, said that only one condition is allowed.

left-hand operand of comma expression has no effect

for (count = index, packet_no = 0;
count < TOTAL_OBJ, packet_no < TOTAL_PKT;
count++, packet_no++)
=> left-hand operand of comma expression has no effect.
I find the above code is correct and could not understand why this error comes.
This is how the comma operator works, what you want to do is to use OR or AND (probably AND in your case):
// the condition for resuming the loop is that one of the conditions is true
count < TOTAL_OBJ || packet_no < TOTAL_PKT
// the condition for resuming the loop is that both conditions are true
count < TOTAL_OBJ && packet_no < TOTAL_PKT
You have three comma operators in each of the three terms of the for statement. The warning is for term 2.
Both expressions of terms 1 and 3 are executed as expected.
The left operation of the term 2 is evaluated only as a void, doesn't take part in the for condition, and therefore leads to your warning.
The conditional statement(for, while or if ) having conditional expressions with comma operator(s), the value of last expression is the conditional value(True or False) of conditional statement.
For ex.
int i = 1;
int j = 0;
int k = 1;
if(i, j, k) {
printf("Inside");
}else {
printf("Outside");
}
prints "Outside" as comma operator is evaluated from left to right and k is the last expression evaluated in if statement which returns false.
int i, j;
if(i = 0 , j = 1) {
printf("Inside");
}else {
printf("Outside");
}
Above prints "Inside". j = 1 is the last expression evaluated inside the if statement which has true value.
int i = 1;
int j = 0;
int k = 1;
if(i, j, k) {
printf("Inside");
}else {
printf("Outside");
}
Correction to above: This code will print "Inside" as the comma operator is evaluated from left to right and k is the last expression evaluated in the if statement, which returns true since k = 1.

Need some help understanding a weird C behavior

This part of my code works fine:
#include <stdio.h>
int main(){
//char somestring[3] = "abc";
int i, j;
int count = 5;
for((i=0) && (j=0); count > 0; i++ && j++){
printf("i = %d and j = %d\n", i, j);
count--;
}
return 0;
}
The output as expected:
i : 0 and j : 0
i : 1 and j : 1
i : 2 and j : 2
i : 3 and j : 3
i : 4 and j : 4
Things get weird when I uncomment the char string declaration on the first line of the function body.
#include <stdio.h>
int main(){
char somestring[3] = "abc";
...
}
The output:
i : 0 and j : 4195392
i : 1 and j : 4195393
i : 2 and j : 4195394
i : 3 and j : 4195395
i : 4 and j : 4195396
What's the logic behind this? I'm using gcc 4.4.1 on Ubuntu 9.10.
j never gets initialised, because of the short-circuiting behaviour of &&. Since (i=0) evaluates to false, (j=0) never gets executed, and hence j gets a random value. In the first example, that just happens to be zero.
You should say i=0, j=0 to achieve what you want.
The i++ && j++ has the same problem; it should be i++, j++.
Also, this:
char somestring[3] = "abc";
is reserving one too few bytes, because of the trailing NUL character in the string - you need four bytes. But if you're not going to modify the string, you don't need to specify the number of bytes - you can simply say this:
char *somestring = "abc";
instead.
If you use &&, only the first argument gets evaluated if it's false. i=0 is false, so j doesn't get set to 0. You should use the komma operator:
for((i=0) , (j=0); count > 0; i++, j++){ [...]
for((i=0) && (j=0)... seems to be incorrect already.
i=0 has already value of 0, so the evaluation of j=0 is not needed, so it is skipped.
(i++) && (j++) seems to be incorrect for the very first iteration, too, by the same reason.
You are using (i==0) && (j==0) to initialise both variables in your loop.
However, a property of && is that if the first operand evaluates to FALSE (i.e. 0), the second operand is never executed. So, as i is 0, j is left uninitialised. In your first run, you were simply lucky that it happened to contain the value 0.
Your variables i & j aren't initialized. What do do mean by (i=0) && (j=0)?
The compiler will make a shortcut and only assign i=0 j remains uninitialized with the effect you described.

Resources