Bite Bytes
Bite Bytes

Reputation: 1513

Iterating an array backward in C using an unsigned index

Is the following code, safe to iterate an array backward?

for (size_t s = array_size - 1; s != -1;  s--)
    array[s] = <do something>;

Note that I'm comparing s, which is unsigned, against -1;

Is there a better way?

Upvotes: 1

Views: 157

Answers (3)

0___________
0___________

Reputation: 67546

IMO in the iterations use large enough signed value. It ss easier to read by humans.

Upvotes: 0

melpomene
melpomene

Reputation: 85767

This code is surprisingly tricky. If my reading of the C standard is correct, then your code is safe if size_t is at least as big as int. This is normally the case because size_t is usually implemented as something like unsigned long int.

In this case -1 is converted to size_t (the type of s). -1 can't be represented by an unsigned type, so we apply modulo arithmetic to bring it in range. This gives us SIZE_MAX (the largest possible value of type size_t). Similarly, decrementing s when it is 0 is done modulo SIZE_MAX+1, which also results in SIZE_MAX. Therefore your loop ends exactly where you want it to end, after processing the s = 0 case.

On the other hand, if size_t were something like unsigned short (and int bigger than short), then int could represent all possible size_t values and s would be converted to int. In other words, the comparison would be done as (int)SIZE_MAX != -1, which would always return false, thus breaking your code. But I've never seen a system where this could happen.


You can avoid any potential problems by using SIZE_MAX (which is provided by <stdint.h>) instead of -1:

for (size_t s = array_size - 1; s != SIZE_MAX;  s--)
    ...

But my favorite solution is this:

for (size_t s = array_size; s--; )
    ...

Upvotes: 3

Felix Guo
Felix Guo

Reputation: 2708

Well, s will never be -1, so your ending condition will never happen. s will go from 0 to SIZE_MAX, at which point your program will probably segfault from a memory access error. The better solution would be to start at the max size, and subtract one from everywhere you use it:

for (size_t s = array_size; s > 0; s--)
    array[s-1] = <do something>;

Or you can combine this functionality into the for loop's syntax:

for (size_t s = array_size; s--;)
    array[s] = <do something>;

Which will subtract one before going into the loop, but checks for s == 0 before subtracting 1.

Upvotes: 0

Related Questions