My teacher told me that int **array is not a 2D array, it is just a pointer to a pointer to an integer. Now, in one of my projects I have to dynamically allocate a 2D array of structs, and this is how it is done:
struct cell **array2d = (struct x **)calloc(rows, sizeof(struct x *));
for (int i = 0; i < columns; i ) {
array2d[i] = (struct x *)calloc(j, sizeof(struct x));
}
But here we return a pointer to a pointer to the struct, so how is this a 2D array?
Before using dynamic allocation, I had a statically allocated array of the form: array2d[][]
Now that I replaced it by dynamic allocation, I also replaced array2d[][] by **array2d.
Every function that takes array2d[i][j] als argument now returns an error saying the types don't match.
Could someone explain me what is happening here? What is the difference between **array and array[m][n] and why is the compiler complaining?
CodePudding user response:
They're thoroughly different things.
An array is a sequence of values of the same type stored one after another in memory.
In C, an array is more or less interchangeable with a pointer to its first element — a[0]
is *a
,
a[1]
is *(a 1)
, etc. — at least when we're talking about one-dimensional arrays.
But now consider:
int a[3][3];
in this case, a
contains nine elements, contiguous in memory. a[0][0]
through a[0][2]
, then a[1][0]
immediately after, up until a[2][2]
. *a
is the same as a[0][0]
. An expression like a[1]
isn't meaningful.
If you pass a
to a function, it would fit into a parameter type of int *
or int[3][3]
or int [][3]
(knowing the "stride" of the second dimension is absolutely necessary to doing the math to look up a given element).
On the other hand:
int *b[3];
b[0] = malloc(...);
b[1] = malloc(...);
b[2] = malloc(...);
in this case, b
is an array of 3 elements, each of which is a pointer to an array of 3 elements. You still access it like b[0]0]
or b[1][2]
, but something completely different is happening under the hood. The elements aren't all stored contiguously in memory, and *b
isn't any of them, it's a pointer. If we were to pass b
to a function, we would receive it with a parameter of type int **
or int *[]
. Knowing the length of each row in advance isn't necessary, and in fact each row could have a different length from the others. Some of the rows could even be null pointers, with no storage behind them for integers.
CodePudding user response:
Pointers and arrays are not the same thing and do not have the same functionality.
Think about implementing a graph. A graph has edges starting from nodes. It is clear that an edge corresponds to a pointer whose value is the address of other node. How would you think about an edge using an array ? -- it is possible (and some data structures such as heaps implement edges using arrays) but not so intuitive and incovenient many times.
Arrays are syntactic sugar in C -- they are all the time rewritten using pointer arithmetic, but pointers are not all the time thought as arrays.
Using double-pointers you can encode 2d arrays (seen as an array containing pointers to other arrays), while a [N][M]
array is a single vector in memory that can be accessed in (x,y)
as v[M*x y].