The loop in your code indeed does not work as the test i >= 0 is always true. Compiling with extra warnings will spot this problem.
To avoid this problem, i should be initialized to 10, the test should be i > 0 and i should be decremented at the start of each iteration instead of after it:
for (unsigned i = 10; i > 0;) {
i--;
printf("a[%d]: %d\n", i, a[i]);
}
Combining the test and the decrement produces the classic down loop that works for both signed and unsigned index types:
#include <stdio.h>
int main(void) {
char a[10] = { 0 };
for (unsigned i = sizeof(a) / sizeof(*a); i-- > 0;) {
printf("a[%u]: %d\n", i, a[i]);
}
return 0;
}
The test i-- > 0 is only false for i == 0, but i is decremented as a side effect, so the first iteration uses the value 9 inside the loop body, the second uses 8... and the last uses 0, the value of i after the last decrement. The next next will evaluate to false and leave i with the value UINT_MAX.
Another advantage of this technique is i is initialized to the number of elements, 10, which is also the number of iterations, not 9 as in the question code.
Note also that i-- > 0 can be written i --> 0 as explained in this popular question. While i-- > 0 is idiomatic in C, i --> 0 is not. Whether one is more elegant than the other is a matter of opinion
>=0and wraparaound overflow/underflow is fine on them). Going from0to-1isn't underflow/overflow, going left ofINT_MINor right ofINT_MAXis.icannot overflow or reach −1. Unsigned arithmetic is defined to wrap, so, wheniis zero,i--wraps it around to the maximum representable value,UINT_MAX. This is different from overflow in the meaning of the C standard. So you should say thatiwraps (not overflows) and becomes large (not −1), and then there is a segment fault becausea[i]attempts to access an element out of bounds (not directly becauseioverflowed or wrapped).iis anunsigned intbecause in this case, the conditioni >= 0is always true and the loops never ends.i != -1, as it works with both signed types and unsigned types at least as wide asint(because the −1 will be converted to the maximum value). That could be reasonable as an idiomatic solution except it fails for narrower unsigned types.unsigned inttochar.