At first let's consider how the subscript operator works with the array declared like:
char* a[2][2] = {{"123", "456"}, {"234", "567"}};
The expression a[0]
yields one-dimensional array {"123", "456"}
of the type char* [2]
.
That is, in this expression a[0]
, the array designator a
is implicitly converted to a pointer to its first element of the type char* (*)[2]
. Let denote it like p
. And the source expression is evaluated like *(p + 0)
, that is like *(char* (*)[2] + 0)
that is the same as *(char* (*)[2])
and in turn is the same as char* [2]
.
Using one more subscript operator to the obtained one-dimensional array (the first element of the original two-dimensional array), we will get an object of the type char*
.
Now, let consider the subscript operator with the pointer b
declared like:
char*** b = (char***) a;
The pointer points to the extent of memory occupied by the array a
where there is stored a pointer to the element of the array a
"123"
. That is, at this address there is stored an object of the type char*
that points to the first character of the string literal "123".
In this case, the expression b[0]
gets the value of this pointer, and applying one more subscript operator to this value, you will get the character '1'
of the string literal. This value '1'
is used as a pointer in this call of printf
:
printf("%s", b[0][0]);
Which results in undefined behavior. That is, this call with the conversion specification %s
tries to access memory using the value of the character '1'
as a pointer to a valid object, which it isn't.
The main difference between using expressions with the subscript operators for the array a
and using expressions with subscript operators for the pointer b
is that for the array the memory occupied by the array is not read. Instead the same value of the address of the extent of memory occupied by the pointer to the string literal "123"
is just reinterpreted at first like char * ( * )[2]
then like char **
. While for expressions with subscript operators applied to the pointer b
values pointed to by pointer expressions char ***
and char **
are read.