After seeing ouah's answer and seeing the example in the C FAQ, I now understand where the second technique comes from, although I personally wouldn't use it where I could help it.
The main problem with the first approach you show is that the rows in the array are not guaranteed to be adjacent in memory; IOW, the object immediately following M[0][4]
is not necessarily M[1][0]
. If two rows are allocated from different pages, that could degrade runtime performance.
The second approach guarantees that all the rows will be allocated contiguously, but you have to manually assign M[1]
through M[4]
to get the normal M[i][j]
subscripting to work, as in
for ( size_t i = 0; i < 5; i++ )
M[i] = M[i-1] + 5;
IMO it's a clumsy approach compared to the following:
int (*M)[5] = malloc( sizeof *M * 5 );
This also guarantees that the memory is allocated contiguously, and the M[i][j]
subscripting works without any further effort.
However, there is a drawback; on compilers that don't support variable-length arrays, the array size must be known at compile time. Unless your compiler supports VLAs, you can't do something like
size_t cols;
...
int (*M)[cols] = malloc( sizeof *M * rows );
In that case, the M[0] = malloc( rows * cols * sizeof *M[0])
followed by manually assigning M[1]
through M[rows - 1]
would be a reasonable substitute.