I can't get my head around why the code below is not working as expected:
#include <stdio.h>
int main() {
int i = 0, size = 9, oneOrZero[] = {1,1,1,1,1,1,1,1,0};
while (i < size && oneOrZero[i++]);
if (i == size) printf("All ones"); else printf("Has a zero");
}
Terminal: All ones.
When incrementing the index inside the loop makes the code run as expected:
#include <stdio.h>
int main() {
int i = 0, size = 9, oneOrZero[] = {1,1,1,1,1,1,1,1,0};
while (i < size && oneOrZero[i]) {i++;}
if (i == size) printf("All ones"); else printf("Has a zero");
}
Terminal: Has a zero.
Could someone explain the difference between these two?
The only difference is the order of operations between the increment of the variable and the value the operator returns. So basically ++i returns the value after it is incremented, while i++ return the value before it is incremented. At the end, in both cases the i will have its value incremented.
arr[i++] = i; where i has been incremented by the time its value is written to the array.
This operator is used in C# to increment the value of its operand by one. The type of the resulting value is the same as that of its operand.
In the first code, when i is 8, oneOrZero[i] will evaluate to false because oneOrZero[8] == 0, but i will be incremented to 9 anyway, the increment is not dependent on the truthiness of the expression, it will happen as many times as the expression is evaluated.
So naturally when i == size is evaluated it's 9 == 9, this is, of course, true, therefore "All ones" will be printed giving you the wrong output.
In the second code i is incremented inside the body of the conditional expression, this means it will only be incremented if the condition is met, so when i is 8, oneOrZero[i] will evaluate to false and i is not incremented, retaining its 8 value.
In the next line statement i == size will be 8 == 9 which is false and "Has a zero" will be printed, giving you the correct output.
This is a typical off-by-one error when one uses a iteration index i also for a check (comparison with size). No worries, it happens to almost everyone, all the time.
The problem is that, even though the condition failed, we already changed the result (i) in oneOrZero[i++]. Our second variant doesn't fall into this trap, as the condition and the index increment are decoupled.
We can replicate that behavior with a simpler example:
#include <stdio.h>
int main() {
int i = 0, size = 1, oneOrZero[] = {0};
while (i < size && oneOrZero[i++]);
if (i == size) printf("All ones"); else printf("Has a zero");
}
Now, let's check the condition by hand:
i < size is fine, so we continue to evaluate the right-hand side.i++ increments i to 1 (aka size)oneOrZero[0] is 0, thus the condition failsAfter this single iteration, i == size, and we print All ones.
Compare this to the other variant:
int main() {
int i = 0, size = 1, oneOrZero[] = {0};
while (i < size && oneOrZero[i]) {i++;}
if (i == size) printf("All ones"); else printf("Has a zero");
}
Again, we check the condition:
i < size is fineoneOrZero[0] == 0, so we stop.i never gets incremented
Thus i < size and we print Has a zero.
Note that it's possible to change the condition into
int i = -1;
while(++i < size && oneOrZero[i]);
but that needs careful documentation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With