lin ki
lin ki

Reputation: 39

incompatible pointer type in making 2D array struct in C

I'm trying to make 2D array struct in C like this in main function.

function_1(struct example** ex){}
void main(){
    struct example ex[num_1][num_2];
    function(ex);
}

But gcc keep telling me that type of ex and struct example** ex is different. How can I solve this error?

Upvotes: 0

Views: 112

Answers (2)

John Bode
John Bode

Reputation: 123468

A 2D array expression doesn’t decay to a pointer to pointer, it decays to a pointer to an array.

Unless it is the operand of the sizeof, _Alignof, or unary & operators, or is a string literal used initialize a character array in a declaration, an expression of type "N-element array of T" will be converted, or "decay", to an expression of type "pointer to T" and the value of the expression will be the address of the first element of the array.

In the call to function, the expression ex decays from type "num_1-element array of num_2-element array of struct example" to "pointer to num_2-element array of struct example", so your function prototype needs to be

void function( struct example (*ex)[num_2] )
{
  ...
  ex[i][j] = some_value();
  ...
}

In the context of a function parameter declaration, T a[N] and T a[] are "adjusted" to T *a, so you could also write that prototype as

void function( struct example ex[][num_2] )
{
  ...
  ex[i][j] = some_value();
  ...
}

There are a couple of problems with this - function doesn’t know how many rows are in the array, so you would need to pass that as a separate parameter:

void function( struct example (*ex)[num_2], size_t rows )
{
  ...
}

Also the function can only accept arrays with num_2 columns - it cannot work on any arbitrarily-sized 2D array.

If your function needs to handle arbitrarily-sized arrays and you have a compiler that supports variable-length arrays, you can do something like this:

void function( size_t rows, size_t cols, struct example ex[rows][cols] )
{
  ...
}

and call it from main as

function( num_1, num_2, ex );

If your compiler doesn’t support VLAs, you’ll have to get creative. One trick is to pass a pointer to the first element and treat it as a 1D array in the function:

void function( struct example *ex, size_t rows, size_t cols )
{
  ...
  ex[i * rows + j] = some_value();
  ...
}

and call it as

function( &ex[0][0], num_1, num_2 );

Note that this trick only works for 2D arrays defined as

T a[M][N];

or arrays dynamically allocated as

T (*p)[N] = malloc( sizeof *p, M );

It won’t work for 2D arrays allocated as

T **p = malloc( sizeof *p * M );
for ( size_t i = 0; i < N; i++ )
  p[i] = malloc( sizeof *p[i], N );

but in that case, your function prototype would be

void function( T **p, size_t rows, size_t cols )
{
  ...
}

As a final note, main returns int, not void. Older compilers won’t complain, but the behavior is undefined and could cause problems at runtime.

Upvotes: 0

Kolodez
Kolodez

Reputation: 635

I edited my original answer:

You could instead write

function_1(struct example (*pex) [num_1][num_2]){}
void main(){
    struct example ex[num_1][num_2];
    function(& ex);
}

at least if you know num_1 and num_2 at compile time.

Upvotes: 1

Related Questions