1

I'm getting this error:

incompatible pointer types returning 'int [4][2]' from a function with result type 'int *'

When I try to do this

int* getValid(int blank[2]){

int row = blank[0];
int col = blank[1];
static int valid[4][2];

valid[0][0] = row;
valid[0][1] = col-1;
valid[1][0] = row;
valid[1][1] = col+1;
valid[2][0] = row-1;
valid[2][1] = col;
valid[3][0] = row+1;
valid[3][1] = col;

return valid;

}

I'm trying to return a 2D array that I generate inside the function.

I'm mostly code in Python so arrays in C are kicking my butt..

3 Answers3

1

You cannot pass an array to/from a function in C. But you can pass a pointer. And that can point to an array.

So, you need a function like:

#define COLS 2

int (*getValid(int blank[2]))[COLS]
{
    static int valid[4][COLS];
    ...
    return valid;
}

Mind the parenthesis. I also use COLS for the innter dimension's length. This avoids magic numbers, i.e. repeating constants throughout your code. Use that macro for all declarations the array is involved, including the definition.

This is a "function without arguments returning a pointer to an 1D array with COLS ints". For details about arrays and pointers in C, please see a good C book and do some research on your own. Just keep in mind that while they are different types, they have a lot in common in practical use (language mechanisms behind are more difficult to understand).

Simply said, if you use return valid with the above declaration of the function, the name of the array is converted to a pointer to the first element. Which is exactly what you shall return.

The caller need to use the same pointer type (pointer to 1D array) for the result:

int (*arr)[COLS] = getValid(...);

The elements are accessed like for the original array:

arr[row][col]

Additional information: You should not use a static array in the function, unless you want to safe state between calls. Better allocate the array dynamically with malloc:

int (*arr)[COLS];
arr = malloc(sizeof(*arr) * 4); // 4 rows of the inner array

Don't forget to check if malloc failed and take appropriate measures.

Also don't forget to release the dynamically allocated array once you're done with it (but not earlier):

free(arr);
too honest for this site
  • 12,050
  • 4
  • 30
  • 52
0

In fact, you must let an n-dimension array decay to a pointer to a n-1 dimension array. And as you use a static array, it is safe to return its address.

The only tricky thing would be to declare a function returning a pointer to an array of size 2, but a typedef can really help here:

typedef int Arr2[2];

Arr2* getValid(int blank[2]){

    int row = blank[0];
    int col = blank[1];
    static int valid[4][2];

    valid[0][0] = row;
    valid[0][1] = col-1;
    valid[1][0] = row;
    valid[1][1] = col+1;
    valid[2][0] = row-1;
    valid[2][1] = col;
    valid[3][0] = row+1;
    valid[3][1] = col;

    return valid;

}

And you can safely use it like that:

Arr2 * arr = getValid(blank);

for (i=0; i<4; i++) {
    for (j=0; j<2; j++) {
        printf(" %d", arr[i][j]);
    }
    putc('\n', stdout);
}

Compiles and runs fine without any warning.

But beware: it is safe only because valid is declared with static storage. Never return a pointer to an automatic array! (use dynamic arrays (allocated with malloc if you do not want static storage)

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
-1

In C arrays are second class citizens. In order to pass them around you would need to wrap in a structure.

I.e.:

struct t_array42int{int o[4][2];} getValid(int *blank){

int row = blank[0];
int col = blank[1];
static struct t_array42int valid_container;

int (*valid)[2] = valid_container.o;

valid[0][0] = row;
valid[0][1] = col-1;
valid[1][0] = row;
valid[1][1] = col+1;
valid[2][0] = row-1;
valid[2][1] = col;
valid[3][0] = row+1;
valid[3][1] = col;

return valid_container;

}

Then you can store your function return value like:

struct t_array42int tmp = getValid(something);

Of-course there are ways to simplify this process of "wrapping" but those are often not standard or too obfuscated.

The disadvantage of using structures is that structure types aren't compared by their members layout but instead (normally) by their names. So something like this:

struct { int o[2]; } a;

struct { int o[2]; } b;

a = b; //Error

Is illegal.

You should write:

struct t_array2int { int o[2]; } a;

struct t_array2int b;

a = b; //OK

Instead.

You could also return a pointer to your array instead because it's storage is static (i.e. it won't cease to exist after returning from function):

int (*getValid(int *blank))[2]{

int row = blank[0];
int col = blank[1];
static int valid[4][2];


valid[0][0] = row;
valid[0][1] = col-1;
valid[1][0] = row;
valid[1][1] = col+1;
valid[2][0] = row-1;
valid[2][1] = col;
valid[3][0] = row+1;
valid[3][1] = col;

return valid;

}

The function prototype:

int (*getValid(int *blank))[2]

Means that if you call your function getValid with a single argument of type int * - getValid(something) and dereference it, *getValid(something) you'll get an array that can't be accessed like (*getValid(something))[2] and so have maximum 2 elements of type int.

Simple instance of the above example will be:

int (*tmp)[2] = getValid(something);

And I also suggest to write your array parameters with their real type (which can never be an array - the compiler is only fooling you into thinking that arrays can be passed by value). I.e.: void f(int a[N]) is adjusted to void f(int *a). And int * is not the same as int [N].

For a newcomer I suggest you remember that arrays are not the same as pointers but are mistreated as such very badly. Also I suggest you to never write functions with array parameters. And if you want to use arrays in a different way then to get pointer to their first element to use structures instead - much safer.

The main thing with array parameter is that:

void f(int a[2]) 
{ 
    sizeof(a) == sizeof(int *); //evaluates to 1

    sizeof(a) != sizeof(int [2]); //evaluates to 1
}
AnArrayOfFunctions
  • 3,452
  • 2
  • 29
  • 66
  • Names starting with underscore are reserved fot the implementation. And a singe underscore is the worst name ever. – too honest for this site Jun 29 '16 at 10:58
  • I've just started learning about pointers and memory allocation. From my understanding an array's name is simply a pointer to the first item of the array, or array[i] a pointer to the ith item in the array. Is this correct? I ask because you said arrays are not the same as pointers. – Fernando Ortega Jul 02 '16 at 23:38