Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initialization from incompatible pointer type warning when assigning to a pointer

Tags:

arrays

c

pointers

GCC gives me an 'Initialization from incompatible pointer type' warning when I use this code (though the code works fine and does what it's supposed to do, which is print all the elements of the array).

#include <stdio.h>

int main(void)
{
    int arr[5] = {3, 0, 3, 4, 1};
    int *p = &arr;

    printf("%p\n%p\n\n", p);

    for (int a = 0; a < 5; a++)
        printf("%d ", *(p++));
    printf("\n");
}

However no warning is given when I use this bit of code

int main(void)
{
    int arr[5] = {3, 0, 3, 4, 1};
    int *q = arr;

    printf("%p\n%p\n\n", q);

    for (int a = 0; a < 5; a++)
        printf("%d ", *(q++));
    printf("\n");
}

The only difference between these two snippets is that I assign *p = &arr and *q = arr .

  • Exactly what different is the & making ?
  • And why does the code execute and give the exact same output in both the cases ?
like image 233
Nathu Avatar asked Jun 13 '17 14:06

Nathu


2 Answers

  • &arr gives an array pointer, a special pointer type int(*)[5] which points at the array as whole.
  • arr, when written in an expression such a int *q = arr;, "decays" into a pointer to the first element. Completely equivalent to int *q = &arr[0];

In the first case you try to assign a int(*)[5] to a int*. These are incompatible pointer types, hence the compiler diagnostic message.

As it turns out, the array pointer and the int pointer to the first element will very likely have the same representation and the same address internally. This is why the first example "works" even though it is not correct C.

like image 89
Lundin Avatar answered Sep 17 '22 07:09

Lundin


TL;DR Check the types.

  • &arr is of type int (*) [5] (pointer to an array of 5 ints).
  • arr is of type int [5], but not always.

Quoting C11, chapter §6.3.2.1, (emphasis mine)

Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue.

hence,

 int *q = arr;   // int[5] decays to int *, == LHS

and

 int *q = &arr[0];   // RHS == LHS

are same, whereas,

 int *q = &arr; // LHS (int *) != RHS (int (*) [5])

is a mismatched type expression.

Now, it works, because, as already mentioned in Lundin's answer, the address of the array variable is likely to be the same as the address of the first element of the array, so despite the type mismatch, the value is same, so this seems to work.

like image 25
Sourav Ghosh Avatar answered Sep 20 '22 07:09

Sourav Ghosh