Question

Converting to char*** from char* [2][2]

I have the following variable

char* a[2][2] = {{"123", "456"}, {"234", "567"}};

I wanted to refer it using another variable. While the cast works, accessing elements of b gives a segmentation fault. Eg.

char*** b = (char***) a;
printf("%s", b[0][0]); // Segmentation fault
printf("%s", a[0][0]); // "123"

I did notice that address of b and a is same, but different with indices specified. It would be helpful to understand exactly why address b[0][0] is different from a[0][0].

 2  121  2
1 Jan 1970

Solution

 5

To index char *** you have to have char ** pointers pointing to char * pointers.

char* a[2][2] has only char* pointers. The char ** pointers have to exist somewhere. You have to allocate memory for char ** pointers.

#include <stdio.h>
int main() {
    char* a[2][2] = {{"123", "456"}, {"234", "567"}};
    char **b[2] = {a[0], a[1]};
    char ***c = b;
    printf("%s\n", a[0][0]);
    printf("%s\n", b[0][0]);
    printf("%s\n", c[0][0]);
}
2024-07-19
KamilCuk

Solution

 4

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.

2024-07-19
Vlad from Moscow

Solution

 1

If just you want to refer to a as another variable, you could declare a pointer-to-array:

char *a[2][2] = {/* ... */}

char *(*b)[2] = a;
puts(a[0][0]);
puts(b[0][0]);

The reason why just using char *** does not work is because that expects a sort of 'array of pointers' where each element is a pointer a separate block containing the pointers to the strings.

But when you declare char *a[2][2], you have a 2 by 2 array of pointers to strings directly. Instead of having 2 pointers to 2 separate arrays of string pointer, you have 2 contiguous arrays of string pointers, one right after the other in memory.

When you index a contiguous multidimensional array, the indices are used to calculate a single address within the contiguous allocation. But when you have a pointer to pointer, each element is a pointer to a new array, so 2 dereferences are needed. The first case has one less layer of indirection.

This difference in layout is why you cannot treat multidimensional arrays as pointers to pointers. You must explicitly the declare a pointer to an array, representative of the multidimensional array you are trying to index.

2024-07-19
CPlus