0

I am currently building a Matrix calculator to add matrices, and for some reason when I add two matrices together, the correct answers for each point in matrix addition get spaced out, and in between them are zeros.

For example,

1 1 1
1 1 1
1 1 1
+
1 1 1
1 1 1
1 1 1

results in

2 0 2
0 2 0
2 0 2

instead of a matrix full of twos .

here is the code for the printing and adding function for the matrices


void printMatrix(int matriks,int matrix[3][3]) {

    int row;
    int column;

    printf("matriks %d:\n",matriks);
    for (row = 0; row < 3; row++) {
        for (column = 0; column < 3; column++) {
            printf(" %d", matrix[row][column]);
        }

        printf("\n");
    }


}

void addMatrices(int m1[3][3], int m2[3][3], int *result[3][3])  {

   int row;
   int col;
    for (row=0; row < 3; row++) {
        for (col=0; col<3;col++) {
            result[row][col] = m1[row][col] + m2[row][col];
        }
    }


}




and this is how theyre called in main()

 int result[3][3];
 int sampleM1[3][3] = {{1,1,1}, {1,1,1}, {1,1,1}};
 int sampleM2[3][3] = {{1,1,1}, {1,1,1}, {1,1,1}};
 addMatrices(sampleM1,sampleM2,&result);
 printMatrix(0,result);

any help would be appreciated. Thanks!

k12293139
  • 29
  • 4

2 Answers2

4

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.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Thank you! im at an introductory class, so im still a beginner at C, and feel like theres so many things to learn but your answer helped me. – k12293139 Feb 12 '23 at 11:33
1

When you're compiling, turn warnings on, e.g. on gcc via -Wall.

If you would have done that, you would have seen a bunch of warnings as can be seen here: https://godbolt.org/z/79a7drWar

You should know, that arrays will decay to pointer if passed as argument to a function (see: https://en.cppreference.com/w/c/language/array#Array_to_pointer_conversion).

Change

void addMatrices(int m1[3][3], int m2[3][3], int *result[3][3]);

to

void addMatrices(int m1[3][3], int m2[3][3], int result[3][3]);

and call it without the address of operator

addMatrices(sampleM1,sampleM2,result);
Erdal Küçük
  • 4,810
  • 1
  • 6
  • 11