arrayscpointerscompilationdouble-pointer

Difference Between declaration of 2D array and pointer


Consider this C program

int main()
{
    int arr[][3] = {1,2,3,4,5,6};
    int **p= &arr;
    printf("%u %u" , *p, *(p+1));

    return 0;
}

Some compilers are giving output as 1,4 some compilers are giving type compatible error

According to me We need double dereference in order to get value right, and if we have a 2D array then Wouldn't the double pointer will point to its first element, then why we are getting type compatible error and why referencing only once giving array elements?


Solution

  • Given ...

        int arr[][3] = {1,2,3,4,5,6};
    

    ... the type of &arr is int (*)[2][3]. This is neither the same as nor compatible with int **. You can convert a value of the former type to a value of the latter type, but the language spec requires an explicit cast for that.

    Some compilers are giving output as 1,4 some compilers are giving type compatible error

    Some compilers evidently provide an extension by performing that conversion implicitly, and some are doing you a better favor by pointing out your error. Those that perform the implicit conversion are not serving you well. Given ...

    int **p = &arr;
    

    , *p has type int *, but what p actually points to is an array of arrays. Arrays are not pointers, and you don't get array decay here because that's a function of expression type. There is no array type among the types of p, *p, and **p. If you evaluate *p then you violate the strict aliasing rule, and in practice, you likely attempt to interpret the first several bytes of arr as a pointer. That's likely to be those either of the 1 alone or of the 1 and 2 together.

    According to me We need double dereference in order to get value right,

    Yes and no. Arrays are not pointers, but they are automatically converted to pointers to their first elements in most expressions. To get an individual int from your 2D array, you need a combination of array-to-pointer conversions, pointer arithmetic, and, yes, two dereferences. But the dereferences alone don't do it.

    and if we have a 2D array then Wouldn't the double pointer will point to its first element, then why we are getting type compatible error and why referencing only once giving array element?

    By attempting to access via the wrong pointer type, you prevent some of those things from happening correctly. This is a violation of the strict aliasing rule, and, as far as C is concerned, anything can happen.

    You probably wanted this:

        int (*p)[3] = arr;
    

    Note both the change to the type of p (it is now a pointer to an array of 3 int), and the omission of the & operator. The new type of p is the correct pointer type to which arr decays, so there is no conversion required. As long as p holds this value, you can use its name interchangeably with arr for most (but not all) purposes within their joint scope.

    In particular, if you say *p then the result is in array, subject to decay to a pointer, so you can also do **p to get the 1.