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