1

I am new to C++ and I am trying to achieve a backward for loop, I founded solutions which works very well but I want to know what my version is not correct and making an infinite loop.

Here is a working version that I founded (I don't understand how we can decrease i in the condition..) :

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

Here is a version I wrote which works but don't go down to 0 (this way seems more logical to me) :

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

If I say for exemple n=10, I will get this if I print i in the loop :

9
8
7
6
5
4
3
2
1

And here is the version which for me is the more logical and should go down to zero but is providing an infinite loop.

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

Could someone explain to me why the last version isn't working and what is the best choice to make ?

Antonio Pérez
  • 6,078
  • 4
  • 27
  • 54
oktomus
  • 497
  • 3
  • 24
  • 2
    It's an unsigned integer. When you subtract 1 from 0 qua unsigned int, you get a very large positive number rather than -1, because -1 isn't in the range of values representable as unsigned integers. Change it to a signed int (if your upper limit is in the range representable in that data type). – Hammerite Jun 03 '16 at 09:08
  • Thank you @Hammerite ! I didn't know that – oktomus Jun 03 '16 at 09:09
  • 1
    [This reference should tell you all you need to know.](http://en.cppreference.com/w/cpp/language/operator_arithmetic#Overflows) – Some programmer dude Jun 03 '16 at 09:09
  • Worth noting since you start from "size": the c++11 provide `std::rbegin()` and `std::rend()`, so iterate-able containers can be iterated backwards by `for (auto it = std::rbegin(values); it != std::rend(values); ++it) { std::cout << std::distance(std::begin(values), it) << std::endl; }`, – stefaanv Jun 03 '16 at 09:27
  • A good compiler of code analyser should warn that such condition is always-true – Ajay Jun 03 '16 at 09:28

2 Answers2

5

An unsigned number is always >= 0. (When it reaches zero a further decrement sets it to std::numeric_limits<unsigned>::max())

So your final for loop is equivalent to

for (unsigned i = size-1 ; true ; i--)

which, of course, loops forever.

In your first loop, you have i-- > 0 as the stopping condition. When i is zero, i-- is an expression with value zero (so the loop halts), despite the fact that i is then set to std::numeric_limits<unsigned>::max(). Some folk like (me included; cue the downvotes) to write i-->0 and regard --> as the slide operator. See What is the "-->" operator in C++?

Community
  • 1
  • 1
Bathsheba
  • 220,365
  • 33
  • 331
  • 451
  • Thanks ! Can you tell me more about the `i--` in the condition for the first version ? I didn't that was possible.. – oktomus Jun 03 '16 at 09:14
  • 1
    Added that. It's rather elegant, if a little hard to follow, especially at 3am when you're debugging something! Perhaps therefore worth avoiding. – Bathsheba Jun 03 '16 at 09:16
  • 1
    That's a good question! It really depends on your field and so is subjective. I'm a scientific programmer so *love* the `-->` idiom, especially when working with `unsigned` types. When I retire all my poor colleagues will be expected to understand the idiom. But I think that could be the exception rather than the norm. Another approach would be to use `signed` types, or use a different loop structure. – Bathsheba Jun 03 '16 at 09:22
  • Ok thanks, I think I will go for the `unsigned` types – oktomus Jun 03 '16 at 09:47
2

The statement i >= 0 is always true because i is unsigned which means that is never below zero. If you decrease the value while i is zero, there will occur a so-called underflow and it will have a very high number.

The first version certainly gets the job done, so I would stick to it.

IceFire
  • 3,719
  • 2
  • 19
  • 46