Don't treat result
as a pointer to a two-dimensional array, arrays are, when passed to a function, implicitly converted to a pointer to the first element of that array. So you're doing an extra level of indirection above what you need.
In other words, the function declaration should be:
void addMatrices(int m1[3][3], int m2[3][3], int result[3][3]) {
and the call should be:
addMatrices(sampleM1,sampleM2,result);
A decent compiler should have warned you of this:
prog.c: In function ‘addMatrices’:
prog.c:21:30: error: assignment to ‘int *’ from ‘int’ makes pointer from integer without a cast [-Werror=int-conversion]
26 | result[row][col] = m1[row][col] + m2[row][col];
| ^
prog.c: In function ‘main’:
prog.c:30:32: error: passing argument 3 of ‘addMatrices’ from incompatible pointer type [-Werror=incompatible-pointer-types]
37 | addMatrices(sampleM1,sampleM2,&result);
| ^~~~~~~
| |
| int (*)[3][3]
prog.c:16:51: note: expected ‘int * (*)[3]’ but argument is of type ‘int (*)[3][3]’
20 | void addMatrices(int m1[3][3], int m2[3][3], int *result[3][3]) {
| ~~~~~^~~~~~~~~~~~
And just a bit of advice: once you start creating higher-level data structures, it's best to have them act much the same as C++ classes. In other words, place them into their own header and source files as specific types, rather than having to deal with the general types provided by C (like arrays).
For example, have a structure along the lines of:
// Everything you need to know about a matrix (of integers).
typedef struct {
size_t rows, cols;
int *data;
} tIntMatrix; // Poor man's template :-)
and provide functions to manipulate the specialised types directly:
// Allocate and de-allocate functions.
tIntMatrix *IntMatrixCreate(size_t rows, size_t cols);
tIntMatrix *IntMatrixCreateAndInit(size_t rows, size_t cols, int *values);
void IntMatrixDestroy(tMatrix *matrix);
// Get and set functions.
int IntMatrixGet(size_t row, size_t col);
void IntMatrixSet(size_t row, size_t col, int value);
void IntMatrixSetRow(size_t row, int *values);
void IntMatrixSetCol(size_t col, int *values);
void IntMatrixSetAll(int *values);
// Matrix manipulation functions, whatever is needed.
void IntMatrixAdd(tMatrix *m1, tMatrix *m2, tMatrix *sum);
void IntMatrixMult(tMatrix *m1, tMatrix *m2, tMatrix *product);
void IntMatrixInvert(tMatrix *m1, tMatrix *inversion);
// Traverse cells with a callback function.
// Function receives, for each cell: rows, cells, row, cell, value.
typedef void (*)(size_t, size_t, size_t, size_t, int) IntMatrixCb;
void IntMatrixProcess(tIntMatrix *matrix, IntMatrixCb callback);
C can be (at least partially) object-oriented, it just takes a little more work, but doing so provides much the same safety as those languages that are inherently object oriented, like encapsulation in this case.
By that, I mean the internal data structure is hidden<sup(a) from you, all you need to know, in order to be able to use the matrices, is the API.
Then, with use of a callback function:
void cbPrint(int size_t rows, size_t cols, size_t row, size_t col, int value) {
printf("%d", value);
putchar(col == cols - 1 ? '\n' : ' ');
}
Your main code then becomes something like:
tIntMatrix *sampleM1 = IntMatrixCreateAndInit(3, 3, {
1, 1, 1,
1, 1, 1,
1, 1, 1
});
tIntMatrix *sampleM2 = IntMatrixCreateAndInit(3, 3, {
1, 1, 1,
1, 1, 1,
1, 1, 1
});
tIntMatrix *result = IntMatrixCreate(3, 3);
IntMatrixAdd(sampleM1, sampleM2, result);
puts("Matriks 0:"); IntMatrixProcess(result, cbPrint);
<sup(a) Yes, I know you can see the rows/cols/data
structure but you don't have to use it if the API is any good. And, you can hide it behind an opaque pointer if you really want it hidden.