1

The following program produces unexpected results

#include <iostream>
using namespace std;

int main() {
    for(unsigned int i = 10; i >= 0; i--)
    {
        cout << i << endl;
    }
    return 0;
}

but changing unsigned int to just int gives the output 10,9,8...,0

What is the correct way to have have an unsigned int and use it to iterate over the values [n, 0] (inclusive)? I iterate each element of an array but don't want to use the foreach syntax because I need a variable to hold the position of the element.

northerner
  • 756
  • 5
  • 21

3 Answers3

5

unsigned goes negative, not correct. Unsigned arithmetic wraps around, so in unsigned arithemetic if you subtract one from zero you get the largest possible unsigned value. What this is depends on your compiler, but if you have 32 bit integers then it would be 4294967295.

I don't think your program should crash, I think it should loop for ever because in unsigned arithmetic i >= 0 is always true.

Incidentally the way I would write that loop so that it uses unsigned arithmetic correctly is

for (unsigned int i = 11; i-- > 0; )
{
    cout << i << endl;
}
john
  • 85,011
  • 4
  • 57
  • 81
  • Right that makes sense. Then what's the correct way to iterate [n, 0] where the iterator is of type `unsigned int`? – northerner Jul 17 '19 at 08:38
  • I just added a paragraph to the answer to show one way. – john Jul 17 '19 at 08:39
  • @john good fix. But I guess you could also put the `i--` in the place for `iteration_expression` if you want to be more explicit. Also, if you use pre-increment operator, this would fail but, `for (unsigned int i = 11; i > 0; --i)` would not. Is that right? – VictorHMartin Jul 17 '19 at 09:44
  • 1
    @VictorHMartin That version would give you different output, 11 down to 1, instead of 10 down to 0, because you are decrementing after the loop, not before. – john Jul 17 '19 at 10:10
  • Ah, I see it now. Thanks for the answer @john! – VictorHMartin Jul 17 '19 at 10:12
3

If your program crashes it means that the compiler is defective.

Decreasing an unsigned once it's zero produces the largest number of that type.

The idiom

for (unsigned i = 11; i--> 0; )

(which when used with the loop body you present will output the integers 10, 9, ..., 0)

is often used when working with unsigned types, although it is falling out of fashion. --> is not really an operator in its own right as it's parsed to two separate tokens -- and >, but it's occasionally called the slide operator, particularly by older folk such as me.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
1

I think your confusion has to do with how for loops operate. Here you can find a description. The important detail is to understand the every time the loop

for (init_statement; condition; iteration_expression){ statement;}

is run, the order of the operations are equivalent to the following:

{
 init_statement 
 while ( condition ) { 
  statement 
  iteration_expression ; 
 }
}

It means that i is decreased after the block of the for loop is executed.

In the case of int, when i = 0, it runs the code inside it and then, it decreases the value. That way, the next iteration of the loop fails the condition, so it does not print i = -1.

Regarding unsigned int it never goes negative. If you debug it you will see how, once it reaches 0, instead of having the value -1 that value is converted to unsigned and the result is a big positive value. In particular, 4294967295, if unsigned int is 32 bits. You can see the details in this other question.

And that's why you have "unexpected behaviour" (not for the compiler), because suddenly you have a really big positive number, so you probably have an infinite loop in your hands.

VictorHMartin
  • 325
  • 5
  • 20