gnuvince
gnuvince

Reputation: 2387

For loop condition to stop at 0 when using unsigned integers?

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

Answers (8)

R.. GitHub STOP HELPING ICE
R.. GitHub STOP HELPING ICE

Reputation: 215287

for (i=N; i+1; i--)

Upvotes: 1

mark4o
mark4o

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

Stephen Canon
Stephen Canon

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

Kizaru
Kizaru

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

CB Bailey
CB Bailey

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

RBerteig
RBerteig

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

Nikolai Fetissov
Nikolai Fetissov

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

KeatsPeeks
KeatsPeeks

Reputation: 19337

You can use this:

for (size_t i = n + 1; i-- > 0;)
{
}

Hope that helps.

Upvotes: 4

Related Questions