XDavidT XDavidT - 1 month ago 12
C Question

Static Matrix multiplication to dynamic matrix and free in c

I need to build program that make Matrix multiplication.
When i have 2 Static matrix, and the function return pointer to the new dynamic matrix.

My problem is make the multiplication right when I'm moving the matrix into a function.

Main is:

int a_matrix[A_R][A_C] = { {1,4,6,7},{1,1,5,9} }; //A[][X]&B[X][] --> X Must be Equal !!
int b_matrix[A_C][B_C] = { {5,6,3},{8,2,1}, {4,5,6},{0,9,6} };
int **new_matrix;

new_matrix = multiplying(A_R, A_C, B_C, a_matrix, b_matrix);
print_mtrx(new_matrix,A_R, B_C);
free_mtrx(new_matrix, B_C);
printf("Done...->Exit");


The problem is in the "multiplying" function, and here is it:

int multiplying(int a_rows, int a_cols, int b_cols, int A[A_R][A_C], int B[A_C][B_C]) {
//a_cols == b_rows --> from that we understand thar C is build as C[a_rows][b_cols]
int **C,i,j,k;
int sum;
C = (int**)malloc(sizeof(int*)*a_rows);

for (i = 0; i < a_rows; i++) {
C[i] = (int*)malloc(sizeof(int)*b_cols);
for (j = 0; j < b_cols; j++) {
sum = 0;
for (k = 0; k < a_cols; k++)
sum += A[i][k] * B[k][j];
C[i][j] = sum;
}
}

return(C);
}


The free matrix is:

void free_mtrx(int **mtrx, int rows) {
int i;
for (i = 0; i < rows; i++)
free(mtrx[i]);
free(mtrx);
}


After Update

Answer Source

Assuming C99 (or C11 and the implementation does not define __STDC_NO_VLA__), then the simplest approach is use variable length arrays (VLAs) and to have the calling code allocate the space for the result matrix too. To multiply two matrices, A[M][N] and B[P][Q] in that order, the values of N and P must be equal and the result matrix is C[M][Q].

#include <stdio.h>

static
void matrix_multiply(int A_rows, int A_cols, int B_cols,
                     int A[A_rows][A_cols],
                     int B[A_cols][B_cols],
                     int C[A_rows][B_cols])
{
    for (int i = 0; i < A_rows; i++)
    {
         for (int j = 0; j < B_cols; j++)
         {
              int sum = 0;
              for (int k = 0; k < A_cols; k++)
                  sum += A[i][k] * B[k][j];
              C[i][j] = sum;
         }
    }
}

static void print_matrix(const char *tag, int w, int N, int M, int matrix[N][M])
{
    printf("%s (%dx%d):\n", tag, N, M);
    for (int i = 0; i < N; i++)
    {
         for (int j = 0; j < M; j++)
             printf("%*d", w, matrix[i][j]);
         putchar('\n');
    }
}

int main(void)
{
    int A[3][4] =
    {
        { 41, 76, 70, 42, },
        { 70, 62, 77, 74, },
        { 49, 55, 43, 65, },
    };
    int B[4][5] =
    {
        { 73, 33, 42, 72, 65, },
        { 69, 30, 83, 83, 64, },
        { 90, 74, 84, 51, 23, },
        { 62, 45, 84, 46, 43, },
    };
    int C[3][5];
    print_matrix("A", 3, 3, 4, A);
    print_matrix("B", 3, 4, 5, B);
    matrix_multiply(3, 4, 5, A, B, C);
    print_matrix("C", 6, 3, 5, C);
    return 0;
}

Output:

A (3x4):
 41 76 70 42
 70 62 77 74
 49 55 43 65
B (4x5):
 73 33 42 72 65
 69 30 83 83 64
 90 74 84 51 23
 62 45 84 46 43
C (3x5):
 17141 10703 17438 14762 10945
 20906 13198 20770 17517 13471
 15272  9374 15695 13276 10489

If you want to do dynamic memory allocation, then I think you have to pass a pointer to a pointer to a VLA array to the function to get the value returned. That leads to code like this, which is very similar to the previous code — except for the (unchecked) memory allocation. Note that because this uses static_assert, it is a C11 program, not a C99 program.

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

#ifdef __STDC_NO_VLA__      // C11
static_assert(0, "No VLA support");
#endif

static void matrix_multiply(int A_rows, int A_cols, int B_cols,
                            int A[A_rows][A_cols], int B[A_cols][B_cols],
                            int (**C)[B_cols])
{
    (*C) = malloc(sizeof(int [A_rows][B_cols]));  // XXX: Check memory allocation!
    for (int i = 0; i < A_rows; i++)
    {
         for (int j = 0; j < B_cols; j++)
         {
              int sum = 0;
              for (int k = 0; k < A_cols; k++)
                  sum += A[i][k] * B[k][j];
              (*C)[i][j] = sum;
         }
    }
}

static void print_matrix(const char *tag, int w, int N, int M, int matrix[N][M])
{
    printf("%s (%dx%d):\n", tag, N, M);
    for (int i = 0; i < N; i++)
    {
         for (int j = 0; j < M; j++)
             printf("%*d", w, matrix[i][j]);
         putchar('\n');
    }
}

int main(void)
{
    enum { N = 3, M = 4, P = 4, Q = 5 };
    int A[N][M] =
    {
        { 41, 76, 70, 42, },
        { 70, 62, 77, 74, },
        { 49, 55, 43, 65, },
    };
    int B[P][Q] =
    {
        { 73, 33, 42, 72, 65, },
        { 69, 30, 83, 83, 64, },
        { 90, 74, 84, 51, 23, },
        { 62, 45, 84, 46, 43, },
    };
    static_assert(M == P, "Matrix dimensions are mismatched");
    int (*C)[Q];
    print_matrix("A", 3, N, M, A);
    print_matrix("B", 3, P, Q, B);
    matrix_multiply(N, M, Q, A, B, &C);
    print_matrix("C", 6, N, Q, C);
    free(C);
    return 0;
}

This produces the same output as before, of course.