Reputation: 2387
I have a loop that has to go from N to 0 (inclusively). My i
variable is of type size_t
which is usually unsigned. I am currently using the following code:
for (size_t i = N; i != (size_t) -1; --i) {
...
}
Is that correct? Is there a better way to handle the condition?
Thanks,
Vincent.
Upvotes: 14
Views: 3745
Reputation: 60883
Just because for
has a convenient place to put a test at the beginning of each iteration doesn't mean you have to use it. To handle N to 0 inclusive, the test should be at the end, at least if you care about handling the maximum value. Don't let the convenience suck you in to putting the test in the wrong place.
for (size_t i = N;; --i) {
...
if (i == 0) break;
}
A do-while loop would also work but then you'd additionally give up i
being scoped to the loop.
Upvotes: 6
Reputation: 106197
Personally, I would just use a different loop construct, but to each their own:
size_t i = N;
do {
...
} while (i --> 0);
(you could just use (i--)
as the loop condition, but one should never pass up a chance to use the -->
"operator").
Upvotes: 4
Reputation: 2493
for ( size_t i = N ; i <= N ; i-- ) { .... }
This would do it because size_t is an unsigned int. Unsigned ints are 32bits. When the variable i has a value of 0, you want your loop to execute the condition. If you perform i--, the computer does
00000000000000000000000000000000
-00000000000000000000000000000001
Which results in a clear overflow, giving a value of 111111111...1. For a signed two's complement integer, this value is clearly negative. However, the type of i is an unsigned int so the computer will interpret 111111...1 to be a very large positive value.
So you have a few options:
1) Do as above and make the loop terminate when overflow occurs.
2) Make the loop run from i = 0 to i <= N but use (N-i) instead of i in everywhere in your loop. For example, myArray[i] would become myArray[N-i] (off by one depending on what the value of N actually represents).
3) Make the condition of your for loop exploit the precedence of the unary -- operator. As another user posted,
for ( size_t i = N + 1 ; i-- > 0 ; ) { ... }
This will set i to N+1, check to see if the condition N+1 > 0 still holds. It does, but i-- has a side effect, so the value of i is decremented to i = N. Keep going until you get to i = 1. The condition will be test, 1 > 0 is true, the side effect occurs, then i = 0 and it executse.
Upvotes: 3
Reputation: 792069
Yes, it's correct and it is a very common approach. I wouldn't consider changing it.
Arithmetic on unsigned integer types is guaranteed to use modulo 2^N
arithmetic (where N
is the number of value bits in the type) and behaviour on overflow is well defined. The result is converted into the range 0
to 2^N - 1
by adding or subtracting multiples of 2^N
(i.e. modulo 2^N
arithmetic).
-1
converted to an unsigned integer type (of which size_t
is one) converts to 2^N - 1
. --
also uses modulo 2^N
arithmetic for unsigned types so an unsigned type with value 0
will be decremented to 2^N - 1
. Your loop termination condition is correct.
Upvotes: 8
Reputation: 43336
You can use a second variable as the loop counter to make the range of iteration clear to a future reviewer.
for (size_t j=0, i=N; j<=N; ++j, --i) {
// code here ignores j and uses i which runs from N to 0
...
}
Upvotes: 1
Reputation: 84189
Since unsigned integer will roll into its max value when decremented from zero, you can try the following, provided N
is less then that maximum value (someone please correct me if this is UB):
for ( size_t i = N; i <= N; i-- ) { /* ... */ }
Upvotes: 0
Reputation: 19337
You can use this:
for (size_t i = n + 1; i-- > 0;)
{
}
Hope that helps.
Upvotes: 4