I know it's "too clever", but if I'm writing code no one else will ever see,
while (i --> 0) {
// use array[i]
}
easy to read (if not understand), and correct!I thought most people used the explicit version:
for (size_t i = count; i > 0; --i) {
// use array[i - 1]
}
You can also do something like: size_t index = i - 1;
to not have to use i-1. I believe the compiler optimizes that out anyway to be identical.That's the price of innovation, I guess; before C invented its "for"-loop, other languages had their equivalents generally looking like this:
FOR var = start [DOWN] TO end BY step DO ... END
No custom increment expressions, and "step" even usually was only allowed to be a constant (in which case, the language usually didn't have DOWN specifier and used the step's sign instead). Then Dennis Ritchie invented C, and ditched the traditional "do"-loop (Fortran started that construct with DO, so it was called DO loop; Algol used FOR instead, but most people preferred the Fortran's nomenclature... until C came to dominate, but that wouldn't happen for yet another 20 years) in favour of his invention because he felt that easily iterating through linked lists or strings was a much more pressing concern: for(p=head; p; p=p->next) { ... }
for(s=str; *s; s++) { ... }
The downside, of course, is that now you can't straightforwardly write for size_t i = count - 1 downto 0 do
...
endI do this in another way:
for( size_t i_plus_one = count; i_plus_one > 0; --i_plus_one )
{
const size_t i= i_plus_one - 1;
// actual loop code
}
It's in my opinion better than using i-- as condition, since I generally avoid using results of -- and ++, because doing so is bug-prone.This is why I prefer to use C++ and its reversed iterators. The rbegin and rend accessors are there in the containers from the beginning. It’s less error prone than the C version using indices. (Of course some situations require me to use indices, so I do use the i-->0 trick, but it is much rarer.)
For the uninformed: counting backwards in a for loop is faster because comparing an unsigned integer against 0 is generally faster than comparing it against any other value.
It also says not to use `for (i >= 0)` because any unsigned integer is >= 0, and the loop will never end.
Why not use the C/C++ idiom of pointer math?
_Bool find_last (size_t count, int *haystack, int needle, size_t *where)
{
for (const int *pos = haystack + count; pos-- != haystack;) {
if (*pos == needle) {
*where = pos - haystack;
return 1;
}
}
return 0;
}As long as you make sure the end points are valid, this is most intuitive for me. Just using i as a backwards step.
for (int i = 1; i <= N; i++) {
array[N-i]
}I prefer:
const size_t n = 10;
for (size_t i = n; i --> 0;) {
std::cout << i << "\n";
}I've been using this method for more than 30 years!
> Now your index variable is signed, which can cause problems when used in expressions due to C's conversion rules.
Array indices are already signed. This shouldn't be a problem.
[flagged]
[flagged]
[dead]
I myself write loops with goto. It gives precise control, allows to reuse the knowledge gained from operations inside the loop, avoids artificial "while true" and is generally more convenient. It is also makes the language simpler as you can forget 4 to 5 loop-related keywords and hard-to parse operators designed primarily to look nice in loop conditions while also modifying their arguments.