Hacker News
Iterating Backwards in C(davidpriver.com)
46 points by cremno 3 days ago | 21 comments
[–] Joker_vD 22 minutes ago
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
      ...
   end
[–] kenferry 2 hours ago
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!
[–] krackers 2 hours ago
Oh I remember this from the classic SO post, but it was just presented as a funny trick. I never realized that it solves the issue mentioned in the article and there is a legitimate use-case for post-decrement in the comparison itself.

https://stackoverflow.com/questions/1642028/what-is-the-oper...

[–] cryptonector 48 minutes ago
It's a well-known (ish) idiom that nobody uses. It's very entertaining though, for sure. In some circles it's known as the down-to operator.
[–] viega 1 hour ago
I always use unsigned values and do:

  while (i-- != 0) { ... }
It's more clear than the most idiomatic way, which is to drop the explicit comparison:

  while (i--) { ... }
 
All of it is better than the clunky old for-loop syntax.
[–] chii 40 minutes ago
if `i` ever gets modified inside the loop, and skips 0 (e.g., got decremented twice when it is at 1), then you might end up with an infinite loop?

Usually, this won't happen of course, but because `i` is not declared inside a for-loop, it must have been declared outside, and thus might even look like a regular variable that could be used by some "clever" coding to multipurpose it!

In any case, it's a niche worry i have, so i usually don't do it if i know there's a for loop that would do.

[–] mtklein 1 hour ago
I don't think it's too clever at all. Notably it works with both signed and unsigned i. Frankly if I see anyone doing anything other than this, they're wrong.
[–] stephencanon 2 hours ago
Always.

(Hi Ken!)

[–] kooi 24 minutes ago
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]

}
[–] bugake 56 minutes ago
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.

[–] randomblock1 30 minutes ago
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.
[–] seeknotfind 13 minutes ago
Yes, this is the best answer. This also works with `-fsanitize=unsigned-integer-overflow`.
[–] AdieuToLogic 1 hour ago
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;
  }
[–] i2talics 42 minutes ago
Most compilers will be able to optimize the index version into this.
[–] MaulingMonkey 2 hours ago
I prefer:

    const size_t n = 10;
    for (size_t i = n; i --> 0;) {
        std::cout << i << "\n";
    }
[–] hedgehog 2 hours ago
That's a certain kind of taste... I checked out your home page, game dev, check, and this work of art is worth linking (no irony, I love it):

http://maulingmonkey.com/brainfuck/

[–] omoikane 1 hour ago
That looks like the brainfuck mandelbrot set by Erik Bosman, but the example is missing the header line with the credit. The one I saw came from here:

https://github.com/thaliaarchi/bfcorpus/blob/main/ebosman/ma...

Be sure to check out other files in that directory for how the program is assembled.

(Erik Bosman's mandelbrot set is a personal favorite of mine, very useful for benchmarking brainfuck interpreters)

[–] ranger_danger 2 hours ago
Cute but wouldn't work with ssize_t :)

VHDL's array/vector syntax actually works a similar way:

-- gives 0, 1, 2, 3:

for i in 0 to 3 loop

-- gives 3, 2, 1, 0:

for i in 3 downto 0 loop

-- Source - https://stackoverflow.com/a/7642026 -- Posted by Kerrek SB -- Retrieved 2026-10-29, License - CC BY-SA 3.0

[–] fourthark 1 hour ago
Does work with ssize_t, just not necessary.
[–] ranger_danger 1 hour ago
Depends on your definition of "work".

For me it does not work because I'd want to use it with values < 0, but the for loop checks for > 0, so I would have to modify that first.

[–] abstractspoon 2 days ago
I've been using this method for more than 30 years!