-5
void f(int **);
void g(int *[]);
void h(int *[3]);
void i(int (*)[]);
void j(int (*)[3]);
void k(int [][3]);

void f(int **a) {}
void g(int *a[]) {}
void h(int *a[3]) {}
void i(int (*a)[]) {}
void j(int (*a)[3]) {}
void k(int a[][3]) {}

int main(void) {
    int a[3] = {1,2,3};
    int b[2] = {4,5};
    int *c[2] = {a, b};
    int d[2][3] = {{1,2,3},{4,5,6}};
    f(c);
    f(d); // note: expected ‘int **’ but argument is of type ‘int (*)[3]’
    g(c);
    g(d); // note: expected ‘int **’ but argument is of type ‘int (*)[3]’
    h(c);
    h(d); // note: expected ‘int **’ but argument is of type ‘int (*)[3]’
    i(c); // note: expected ‘int (*)[]’ but argument is of type ‘int **’
    i(d);
    j(c); // note: expected ‘int (*)[3]’ but argument is of type ‘int **’
    j(d);
    k(c); // note: expected ‘int (*)[3]’ but argument is of type ‘int **’
    k(d);
    return 0;
}

What is the difference in these C function argument type? There're a lot of confusing between arrays of pointers and two dimensional arrays The comments are the GCC warning logs.

Tom Jerry
  • 307
  • 2
  • 10
  • `int **` is a pointer to pointer to `int`. `int (*)[3]` is pointer to array of `int`. Both are different and not interchangable. – ameyCU Apr 24 '17 at 14:08
  • 1
    see [cdecl.org](https://cdecl.org/?q=void+i%28int+%28*%29%5B%5D%29%3Bhttps://cdecl.org/?q=void+i%28int+%28*%29%5B%5D%29%3B) – Garf365 Apr 24 '17 at 14:08
  • 2
    Possible duplicate of [C pointer to array/array of pointers disambiguation](http://stackoverflow.com/questions/859634/c-pointer-to-array-array-of-pointers-disambiguation) – Werner Henze Apr 24 '17 at 14:12
  • @WernerHenze It's not duplicated, but I haven't noticed the **Operator precedence**, it's much more easier to understand these odd declaration. – Tom Jerry Apr 24 '17 at 14:54

1 Answers1

1

First, lets sort out which declarations are actually equivalent, because there is a lot of redundancy in your example code.

For instance, these three declarations all mean exactly the same thing to the compiler:

void f(int **a) {}
void g(int *a[]) {}
void h(int *a[3]) {}

Any array typed function argument decays to a pointer to the first element of the array, so int **a is the type that's actually used for all three function arguments.

Likewise, these two declarations are identical:

void j(int (*a)[3]) {}
void k(int a[][3]) {}

Here, the effective type of the argument is int (*a)[3].


That leaves you with only three different variants:

void f(int **a) {}
void i(int (*a)[]) {}
void j(int (*a)[3]) {}

The first one is a pointer to a pointer to an int. This is often used to pass a 2D array as a pointer to an array of pointers to line arrays. The indexing works fine, but it requires the additional pointer array to be set up correctly.

The second is pretty much unusable: It defines a pointer to an array, of which the size is not known. As such, you cannot index into the array with a[y][x], because the size of the lines is not known, so the offset of the line y cannot be calculated.

The last one passes a 2D array with a width of three ints. You can easily index into it with a[y][x] because when you say a[y] the compiler knows that the lines are arrays of three integers, and will calculate the offset accordingly.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106