2

I've built a function with the header void function(int d, char*** w) if i call on it like this:

int d;
char** arr;
//some memory allocate function here
function(d, &arr);

i have no problem, but like this:

int d;
char arr[d][d];
function(d,%arr);

i get this error message: passing argument 2 of (function) from incompatible pointer type what's the difference? i learned that they're supposed to be the same type the only difference is that the arr[d][d] declaration has a set continuous part of the memory to work with

Ella
  • 41
  • 2
  • 1
    With `char **arr` passing arr gives you a pointer to a pointer. With `char arr[d][d]` passing arr gives you a pointer to a char array. – stark May 27 '22 at 13:25

2 Answers2

2

In most contexts, an array will decay to a pointer to its first member. However, this does not extend past the first dimension of a multidimensional array.

This means that an array of type char [d][d] decays to a pointer of type char (*)[d], not char **. These types are incompatible.

If you define your function like this:

void function(int d, char arr[][d])

Then it can accept an array of type char [d][d].

dbush
  • 205,898
  • 23
  • 218
  • 273
  • Wait, is it actually legal to have `arr`'s second dimension sized in terms of the runtime argument `d`? Did I miss some change in the C standard, or have I misunderstood the rules for multidimensional array arguments all this time? I could've sworn the second and subsequent dimensions had to be compile-time constants, but I'll admit to not doing much with them (partially because I thought they were so limited). – ShadowRanger May 27 '22 at 13:30
  • @ShadowRanger Yes, this is how you can pass a VLA to a function. A declaration would look like this: `void function(int, char arr[][*]);` – dbush May 27 '22 at 13:34
  • @ShadowRanger C11 6.7.6.3p20-21 give examples. – dbush May 27 '22 at 13:35
  • 1
    [TIL](https://stackoverflow.com/q/53795107/364696). I guess back when I learned C, C99 was new enough that the full scope of VLA usage wasn't included in my books and classes, and since pre-C99 multidimensional array arguments were so limited, I just always coded the workaround code (accept single-dimension array, index with `row * numcols + col`) and never learned I had other options. – ShadowRanger May 27 '22 at 13:36
2

If you have a one-dimensional array like

int a[] = {1, 2, 3};

it looks like this in memory:

    +---+---+---+
 a: | 1 | 2 | 3 |
    +---+---+---+

And if you then have a pointer to the array's first element:

int *ip = &a[0];

you get something that, by the rules of pointer arithmetic in C, works just about exactly like the array:

    +---+---+---+
 a: | 1 | 2 | 3 |
    +---+---+---+
      ^
      |
    +-|-+
ip: | * |
    +---+

But a two-dimensional array looks like this:

int a2[2][3] = { { 1, 2, 3 } , { 4, 5, 6 } };

    +---+---+---+---+---+---+
a2: | 1 | 2 | 3 | 4 | 5 | 6 |
    +---+---+---+---+---+---+

Or we could draw it like this:

    +---+---+---+
a2: | 1 | 2 | 3 |
    +---+---+---+
    | 4 | 5 | 6 |
    +---+---+---+

But the problem is that this layout is not compatible with a pointer-to-pointer. If we have

int **p2;

and if we initialize it to point to some pointers that point to some integers, it'll end up looking more like this:

    +---+
p2: | * |
    +-|-+
      |
      v
    +---+        +---+---+---+
    | *--------> |   |   |   |
    +---+        +---+---+---+
    | *-----.
    +---+    \       +---+---+---+
              `----> |   |   |   |
                     +---+---+---+

And the problem is that there's nothing in a2 for our pointer p2 to point at that'll work. Since p2 is a pointer-to-a-pointer, it needs to point to a pointer in order to work. But there's no pointer anywhere in a2's representation that can fill this role.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103