I’m going to challenge the frame of the question slightly: you’re not using the right kind of “two-dimensional array” as your data structure.
In C, you have the option to call your function with flexible array bounds. This allows your arrays to be rectangular, that is, rows of equal size laid out contiguously in memory. One simple implementation:
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
void sq_matrix_mul( const ptrdiff_t n,
const double left[n][n],
const double right[n][n],
double product[n][n] )
{
for ( ptrdiff_t i = 0; i < n; ++i )
for ( ptrdiff_t j = 0; j < n; ++j ) {
product[i][j] = 0.0;
for ( ptrdiff_t k = 0; k < n; ++k )
product[i][j] += left[i][k] * right[k][j];
} // end for j
}
#define DIMENSION 4
int main(void)
{
static const double a[DIMENSION][DIMENSION] = {
{ 1, 0, 0, 0 },
{ 0, 2, 0, 0 },
{ 0, 0, 3, 0 },
{ 0, 0, 0, 4 }
};
static const double b[DIMENSION][DIMENSION] = {
{ 1, 1, 1, 1 },
{ 1, 1, 1, 1 },
{ 1, 1, 1, 1 },
{ 1, 1, 1, 1 }
};
double c[DIMENSION][DIMENSION];
sq_matrix_mul( DIMENSION, a, b, c );
for ( ptrdiff_t i = 0; i < DIMENSION; ++i ) {
fputs( "[ ", stdout );
for ( ptrdiff_t j = 0; j < DIMENSION; ++j )
printf( "%f ", c[i][j] );
fputs( "]\n", stdout );
}
return EXIT_SUCCESS;
}
There are of course more complex array-multiplication algorithms with a better runtime than O(N³).
Since the elements of a rectangular array are contiguous in memory, if you literally want to increment through them (such as to set every matrix element to the same value), you just initialize a pointer to the first element and increment it.
The data structure you’re using, a double**, is a ragged array. It’s almost never the data structure you really want (unfortunately, all C and C++ programmers learn about char** argv first). Ragged arrays require a dynamic allocation per row rather than a single one for the entire matrix, add a pointer lookup per access, and have poor data locality, making them much slower. They also waste memory on all those pointers.
If your array is sparse, there are more efficient data structures, such as compressed sparse row. If it is dense, and all the rows are the same size anyway, a rectangular array is strictly superior to a ragged array.
If you do want to stick with a ragged array, simply use the function prototype you did before, and keep the loop the same. Array indices such as a[i][k] will work for either a ragged or a rectangular array.
My personal preference is to use ptrdiff_t (the type you get when subtracting pointers) for array indices, since these are signed and don’t create as many bugs from silent overflows and type promotions as unsigned types do. They also are the right width, not limited to 32 bits on 64-bit systems.
Finally, in C++, this solution would be illegal; I usually write a two-dimensional array class to provide a zero-cost abstraction.
double**cannot point at a 2D array. I take it you use some manner of pointer table? Could you please post the whole function so it becomes clearer why you need to do this.