Never use pointer-to-pointer to allocate multi-dimensional arrays. It is wide-spread but bad and incorrect practice. Doing so will not give you a true 2D array, and it will lead to slower code because of heap fragmentation. It also makes the code harder to write, read and maintain, which in turn increases the potential for memory leaks.
Instead, allocate the 2D array correctly in adjacent memory cells, like this:
int x;
int y;
// store some values in x and y here
int(*matrix)[y] = malloc (sizeof(int[x][y]));
if(matrix == NULL)
{
// error handling here
}
matrix[i][j] = something; // do something with the matrix
free(matrix);
If you insist on keeping this code in a function, then it would be:
void* allocMatrix (int nRow, int nCol)
{
return malloc (sizeof(int[nRow][nCol]));
}
int(*matrix)[y] = allocMatrix(x, y);
Edit: explanation of the code and array pointers.
In the line int(*matrix)[y] = malloc (sizeof(int[x][y]));
, the sizeof(int[x][y])
is pretty straight-forward, it is just the size of a 2D array of ints with dimensions x*y. It is using the concept of variable-length arrays from the C99 standard, which allows array dimensions to be specified in runtime.
An array pointer is a somewhat special type in C, it is able to point to whole arrays, rather than just at the first item of the array, as a normal pointer will do. The array pointer, unlike a regular pointer, knows the size of the array.
An array pointer is written as type(*name)[size]
, so for example an array pointer to an array of 5 ints would be written as int(*arr_ptr)[5] = &the_array;
.
When accessing the contents pointed at, an array pointer behaves just as any pointer, you access the contents of it with *
. So *arr_ptr
gives the array pointed at, and (*arr_ptr)[0]
gives the first item of that array.
For multi-dimensional arrays, the same rules apply. Given the array int arr[x][y]
, an array pointer to this type will be int(*arr_ptr)[x][y] = &arr;
. Accessing the contents *arr_ptr
will give you a two-dimensional array, which is equivalent to an array of arrays. (*arr_ptr)[0]
will therefore give the first array in the array of arrays. The usual rule for any array name when used in an expression, is that it "decays" into a pointer to the first element. Same applies here, so (*arr_ptr)[0]
will therefore also be the same as a pointer to the first element in the first array. And (*arr_ptr)[0][0]
will give the first element of the first array.
Now this syntax (*arr_ptr)[0][0]
looks a bit hard to read; to get the first item of a 2D array, we are used at writing just arr[0][0]
. So when declaring the array pointer, there is a handy trick. Instead of declaring the complete and correct array pointer: int(*matrix)[x][y]
, an array pointer to a 2D array of dimensions x*y, we instead declare it as int(*matrix)[y]
, which is an array pointer to a 1D array with dimension y. It will point at the first item in the 2D array, which is a 1D array of size y. We know that the 2D array contains x such items.
And because of this trick, we'll now be able to use the array pointer with the same syntax as when accessing a 2D array, namely matrix[i][j]
, rather than the hard-to-read (*matrix)[i][j]
.