A Trick You May Not Know And You Shouldn't Even Use
In this dev tip, we talk about a trick that most likely you don’t know and which is now more than anything else a legacy of the forerunners of the C language, who used this trick to simplify compilers. Let’s see what it is.
In C we can access the i-th element of an x array by either writing x[i] or writing i[x].
For example, if we want to set the third element of the x array to zero, the following two lines of code are exactly equivalent.
x[2] = 0;
2[x] = 0;
Are you surprised? This kind of notation is hardly ever seen these days, so you have every right to be surprised.
In reality, this exchange between index and array is motivated by a straightforward mathematical rule. In C, writing x[i] is the same to dereferencing the pointer x by adding an offset equal to i, that is:
*(x + i)
We can always add together an integer and a pointer (which is nothing more than an address), while we can never add two pointers together (it would make no sense). Simply pointers arithmetic. So, for the sum’s commutative property, we can also write *(i + x). And since the very first compilers, which were very rudimentary, did nothing but replacing x[i] with *(x + i), we immediately understand why we can swap index and array!
Back to nowadays
Adding a rule to the C standard that prevents the array index and identifier from being swapped could cause incompatibility with old codebases. To my mind, that’s the only reason no one has ever introduced a rule on this subject. Nowadays, swapping index and array names in 99.9% can only make the code harder to read. I think this stuff can even win the IOCC.
A fun application of this trick is nested indexing. Below is an example of what I mean. Although it is an interesting little game, likely, most of those who read the i[c][b][a] are well lost. Unless this person is like you who just read this article, of course! 😉
#include <stdio.h>
#include <stdlib.h>
int main() {
int a[] = {[3] = 33, [4] = 44, [7] = 77, [8] = 88, [9] = 99};
int b[] = {3, 4, 7, 8, 9}; /* a[b[i]] selects 33, 44, 77, 88, 99 */
int c[] = {1, 2, 4}; /* a[b[c[i]]] selects 44, 77, 99 */
for (int i = 0; i < sizeof(c) / sizeof(c[0]); i++) {
printf("a[b[c[%d]]] = %d[c][b][a] = %d\n", i, i, i[c][b][a]);
}
}
Output:
a[b[c[0]]] = 0[c][b][a] = 44
a[b[c[1]]] = 1[c][b][a] = 77
a[b[c[2]]] = 2[c][b][a] = 99