43

There is this little trick question that some interviewers like to ask for whatever reason:

int arr[] = {1, 2, 3};
2[arr] = 5; // does this line compile?
assert(arr[2] == 5); // does this assertion fail?

From what I can understand, a[b] gets converted to *(a + b) and since addition is commutative, it doesn't really matter their order, so 2[a] is really *(2 + a) and that works fine.

Is this guaranteed to work by C and/or C++'s specs?

Rohan Bari
  • 7,482
  • 3
  • 14
  • 34
NullUserException
  • 83,810
  • 28
  • 209
  • 234
  • 2
    This was mentioned in [Hidden features of C++](http://stackoverflow.com/questions/75538/hidden-features-of-c#76801). – erickb Feb 22 '11 at 02:18
  • 1
    @erickb - This question specifically asks if this is an (extremely popular) implementation fluke or if this is mandated by the standard. – Chris Lutz Feb 22 '11 at 02:21
  • In this specific case, you'll get an error about `a` being undefined (since your declaration declares `arr`, not `a`), but I think everyone understands what you're actually asking... – Chris Dodd Feb 22 '11 at 02:41
  • 2
    You can even get crazy with string pointers. "abcd"[1] is 'b'. Or for you 1["abcd"]. – Graham Perks Feb 22 '11 at 02:46

2 Answers2

40

Yes. 6.5.2.1 paragraph 1 (C99 standard) describes the arguments to the [] operator:

One of the expressions shall have type "pointer to object type", the other expression shall have integer type, and the result has type "type".

6.5.2.1 paragraph 2 (emphasis added):

A postfix expression followed by an expression in square brackets [] is a subscripted designation of an element of an array object. The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))). Because of the conversion rules that apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th element of E1 (counting from zero).

It says nothing requiring the order of the arguments to [] to be sane.

Chris Lutz
  • 73,191
  • 16
  • 130
  • 183
  • 2
    @Chris - How does this extend to multi-dimensional arrays? Can you perform the same tricks to confuse folks? (Or should I ask a new question because of row- and column- major twists?) – jww Oct 02 '14 at 22:52
  • 2
    @jww - Not exactly. You could do `3[x][2]` but you couldn't do `3[2][x]` - it would be equivalent to `*(*(3 + 2) + x)` and you'd be dereferencing the `int`eger 5, which is almost certainly bad. – Chris Lutz Oct 03 '14 at 16:42
  • Well, it names the operands E1 and E2 and then talks only about E1 being an array. Which in my book establishes an order on the arguments. – Peter - Reinstate Monica Dec 20 '20 at 17:41
33

In general 2[a] is identical to a[2] and this is guaranteed to be equivalent in both C and C++ (assuming no operator overloading), because as you meantioned it translates into *(2+a) or *(a+2), respectively. Because the plus operator is commutative, the two forms are equivalent.

Although the forms are equivalent, please for the sake of all that's holy (and future maintenance programmers), prefer the "a[2]" form over the other.

P.S., If you do get asked this at an interview, please do exact revenge on behalf of the C/C++ community and make sure that you ask the interviewer to list all trigraph sequences as a precondition to you giving your answer. Perhaps this will disenchant him/her from asking such (worthless, with regard to actually programming anything) questions in the future. In the odd event that the interviewer actually knows all nine of the trigraph sequences, you can always make another attempt to stomp them with a question about the destruction order of virtual base classes - a question that is just as mind bogglingly irrelevant for everyday programming.

Michael Goldshteyn
  • 71,784
  • 24
  • 131
  • 181
  • 4
    +1 but in C++ you can use `#define ARRAY_SIZE(a) (sizeof(a) / sizeof(0[a]))` as a macro to find an array's size that won't (and can't be made to) work for `std::vector` and types that overload the `[]` operator - which can't prevent `int *a = /*something*/; ARRAY_SIZE(a)` but can be pretty safe for anything else. (It's the only useful use of `0[a]` I've ever seen) – Chris Lutz Feb 22 '11 at 02:19
  • @Chris, I added an addendum re: operator overloading. Thanks for your contribution. – Michael Goldshteyn Feb 22 '11 at 02:20
  • 2
    In C++ you can also `template size_t ARRAYSIZE(T (&a)[N]) { return N; }` which _does_ prevent `int *a = /*something*/; ARRAYSIZE(a)`. – Logan Capaldo Feb 22 '11 at 02:30
  • @Logan Capaldo - I didn't say it was an _appropriate_ use, just that it was _a_ use. :P There may be other contexts where you wish to explicitly avoid calling a class's potential `operator[]` and only operate on variables of types `T*` and `T[]`, though this is veering quickly into the contrived example kingdom. – Chris Lutz Feb 22 '11 at 02:36
  • 1
    @Chris, I was just pointing out the other options, in case someone ran off to change all their `countof` macros ;). Yours has the advantage of working in C and C++ with no changes and gaining bonus functionality in C++. – Logan Capaldo Feb 22 '11 at 02:38
  • @Logan - I usually take a stance against C/C++ interoperability so I had actually forgotten that that was the reason someone suggested that version of the macro. – Chris Lutz Feb 22 '11 at 02:41
  • @Michael let me tell you this was one of the queston asked in written test of microsoft in our institute. – Algorithmist Feb 22 '11 at 02:41