Unsigned integers in C++ for loops

23,189

Solution 1

The problem here is that an unsigned integer is never negative.

Therefore, the loop-test:

i >= 0

will always be true. Thus you get an infinite loop.

When it drops below zero, it wraps around to the largest value unsigned value.
Thus, you will also be accessing x[i] out-of-bounds.

This is not a problem for signed integers because it will simply go negative and thus fail i >= 0.

Thus, if you want to use unsigned integers, you can try one of the following possibilities:

for (unsigned int i = 9; i-- != 0; )

and

for (unsigned int i = 9; i != -1; i--)

These two were suggested by GManNickG and AndreyT from the comments.


And here's my original 3 versions:

for (unsigned int i = 9; i != (unsigned)0 - 1; i--)

or

for (unsigned int i = 9; i != ~(unsigned)0; i--)

or

for (unsigned int i = 9; i != UINT_MAX; i--)

Solution 2

The problem is, your loop allows i to be as low as zero and only expects to exit the loop if i is less than 0. Since i is unsigned, it can never be less than 0. It rolls over to 2^32-1. That is greater than the size of your vector and so results in a segfault.

Solution 3

Whatever the value of unsigned int i it is always true that i >= 0 so your for loop never ends.

In other words, if at some point i is 0 and you decrement it, it still stays non-negative, because it contains then a huge number, probably 4294967295 (that is 232-1).

Solution 4

The problem is here:

for (unsigned int i = 9; i >= 0; i--) 

You are starting with a value of 9 for an unsigned int and your exit definition is i >= 0 and this will be always true. (unsigned int will never be negative!!!). Because of this your loop will start over (endless loop, because i=0 then -1 goes max uint).

Share:
23,189
Benjamin
Author by

Benjamin

Updated on July 17, 2022

Comments

  • Benjamin
    Benjamin almost 2 years

    I have made some research on Stackoverflow about reverse for loops in C++ that use an unsigned integer instead of a signed one. But I still do NOT understand why there is a problem (see Unsigned int reverse iteration with for loops). Why the following code will yield a segmentation fault?

    #include <vector>
    #include <iostream>
    using namespace std;
    
    int main(void)
    {
        vector<double> x(10);
    
        for (unsigned int i = 9; i >= 0; i--)
        {
            cout << "i= " << i << endl;
            x[i] = 1.0;
        }
    
        cout << "x0= " << x[0] << endl;
    
        return 0;
    }
    

    I understand that the problem is when the index i will be equal to zero, because there is something like an overflow. But I think an unsigned integer is allowed to take the zero value, isn't it? Now if I replace it with a signed integer, there is absolutely no problem.

    Does somebody can explain me the mechanism behind that reverse loop with an unsigned integer?

    Thank you very much!

  • Matthieu M.
    Matthieu M. over 12 years
    Or have i be one more than the index, so that 0 is a proper termination condition. As tricky as the rest though.
  • josefx
    josefx over 12 years
    Aren't integer overflow and underflow undefined behavior?
  • Mysticial
    Mysticial over 12 years
    @josefx Only signed integer over/underflow is undefined behavior.
  • GManNickG
    GManNickG almost 12 years
    Or for (unsigned int i = 9; i-- != 0; )
  • Mysticial
    Mysticial almost 12 years
    @GManNickG Ha. I never considered dumping the decrement into the test. :)
  • AnT stands with Russia
    AnT stands with Russia almost 12 years
    I'm not sure what the purpose of all those complicated conditions is. You can simply do for (unsigned int i = 9; i != -1; i--). No need for any casts. A direct comparison to -1 will automatically perform all necessary conversions. -1 is equivalent to UINT_MAX in this context, but -1 is better because it is type-independent.
  • Mysticial
    Mysticial almost 12 years
    @AndreyT I wasn't sure on the exact implicit conversion rules. That's why I made the casts explicit. But if you say it works regardless, I can make the edit.
  • Galaxy
    Galaxy over 6 years
    If you put a cout << i << ' '; as the body of each loop, you will see that i for the first loop ranges [9-0] inclusive, while for the rest of the loops, i ranges [10-0] inclusive.
  • Galaxy
    Galaxy over 6 years
    I would like to propose two of my loops: You don't need a type cast to take the bitwise not of 0, which is all 1s anyway. For signed int, all 1s is equal to -1, and for unsigned int all 1s is equal to UINT_MAX. I must point out that this approach works with an integer data type of any size in bytes. No matter what size in bytes the int literal 0 takes up, all bits get flipped to one. for (unsigned int i = 10; i != ~0; i--)
  • Galaxy
    Galaxy over 6 years
    The next one is basically the same thing but compares i to 32 1s, or 8 fs in hexadecimal. This assumes that an unsigned int takes up 4 bytes or 32 bits of space, hence the 8 fs in the hexadecimal number. That might be a problem if int is not 4 bytes in size, which could occur on weird and obscure compilers/operating systems/architectures such as on embedded systems. So one must be careful with such comparisons. for (unsigned int i = 10; i != 0xffffffff; i--)
  • Salem Derisavi
    Salem Derisavi about 6 years
    The answer from @GManNickG is neat but it needs to start from 10 instead of 9 for (unsigned int i = 10; i-- != 0; )