I have the function with following signature:
void box_sort(int**, int, int)
and variable of following type:
int boxes[MAX_BOXES][MAX_DIMENSIONALITY+1]
When I am calling the function
box_sort(boxes, a, b)
GCC gives me two warnings:
103.c:79: warning: passing argument 1 of ‘box_sort’ from incompatible pointer type (string where i am calling the function)
103.c:42: note: expected ‘int **’ but argument is of type ‘int (*)[11] (string where the function is defined)
The question is why? Whether int x[][] and int** x (and actually int* x[]) are not the same types in C?
I know there was a question almost exactly like this a couple days ago... can't find it now though.
The answer is, int[size][]
(see note at the bottom) and int**
are definitely not the same type. You can use int[]
and int*
interchangeably in many cases, in particular in cases like this because the array decays to a pointer to the first element when you pass it into a function. But for a two-dimensional array, these are very different methods of storing.
Here's what they'd look like in memory for a 2x2 array:
int a[2][2]:
__a[0][0]__|__a[0][1]__|__a[1][0]__|__a[1][1]__
(int) (int) (int) (int)
int **a (e.g. dynamically allocated with nested mallocs)
__a__
(int**)
|
v
__a[0]__|__a[1]__
(int*) (int*)
| |
| |
v ------------------>
__a[0][0]__|__a[0][1]__ __a[1][0]__|__a[1][1]__
(int) (int) (int) (int)
You could construct the second one like this:
int **a = malloc(2 * sizeof(int*));
a[0] = malloc(2 * sizeof(int));
a[1] = malloc(2 * sizeof(int));
Note: As others have noted, int[][]
isn't a real type; only one of the sizes can be unspecified. But the core of the question here is whether a two-dimensional array and a double pointer are the same thing.
You never constructed an array of pointers as the signature requires.
There are two ways to do 2D arrays in C. In one case, you just have a lot of something and the compiler is told what the dimensions are. It calculates the beginning of the row by multiplying the row index by the number of columns and then it adds the column index to find the element within that row.
The other way is with a vector of pointers, where the compiler just dereferences the vector to find the beginning of the row, but the compiler won't make these for you automatically, you have to do it yourself.
Your actual object is one of the first kind, but your function prototype is asking for the second kind.
So you should either change the prototype to match the object or construct a vector of row pointers to pass to the function.
There is no such type in C as int[][]
, only the first part of a multidimensional array can be unspecified. So int[][5]
is okay.
In addition to the other answers posted here, if you can use C99, you can use variable arrays to accomplish what you want:
void box_sort(int N, int M, int x[M][N]);
This will work on most platforms except Microsoft's Visual C++.
When an array expression appears in most contexts, its type is implicitly converted from "N-element array of T" to "pointer to T", and its value is set to the address of the first element in the array. The exceptions to this rule are when the array expression is an operand of the sizeof
or address-of (&
) operators, or if the array expression is a string literal being used to initialize another array in a declaration.
What this means in the context of your code is that in your call to box_sort
, the type of the expression boxes
is implicitly converted from M-element array of N-element array of int
to pointer to N-element array of int
, or int (*)[MAX_DIMENSIONALITY+1]
, so your function should be expecting parameter types like:
void box_sort(int (*arr)[MAX_DIMENSIONALITY+1], int x, int y)
{
...
}
Since int *a
and int a[]
are synonymous in a function parameter declaration, it follows that int (*a)[N]
is synonymous with int a[][N]
, so you could write the above as
void box_sort(int arr[][MAX_DIMENSIONALITY+1], int x, int y)
{
}
although I personally prefer the pointer notation, as it more accurately reflects what's going on. Note that in your function, you would subscript arr
as normal:
arr[x][y] = ...;
since the expression arr[x]
is equivalent to *(arr + x)
, the pointer is implicitly dereferenced.
If you want box_sort to work on arbitrarily-sized arrays (i.e., arrays where the second dimension isn't necessarily MAX_DIMENSIONALITY+1), then one approach is to do the following:
int boxes[X][Y];
...
box_sort (&boxes[0], X, Y, x, y);
...
void box_sort(int *arr, size_t rows, size_t cols, int x, int y)
{
...
arr[x*cols + y] = ...;
}
Basically, you're treating boxes
as a 1-d array of int and calculating the offsets manually.