List1
is an array of two arrays of 10 const char
. So &List1
is a pointer to an array of two arrays of 10 char
. If var_name
is an array of those, it is an array of pointers to an array of two arrays of 10 const char
. You can build a declaration for that piece by piece:
var_name
is an array…: var_name[]
.
- … of pointers:
*var_name[]
.
- …to an array of two…:
(*var_name[])[2]
.
- …arrays of 10…:
(*var_name[])[2][10]
.
- …
const char
: const char (*var_name[])[2][10]
.
Then you can define and initialize it:
char (*var_name[])[2][10] = { &List1, &List2, &List3, &List4};
"Book"
is in element 1 of List3
, which is in element 2 of var_name
, so you can refer to it with (*var_name[2])[1]
.
Note that this requires the *
, because var_name[i]
is a pointer. This follows the sample code you gave where the array is initialized with &List1
. It is more common to use a pointer to the first element of an array instead of a pointer to the array. (The addresses in memory are the same, but the types are different.)
Suppopse we want to eliminate this unnecessary pointer level and initialize var_name
with { List1, List2, List3, List4 }
. As usual in C, those arrays will be automatically converted to pointers to their first elements. The first element of each of those arrays is an array of 10 const char
. So we will be initializing var_name
with pointers to arrays of 10 const char
.
Thus, var_name
will be an array of pointers to arrays of 10 const char
. Again, we can build the declaration piece by piece:
var_name
is an array…: var_name[]
.
- … of pointers…:
*var_name[]
.
- … to arrays of 10…:
(*var_name[])[10]
.
- …
const char
…: const char (*var_name[])[10]
.
Then the definition and initialization is:
const char (*var_name[])[10] = { List1, List2, List3, List4 };
Now the elements of List3
are pointed to by var_name[2]
, so we can refer to "Book"
with var_name[2][1]
.