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.
Related
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.
Could you please explain why the following program is giving such outputs?
#include<stdio.h>
int main()
{
int i=-3,j=1,k=0;
int m;
m=++i || ++j && ++k;
printf("i= %d\nj=%d\nk=%d\nm=%d", i,j,k,m);
return 0;
}
Output:
i= -2
j=1
k=0
m=1
Since ++i is essentially true, because it is not 0, therefore the || other part will not be evaluated, since it does not matter at this point, the expression is true. Therefore j and k will not change. true is 1, that is why m is 1.
I can't understand why this simple code has this strange behaviour.
` code:
int main(){
int m[10][10];
int i=0;
int j=0;
for (i;i<10;i++) {
for (j;j<10;j++) {
m[i][j]=i+j;
printf("%d ", m[i][j]);
}
printf("\n");
}
printf("%d ", m[4][3]);
}
`
I'm expecting a matrix-like output, but the output is this:
0 1 2 3 4 5 6 7 8 9
32678
Note that the program prints 9 empty lines before 32678 (the printed value of m[4][3], obviously it should be 7). Thanks for your time.
for (i;i<10;i++)
{
for (j;j<10;j++)
In these both loops initialize iand j to 0. And you will get matrix like output.See working program here -https://ideone.com/cm3vV9
Declare like this
for (i=0;i<10;i++)
{
for (j=0;j<10;j++)
You get 9 lines between values because printf("\n"); run 9 time inside loop and then value of m[4][3] is printed (which is ofcourse not its value it throws just some random value ).
The reason m[4][3] is printing 32678 is because that portion of the array had not yet been initialized when you called printf() during the first iteration of the outer loop.
The inner loop code is ending after one iteration because you never initialize the loop counter j to 0 after each iteration of i. Use this code instead:
int main() {
int m[10][10];
for (int i=0; i<10; i++) {
for (int j=0; j<10; j++) {
m[i][j] = i + j;
printf("%d ", m[i][j]);
}
printf("\n");
}
}
Consider for (j;j<10;j++) carefully: j is not reset to zero on a subsequent iteration of i. Remedy this with for (int j = 0, j < 10, ++j) etc. and similarly for i. Drop the wider scope declarations of i and j.
The declaration inside a for loop construct has been part of C for a while now; keeping variable scope as local as possible helps program stability.
Your for loops are a bit strange, in that you aren't actually assigning anything to your loop counters in your initialization expressions. For example, this:
for (i;i<10;i++) {
is unusual... I'd expect to see this instead:
for (i = 0; i < 10; i++) {
...where i is set to 0 at the start of the loop.
For your outer loop, that quirk is harmless since you initialize i to 0 earlier in main()... but for your inner loop, it means that j does not start over at 0 for the second or subsequent times the loop is run, making the test expression false right away, and preventing the loop from running at all after the first iteration of the outer loop. That leaves most of your array (everything after the first row) uninitialized.
Changing the inner loop's initialization expression as follows:
for (j = 0; j < 10; j++) {
should fix it.
Note that eg. j; instead of j = 0; as the initialization expression is still valid, it just doesn't do anything.
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.
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