Unsigned integers in C++ for loops
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).
Benjamin
Updated on July 17, 2022Comments
-
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. over 12 yearsOr have
i
be one more than the index, so that0
is a proper termination condition. As tricky as the rest though. -
josefx over 12 yearsAren't integer overflow and underflow undefined behavior?
-
Mysticial over 12 years@josefx Only signed integer over/underflow is undefined behavior.
-
GManNickG almost 12 yearsOr
for (unsigned int i = 9; i-- != 0; )
-
Mysticial almost 12 years@GManNickG Ha. I never considered dumping the decrement into the test. :)
-
AnT stands with Russia almost 12 yearsI'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 toUINT_MAX
in this context, but-1
is better because it is type-independent. -
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 over 6 yearsIf 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 over 6 yearsI 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 toUINT_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 literal0
takes up, all bits get flipped to one.for (unsigned int i = 10; i != ~0; i--)
-
Galaxy over 6 yearsThe 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 about 6 yearsThe answer from @GManNickG is neat but it needs to start from 10 instead of 9
for (unsigned int i = 10; i-- != 0; )