In the routine that calls Multiply
, A
might be defined as float A[X][Y];
. However, Multiply
receives only a pointer, not an array. Also, Multiply
receives no information about the sizes of the original arrays, so they cannot be calculated in the subroutine. They must be passed by the caller.
When an array is used in an expression, including a function argument but excluding the operand of sizeof
or unary &
(or a string literal used to initialize an array), it is automatically converted to a pointer to its first element.
If A
is an array of X
arrays of Y
float
, then the first element of A
is an array of Y
float
. Therefore, when A
is used as a function argument, it is automatically converted to the type float (*)[Y]
. This is different from the parameter declaration, which is float *
. A pointer to an array of float
is not compatible with a pointer to a float
, and your compiler should warn you about that.
If you nonetheless compile the program with warnings ignored, or a cast to override the types, then Multiply
has only a float *
for A
. It has no information about the size of the array or the fact that is an array of arrays. Then, in the expression sizeof(A) / sizeof(A[0])
(in which the parentheses are unnecessary), sizeof(A)
is the size of a pointer to float
, because A
is a pointer to float
, and sizeof(A[0])is the size of a
float, because
A[0]is a
float(as it must be since
Ain
Multiplyis a
float *`).
The parameter B
has the same problem with the size calculation. In Multiply
, B
is only a pointer to float
, size sizeof(B) / sizeof(B[0])
calculates only the size of a pointer divided by the size of a float
. It does not provide the size of the original array.
Oddly, your code uses A
both as a two-dimensional array, in A[0][0]
, and a one-dimensional array, in A[p*i + k]
. You must choose one of these.
If your compiler supports variable length arrays, then you can declare Multiply
as:
void Multiply(int m, int p, int n, float (*A)[p], float (*B)[n], float (*C)[n])
Then you can use A[i][k]
, B[k][j]
, and C[i][j]
in the routine. In the calling routine, you would write the original arrays as arguments, as with Multiply(X, Y, Z, A, B, C)
, where X
, Y
, and Z
are the necessary dimensions.
An alternative is to pass the arrays as pointers to float
instead of pointers to variable length arrays:
void Multiply(int m, int p, int n, float *A, float *B, float *C)
Then you would use A[p*i + k]
and such as your current code shows. In the calling routine, you would pass pointers to the [0][0]
elements of the arrays: Multiply(X, Y, Z, &A[0][0], &B[0][0], &C[0][0])
.
Pedantically, this may have aliasing and pointer arithmetic problems since the resulting code accesses float
elements using index calculations outside the nominal arrays. It is commonly supported in compilers, but you ought to check.