The Weird Valid Syntax in C: Why 3[s] Is the Same as s[3]
If you spend enough time looking through C codebases or playing around with obfuscated C contests, you will eventually encounter a bizarre syntax quirk: writing array indexing upside down.
Most programmers are used to arr[i]. But in C, i[arr] is not only syntactically valid — it does the exact same thing, including allowing writes to memory.
Here is a short C program that demonstrates it in action:
#include <stdio.h>
int main(void) {
char s[] = "WGabc"; /* writable stack array — both gates open */
printf("s[3] = %c\n", s[3]); /* the normal way */
printf("3[s] = %c\n", 3[s]); /* the "backwards" way — same address */
3[s] = 'X'; /* WRITE through the backwards index */
printf("s = %s\n", s);
return 0;
}
If you compile and run this code, you get the following output:
s[3] = b
3[s] = b
s = WGaXc
At first glance, 3[s] = 'X' looks like a compiler bug or invalid syntax. Why does a number subscripted by an array variable even compile, let alone mutate memory?
The Proof: Commutativity Under the Hood
The reason 3[s] works isn’t a hack — it is a direct mathematical consequence of how the C standard defines the subscript operator [].
In C, array indexing is pure syntactic sugar for pointer arithmetic and dereferencing:
a[i] ≡ *(a + i)
When you trace the equivalence step-by-step, the load-bearing link becomes obvious:
str[0] ≡ *(str + 0) ← standard C rule: a[i] ≡ *(a + i)
*(str+0) ≡ *str ← +0 is identity
*str ≡ *(0 + str) ← addition COMMUTES: (str + 0) == (0 + str)
*(0+str) ≡ 0[str] ← standard C rule applied "backwards"
The backwards notation is the party trick; addition commutativity is the core concept.
Because addition in C pointer arithmetic is commutative, *(s + 3) and *(3 + s) evaluate to the exact same memory address. Since a[i] is defined directly as *(a + i), the compiler treats s[3] and 3[s] as completely identical operations.
Takeaway
While you definitely shouldn’t write 3[s] in production code unless you want to confuse your team during a code review, understanding why it works reinforces a fundamental truth about C: arrays decay to pointers, and subscripts are just pointer arithmetic in disguise.