Skip to content
HN On Hacker News ↗

Iterating Backwards in C

▲ 108 points • 76 comments • by cremno • 1w ago • HN discussion ↗

Pangram verdict · v3.3

We believe that this entire text is human-written.

0 %

AI likelihood · overall

Human
100% human-written 0% AI-generated
SEGMENTS · HUMAN 1 of 1
SEGMENTS · AI 0 of 1
WORD COUNT 435
PEAK AI % 0% · §1
Analyzed
Oct 30
backend: pangram/v3.3
Segments scanned
1 windows
avg 435 words each
Distribution
100 / 0%
human / AI fraction
Verdict
Human
Pangram v3.3

Article text · 435 words · 1 segments analyzed

Human AI-generated
§1 Human · 0%

This is shorter than some of my other posts, but I keep seeing people doing this wrong. It's even worse now in the LLM era. Let's say you have a buffer and a counter and you need to iterate it backwards for some reason: _Bool find_last(size_t count, int *haystack, int needle, size_t *where); Almost everyone can do the forward version on autopilot: for(size_t i = 0; i < count; i++){ if(haystack[i] == needle){ *where = i; return 1; } } return 0; So they try to do the same thing, just iterating backwards: for(size_t i = count - 1; i >= 0; i--){ } But that doesn't work at all! i >=0 is tautologically true (modern compilers will warn). Even worse, if count is 0, i immediately becomes SIZE_MAX. Ok, so they try the next version: for(ssize_t i = count - 1; i >= 0; i--){ } This works in practice with a signed index but introduces some problems: Now your index variable is signed, which can cause problems when used in expressions due to C's conversion rules. ssize_t is a POSIX thing so you'd have to define it yourself on windows. If your type is 32 bit, you run into promotion problems and might even run into truncation problems. This spelling of the loop is overcomplicated and requires special inspection each time. Did you get the second-clause condition right? Avoiding these problems brings us to the actual, proper way to iterate backwards in C: for(size_t i = count; i--; ){ } So much simpler! Let's break it down: The key is the postdecrement operator on i. It decrements i but yields the value that i was before the operation. In this case, this means that in the body of the loop i is always in bounds as its value will be decremented after initialization so it is at most count - 1, while the condition checks that if it was previously 0 then the loop ends. i will wrap around, but unsigned wrap-around is well defined in C so that is not a problem. The final version: _Bool find_last(size_t count, int *haystack, int needle, size_t *where){ for(size_t i = count; i--; ){ if(haystack[i] == needle){ *where = i; return 1; } } return 0; } Doing it this way means you don't have to mess around with converting to a signed loop index and look at how simple that loop is! You can tell at a glance if someone has implemented the reverse loop properly or not. So please! If you see someone trying to iterate backwards, show them this way to do it!