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].

12
  • 1
    char* [2][2] is not char***, but char**. You should not need a cast to get a pointer to it. Commented Jul 19, 2024 at 19:26
  • 4
    @IS4 char* [2][2] is not char**, not even close. Commented Jul 19, 2024 at 19:28
  • 1
    char*** b means "b is a pointer to a pointer to a pointer to a char". Let's look at that thing which b points to. It must be a pointer to a pointer to a char. Can you show me such a thing in your program? Commented Jul 19, 2024 at 19:31
  • 2
    @5reep4thy Read this: Correctly allocating multi-dimensional arrays It has a good explanation of the difference. TLDR: a char *** pointer never refers to a "3D array" no matter what you've been told. Commented Jul 19, 2024 at 19:34
  • 2
    Don't be a 3-star programmer: try 2 stars: ideone.com/uboLN0 Commented Jul 19, 2024 at 19:41

3 Answers 3

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]);
}
Sign up to request clarification or add additional context in comments.

1 Comment

Interesting that there are no casts when the conversions actually work.
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.

1 Comment

Gives clarity on a lot of my misconceptions :)
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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.