1

Fragment 1:

char** x;
char arr[][4] = {"abc","def"};
x = arr;                             // why is this wrong ? but;

Fragment 2:

char* x;
char arr[4] = {"def"};
x = arr;                             // this is correct

So how can we assign 2d array to a double pointer (also for any multidimensional arrays)?

Also, I have a struct and I want to make an assignment as follows:

struct document
{
    char **text;
    int numOfLines;
};

char arr[3][50] = {
    "IF WE COULD TAKE THE TIME",
    "TO LAY IT ON THE LINE",
    "I COULD REST MY HEAD" };
t->text = arr;                           // I think it is the same problem

but can we directly assign a double pointer as:

t->text = { "IF WE COULD TAKE THE TIME", "TO LAY IT ON THE LINE", "I COULD REST MY HEAD" };

Also why does this work:

char *arr[3] = {
    "IF WE COULD TAKE THE TIME",
    "TO LAY IT ON THE LINE",
    "I COULD REST MY HEAD" };
t->text = arr;
Jonathan Leffler
  • 666,971
  • 126
  • 813
  • 1,185
  • 4
    In the first fragment, `arr` has the type `char (*)[4]` — pointer to an array of 4 characters — which is quite different from `char **`, which is why the compiler complains about the assignment. – Jonathan Leffler Dec 28 '18 at 08:34
  • A C array is several objects in consecutive memory locations. So a two-dimensional array is several one-dimensional arrays in consecutive memory locations. It just *isn't* a pointer to a pointer. – David Schwartz Dec 28 '18 at 08:35
  • possible duplicate [link](https://stackoverflow.com/questions/8767166/passing-a-2d-array-to-a-c-function) – Duck Dodgers Dec 28 '18 at 08:35
  • Does the `t->text = { …three string literals… };` fragment compile? It shouldn't. You'd need to use the compound literal notation: `t->text = (char *[]){ …three string literals… };`. – Jonathan Leffler Dec 28 '18 at 08:42
  • it is wrong ,but the last part is correct – floriferous Dec 28 '18 at 08:43
  • how can we assign 2d array to a double pointer? – floriferous Dec 28 '18 at 08:46
  • You can't (assign a 2D array to a pointer to pointer) — they are not compatible types. – Jonathan Leffler Dec 28 '18 at 09:03

2 Answers2

3

Statement char **x; means pointer to pointer, but char arr[][4]; is somehow pointer to array. Code below works.

#include <stdio.h>

int main(void)
{   
    char (*x)[10];
    char arr1[][10] = {{"First"}, {"Second"}};
    x = arr1;
    printf("%s\n%s\n", arr1[0], arr1[1]);
    printf("%s\n%s\n", x[0], x[1]);
    return 0;
}
Kolkil Kolk
  • 146
  • 1
  • 9
  • Are declarations of char (*x)[10]; and char arr1[][10]; are equivalent? – floriferous Dec 29 '18 at 17:45
  • You cannot static allocate various size array, `char arr[][4] = {{"abc"}, {"cba"}};` is translated to `char arr[2][4] = {{"abc"}, {"cba"}};`, but `char (*x)[4];` (because it is pointer) can be assigned to every array with unknown first dimension. – Kolkil Kolk Dec 30 '18 at 16:56
1

Question 1

char arr[][4] = {"abc","def"}; defines arr to be an array of arrays. With other objects, such as a structure, one structure, say C, could be assigned to another structure, say B, of the same type, using B = C;. However, C has special rules for arrays.

When an array is used in an expression, it is automatically converted to a pointer to its first element, except when it is the operand of sizeof or unary & or is a string literal used to initialize an array. So, when we write:

x = arr;

the automatic conversion makes it as if we had written:

x = &arr[0];

Then, since &arr[0] is a pointer to an array of 4 char, x must also be a pointer to an array of 4 char (or something compatible, perhaps a pointer to an array of an unknown number of char).

Note that char **x; declares a pointer to a pointer. That is, it is a pointer, and, at the memory it points to, there must be another pointer. In contrast, &arr[0] is a pointer to an array. It is a pointer, and, at the memory it points to, there is an array of 4 char. If you tried to use **x, the compiler would look at the memory that x points to and expect to find a pointer there. If, instead, there is not a pointer but rather four arbitrary char values, the program would be broken. So char **x is not compatible with a pointer to an array of 4 char.

A proper declaration for x would be char (*x)[4];. After such a declaration, the assignment x = arr; would be proper.

Question 2

Your code t->text = { "IF WE COULD TAKE THE TIME", "TO LAY IT ON THE LINE", "I COULD REST MY HEAD" }; is not strictly conforming C and does not compile in typical compilers.

Question 3

Consider the code (adjusted to allow compilation):

struct document
{
    char **text;
    int numOfLines;
} t;

char *arr[3] = {
    "IF WE COULD TAKE THE TIME",
    "TO LAY IT ON THE LINE",
    "I COULD REST MY HEAD" };
t.text = arr;

char *arr[3] declares arr to be an array of 3 pointers to char. It is then initialized to contain three pointers to (the first characters of) strings.

So each element of arr, arr[i] is a pointer to char. By C’s rule about automatic conversion of arrays, in t.text = arr;, arr is converted to a pointer to its first element. So we have t.text = &arr[0];. Then &arr[0] is a pointer to a pointer to a char, and t.text is a pointer to a pointer to a char, so the types are compatible.

Eric Postpischil
  • 141,624
  • 10
  • 138
  • 247