Search code examples
cpointersmultidimensional-arrayimplicit-conversionc-strings

How does the notation i[array] work in C?


I haven't come across a similar notation in any other programming language, i.e., I am used to seeing the subscript within the brackets (and not the other way round). I understand how given an array foo, foo essentially is a pointer to the base address of the array; and how pointer notations correlate to array notations, i.e. I get the rationale behind why foo[i], *(foo + i), *(i + foo) are all equivalent... But I don't understand the rationale behind how i[foo] is also equivalent to the three mentioned above, or how it works. Maybe rephrasing this notation in English will help, but I don't see how to do that.


Solution

  • According to the C Standard (6.5.2.1 Array subscripting)

    2 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).

    So due to the commutative nature of the operation + you can write

    a[i]
    

    as either

    *( a + i )
    

    or like

    i[a]
    

    Let's consider the following declaration of a multi-dimensional array

    char * a[][2] =
    {
        { { "Hello" }, { "World" } },
        { { "Hi" }, { "everybody" } }
    };
    

    To access the letter 'v' of the string literal "everybody" you can write en expression

    a[1][1][1]    
    

    that is calculated like

    *( *( *( a + 1 ) + 1 ) + 1 )
    

    The expression can be rewritten like

    *( 1 + *( 1 + *( 1 + a ) ) )
    

    that in turn can be rewritten like

    1[1[1[a]]]
    

    Here is a demonstrative program

    #include <stdio.h>
    
    int main( void )
    {
        char *a[][2] =
        {
            { { "Hello" }, { "World" } },
            { { "Hi" }, { "everybody" } }
        };
    
        printf( "%c\t%c\n", a[1][1][1], *( *( *( a + 1 ) + 1 ) + 1 ) );
        printf( "%c\t%c\n", *( 1 + *( 1 + *( 1 + a ) ) ), 1[1[1[a]]] );
    
    }
    

    Its output is

    v       v
    v       v