What's the best way to do a reverse 'for' loop with an unsigned index?

CFor Loop

C Problem Overview


My first attempt of reverse for loop that does something n times was something like:

for ( unsigned int i = n-1; i >= 0; i-- ) {
    ...     
}

This fails because in unsigned arithmetic i is guaranteed to be always greater or equal than zero, hence the loop condition will always be true. Fortunately, gcc compiler warned me about a 'pointless comparison' before I had to wonder why the loop was executing infinitely.


I'm looking for an elegant way of resolving this issue keeping in mind that:

  1. It should be a backwards for loop.
  2. The loop index should be unsigned.
  3. n is unsigned constant.
  4. It should not be based on the 'obscure' ring arithmetics of unsigned integers.

Any ideas? Thanks :)

C Solutions


Solution 1 - C

How about:

for (unsigned i = n ; i-- > 0 ; )
{
  // do stuff with i
}

Solution 2 - C

for ( unsigned int loopIndex = n; loopIndex > 0; --loopIndex ) {
    unsigned int i = loopIndex - 1;
    ...
} 

or

for ( unsigned int loopIndex = 0; loopIndex < n; ++loopIndex ) {
    unsigned int i = n - loopIndex - 1;
    ...
} 

Solution 3 - C

for ( unsigned int i = n; i != 0; i-- ) {
    // do something with i - 1
    ...     
}

Note that if you use C++ as well as C, using != is a good habit to get into for when you switch to using iterators, where <= etc. may not be available.

Solution 4 - C

Why not simply:

unsigned int i = n;
while(i--)
{ 
    // use i
}

This meets all the requirement enumerated in the body of the question. It doesn't use anything likely to fail code review or violate a coding standard. The only objection I could see to it is if the OP really insisted on a for loop and not a straightforward way of generating i = (n-1) .. 0.

Solution 5 - C

I'd tend to use

 for ( unsigned int i = n; i > 0; )  {
    --i;
    ...     
 }

it's almost the same as skizz' answer, (it misses out a final unnecessary decrement, but the compiler should optimise that away), and actually will pass code review. Every coding standard I've had to work with has had a no-mutation in conditional rule.

Solution 6 - C

for ( unsigned int i = n; i > 0; i-- ) {
    ...  
    i-1 //wherever you've been using i   
}

Solution 7 - C

Maybe this way? IMHO its clear and readable. You can omit the if(n>=1) if it is implicitly known somehow.

if(n>=1) {
    // Start the loop at last index
    unsigned int i = n-1;
    do {
       // a plus: you can use i, not i-1 here
    } while( i-- != 0 );
}

Another version:

if(n>=1) {
    unsigned int i = n;
    do {
       i--;

    } while( i != 0 );
}

The first code without if statement would look like:

unsigned int i = n-1;
do {

} while( i-- != 0 );

Solution 8 - C

for (unsigned int i = n-1; i<(unsigned int)-1; i--)

OK, its "obscure ring arithmetic".

Solution 9 - C

Or you could rely on the wrapping behaviour of unsigned int if you need indexing from n-1 to 0

for(unsigned int i = n-1; i < n; i--) {
    ...
}

Solution 10 - C

for ( unsigned int i = n; i > 0; i-- ) {
    unsigned int x = i - 1;
    // do whatever you want with x    
}

Certainly not elegant, but it works.

Solution 11 - C

The only reason I mention this option is because I did not see it in the list.

for ( unsigned int i = n-1; i < n; i-- ) {
... 
}

Totally against intuition, but it works. the reason it works is because subtracting 1 from 0 yields the largest number that can be represented by an unsigned integer.

In general I do not think it is a good idea to work with unsigned integers and arthmetic, especially when subtracting.

Solution 12 - C

Easy, just stop at -1:

for( unsigned int i = n; i != -1; --i )
{
 /* do stuff with i */
}

edit: not sure why this is getting downvoted. it works and it's simpler and more obvious than any of the above.

Solution 13 - C

for ( unsigned int i = n; i > 0; i-- ) {
    ...     
}

Should work fine. If you need to use the i variable as an index into an array do it like this:

array[i-1];

Solution 14 - C

Hm. Here are your options:

  1. Use i=0 as your break condition - Loop will not execute when i reaches 0, so execute 1 iteration of the loop contents for i=0 after the loop has exited.

for ( unsigned int i = n-1; i > 0; i-- ) {
doStuff(i);
}
doStuff(0);

  1. In the loop, test for i=0 and break out. Not recommended because now you're testing the value of i twice in the loop. Also using break within a loop is generally regarding as bad practice.

for ( unsigned int i = n-1; i >= 0; i-- ) {
doStuff(i);
if (i=0) break;
}

Solution 15 - C

unsigned index;
for (unsigned i=0; i<n; i++)
{
    index = n-1 - i; // {i == 0..n-1} => {index == n-1..0}
}

Solution 16 - C

Since this is not a standard for loop I would probably use a while loop instead, e.g.:

unsigned int i = n - 1;
while (1)
{
    /* do stuff  with i */

     if (i == 0)
    {
        break;
    }
    i--;
}

Solution 17 - C

This is untested, but could you do the following:

for (unsigned int i, j = 0; j < n; i = (n - ++j)) {
    /* do stuff with i */
}

Solution 18 - C

Use two variables, one to count up, and the other for the array index:

unsigned int Index = MAX - 1;
unsigned int Counter;
for(Counter = 0; Counter < MAX; Counter++)
{
    // Use Index
    Index--;
}

Solution 19 - C

for ( unsigned int i = n-1; (n-i) >= 0; i-- ) {
    // n-i will be negative when the loop should stop.
    ...     
}

Solution 20 - C

e.z:

#define unsigned signed

for ( unsigned int i = n-1; i >= 0; i-- ) { ... 
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAuronView Question on Stackoverflow
Solution 1 - CSkizzView Answer on Stackoverflow
Solution 2 - CLou FrancoView Answer on Stackoverflow
Solution 3 - CanonView Answer on Stackoverflow
Solution 4 - CidzView Answer on Stackoverflow
Solution 5 - CPete KirkhamView Answer on Stackoverflow
Solution 6 - CvartecView Answer on Stackoverflow
Solution 7 - CanonView Answer on Stackoverflow
Solution 8 - CEric BainvilleView Answer on Stackoverflow
Solution 9 - CpejeView Answer on Stackoverflow
Solution 10 - CitsmattView Answer on Stackoverflow
Solution 11 - CRenze de WaalView Answer on Stackoverflow
Solution 12 - CDaveView Answer on Stackoverflow
Solution 13 - CarulView Answer on Stackoverflow
Solution 14 - CTimView Answer on Stackoverflow
Solution 15 - Cuser80452View Answer on Stackoverflow
Solution 16 - CstarblueView Answer on Stackoverflow
Solution 17 - CSpoonMeiserView Answer on Stackoverflow
Solution 18 - CSteve MelnikoffView Answer on Stackoverflow
Solution 19 - CPaulo GuedesView Answer on Stackoverflow
Solution 20 - CPuqqaView Answer on Stackoverflow