Search code examples
carraysdereference

Confusion about dereference operator ("*") in C


As far as I know, the derefence operator * returns the value stored in the pointer address. What I'm confused by is the behavior when the operator is used with pointer of an array. For example,

int a[4][2];

Then a is internally converted to pointer of first element of array of 4 elements of 2 ints. Then which value does *a return? I'm really confused!


Solution

  • This:

    int a[4][2];
    

    defined a an array of 4 elements, each of which is an array of 2 int elements. (A 2-dimensional array is nothing more or less than an array of arrays.)

    An array expression is, in most contexts, implicitly converted to a pointer to the array object's initial (zeroth) element. (Note the assumption that there is an array object; that has caused some angst, but it's not relevant here.)

    The cases where an array expression is not converted to a pointer are:

    • When it's the operand of sizeof;
    • When it's the operand of unary &; and
    • When it's a string literal in an initializer used to initialize an array object.

    (Compiler-specific extensions like gcc's typeof might create more exceptions.)

    So in the expression *a, the subexpression a (which is of type int[4][2]) is implicitly converted to a pointer of type int(*)[2] (pointer to array of 2 ints). Applying unary * dereferences that pointer, giving us an expression of type int[2].

    But we're not quite done yet. *a is also an expression of array type, which means that, depending on how it's used, it will probably be converted again to a pointer, this time of type int*.

    If we write sizeof *a, the subexpression a is converted from int[4][2] to int(*)[2], but the subexpression *a is not converted from int[2] to int*, so the expression yields the size of the type int[2].

    If we write **a, the conversion does occur. *a is of type int[2], which is converted to int*; dereferencing that yields an expression of type int.

    Note that despite the fact that we can legally refer to **a, using two pointer dereference operations, there are no pointer objects. a is an array object, consisting entirely of 8 int objects. The implicit conversions yield pointer values.

    The implicit array-to-pointer conversion rules are in N1570 section 6.3.2.1 paragraph 3. (That paragraph incorrectly gives _Alignof as a fourth exception, but _Alignof cannot be applied to an expression. The published C11 standard corrected the error.)

    Recommended reading: Section 6 of the comp.lang.c FAQ.