C

In C, negative array indexing is useful when used in conjunction with some pointer into the array.

Unlike Pascal, C arrays always start at index 0. This is a Good Thing. Except that sometimes it isn't.

Say we want to translate the 8 directions


1 2 3
8 0 4
7 6 5

from their offsets in X and Y to the direction number. That is, we want to translate (-1,-1) to 7, (+1,-1) to 5, (0,+1) to 2 and so on. "if"s are slow; we want to use data directed programming to do the translation by lookup.

We'll use a nice array (note that the Y coordinate increases from bottom up in mathematics, but from top down in programming -- so we've reversed the order of the rows):

int to_dir[3][3] = {
  { 7, 6, 5 },
  { 8, 0, 4 },
  { 1, 2, 3 }
};

To determine the direction number of (dx,dy), we need to lookup to_dir[dy+1][dx+1]. This is ugly and error-prone: it is quite hard to forget we need to add all those 1's.

Here's a better way to do it. Add the definition

int (*dir)[3] = (int(*)[3])&to_dir[1][1];
to the code. Yes, it's ugly. But the typecast is needed for good cause: we're trying to reassign a pointer to arrays of 3 ints into the middle of an array of arrays of 3 ints, rather than to the beginning of a row!

Now use dir[-1][-1], and its friends dir[i][j] with -1≤i,j≤+1 to access the directions. No possibility of forgetting to add 1's -- it's already there inside dir. For added safety, you'd probably prevent access to to_dir by giving it minimal scope, and exporting only dir.

Perl and others

In Perl and others (like Python)too, negative array indexing is not wasted. Perl doesn't have pointer arithmetic (mostly because it doesn't have pointers). Instead, negative indices are counted from the array's end: $ARGV[-1] is the last command line argument.

This almost (but not quite) parallels the behaviour of many UN*X utilities, of course. For instance, vi's "G" command goes to the line given as argument. So "123G" goes to line 123. Line 0 is the last (not first!) line, and is the default; just "G" goes to the last line. And negative line numbers go to lines counted down from the last line.

ISO C++ with generic programming and Gorgonzola cheese

Below, gorgonzola demonstrates how beautifully C++ lets you build array-like classes that allow various forms of negative array indexing. As with everything else in the language, you can do it. The code is incredibly long-winded, but C++ programmers are used to that.

Superficially, prime fodder for exhibition in the C++ Programming Language Freakshow (tm), ariels Esq. (prop.). But in actual fact, it's too simple. After all, the code is only for 1-dimensional arrays. We're interested in doing the same for multi-dimensional matrices. This, I'm sure, will require just a little more code.