https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93848
--- Comment #8 from Martin Sebor <msebor at gcc dot gnu.org> --- In int i[4]; int (*p)[4] = &i; bar_aux (p[1]); p[0] points to i and p[1] to (char*)&i + sizeof (i) (which is the same as &i[4]). The latter is a pointer just past the end of i. Evaluating past-the-end pointers is well-defined, as is all pointer arithmetic on them, just as long as the result is also a valid pointer to the same object (or just past its end). The only way past-the-end pointers differ from others is that the former cannot be dereferenced (by any means, either the * operator, or [] or ->). In int a[1][4]; printf("%p\n", (void *)&a[1][1]); on the other hand, the reference to a[1][1] is undefined because a[1] is not a reference to an element in a but rather just past the end of a, and so it can be neither dereferenced nor used to obtain pointers other than to a or just past it. &a[1] alone is valid (it's equivalent to (char*)&a + sizeof a) and points just past the end of a, but &a[1][1] is equivalent to (char*)&a + sizeof a + 1 which is not valid.