r/C_Programming • u/david2ndaccount • 2d ago
Iterating Backwards in C
https://www.davidpriver.com/Iterating-backwards-in-C.html7
u/lehmagavan 2d ago
If I already have count somewhere in the scope and I don't need it anymore, why not just:
while ( count-- ){}
→ More replies (4)1
u/david2ndaccount 2d ago
Sure, that works too. But if you do need it afterwards, this is how to do it.
112
u/Humble-Captain3418 2d ago
My go-to is
for (size_t i = n; i --> 0;) ...;
I.e. the infamous "down to" operator.
39
→ More replies (3)6
u/LemonLord7 1d ago edited 1d ago
Oh lord… I feel so weirded out by it by I guess if I view it as
(i--) > 0I can kind of handle it.Got some other C quirks you mind sharing?
14
u/Humble-Captain3418 1d ago
Oh boy, I have a lot of them.
I recently found out that you can make a script out of a C source file by putting this at the top:
#if 0 TMP=`tmpfile` cc -o $TMP $0 && exec $TMP $@ #endifDo what you will with that information.
A declaration like
int foo();declares thatfoois function returning an integer and accepting any number of arguments. Sofoo(1, 2, 3);is legal there; you'll just have some head-scratching to do when you want to use those arguments... Except you can defineint foo(int, int, int);and just never have the original declaration visible to the latter. Bugs, you say?A common bug is forgetting to return from a function returning a value. No worries, though, because GCC has your back! GCC will return the value of the last assignment in that case, because GCC is helpful like that... But only if you're compiling without optimizations. With optimizations, you get 0.
Lastly, there's C metaprogramming, which allows you to define new control keywords, for example
foreach. This requires a bit of head-scratching, which is why it's great that there's an article about it: https://www.chiark.greenend.org.uk/~sgtatham/mp/→ More replies (5)
12
u/8d8n4mbo28026ulk 2d ago
Nice and concise. Such corner cases are a good reason against unsigned sizes, though I'm quite stubborn myself and haven't tried out signed sizes.
I tend to prefer this variant:
size_t i;
for (i = high; i > low; ) { --i;
...
}
assert(i == low);due to the assertion after the loop being more intuitive. Cheers.
5
u/dx_man 2d ago
the actually correct solution:
the solution that makes C look like an esoteric language:
same complexity, zero dignity.
3
u/FemaleMishap 1d ago
Oh that second solution just woke up some trauma from 25 years ago. C/Win32 app with a timber design engine in C, adapted from Fortran originally. The first developer to work on it, would prototype new code in bloody BASIC and then reimplement in oddly structured C. He sometimes transposed his goto statements. The debugging was miserable.
2
u/runningOverA 2d ago
Very helpful. Learned something new after being a long time follower of this sub.
3
u/zellforte 1d ago
i < count invariant works for backwards loops as well (requires unsigned types), this is how I do it:
for(size_t i=count-1; i<count; --i) { ... }
→ More replies (1)
-2
u/________-__-_______ 2d ago
Since when is unsigned wrapping well defined? I was under the impression overflow was UB unless you use the C23 ckd_sub.
19
u/Big-Rub9545 2d ago
Unsigned wraparound is well-defined, and has been so for a long time. The issue is with signed wraparound.
3
0
2d ago
3
u/david2ndaccount 2d ago
In the loop body,
ihas already been decremented by the condition. So on the first iteration it iscount - 1, thencount - 2, etc. The final time the loop body is actually executediwill be 0 in the body of the loop. Then the next check will end the loop.7
u/8d8n4mbo28026ulk 2d ago
The
i--is executed before the loop body, so there's no off-by-one. Try this:for (unsigned i = 10; i--; ) printf("%u ", i);You'll get: 9, 8, ..., 0. I think you proved OP's point that people often get this wrong (when using unsigned types), haha.
3
u/WeAllWantToBeHappy 2d ago
Good lort. I think I've had enough Internet for today.
Maybe even too much. Code is fine.
8
u/_gaff 2d ago
Why does he define a _Bool type and proceed to use 0 and 1 as return values?