Reputation: 173
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?
Upvotes: 13
Views: 308
Reputation: 11
#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");
}
The above code executes till i = 8
and the first condition i < size
that is 8 < 9
but the second condition oneOrZero[8]
is false
. and anyway i will be incremented to 9. 9 == 9
so it will print "All ones"
will be printed giving you the wrong output.
#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");
}
The above code executes till i = 8
and evaluates to i < size
and 8 < 9
but oneOrZero[i]
oneOrZero[8] = 0
and evaluates to false
and comes out of the loop
and i == size
8 == 9
and prints Has a zero
will be printed, giving you the correct output.
Upvotes: 0
Reputation: 23802
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.
Upvotes: 17
Reputation: 105886
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 incrementedThus 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.
Upvotes: 7