-1

I am new to the C language trying to multiply 2d arrays via pointer by passing it to a function.

Program exits when it is inside multiplication function, only prints "I am in function".

Please let me know if I am passing 2d array via pointers is correct?

I have mentioned some warnings and output

Thanks

#include <stdio.h>
int m, n;            // rows and columns matrix 1
int x, y;            // rows and columns matrix 2

void multiplication(int **arr, int **arr1)
{
    printf("I am in function");
    int result[m][y];
    for (int i = 0; i < m; i++)
    {
        for (int j = 0; j < n; j++)
        {
          
            result[i][j] = (arr[i][j]) * (arr1[i][j]);
        }
          printf("calculating");
    }
    for (int i = 0; i < m; i++)
    {
        for (int j = 0; i < n; j++)
        {
            printf("printing");
            printf("%d", result[i][j]);
            printf("\t");
        }
        printf("\n");
    }
}
int main()
{
    
    printf("Enter the rows and column for matrix 1\n");
    scanf("%d %d", &m, &n);
    printf("Enter the rows and column for matrix 2\n");
    scanf("%d %d", &x, &y);
    if (n != x)
    {
        printf("Cant multiply matrix");
    }
    else if (n == x)
    {
        int a1[m][n], a2[x][y];
        printf("Enter the value for matrix 1 \n\n");
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {
                scanf("%d", &a1[i][j]);
            }
        }
        printf("Enter the value for matrix 2 \n\n");
        for (int i = 0; i < x; i++)
        {
            for (int j = 0; j < y; j++)
            {
                scanf("%d", &a2[i][j]);
            }
        }
        multiplication(a1, a2);

        return 0;
    }
}

SOME WARNINGS:

matrixmult.c:59:24: warning: passing argument 1 of 'multiplication' from incompatible pointer type [-Wincompatible-pointer-types]
   59 |         multiplication(a1, a2);
      |                        ^~
      |                        |
      |                        int (*)[n]
matrixmult.c:5:27: note: expected 'int **' but argument is of type 'int (*)[n]'
    5 | void multiplication(int **arr, int **arr1)
      |                     ~~~~~~^~~
matrixmult.c:59:28: warning: passing argument 2 of 'multiplication' from incompatible pointer type [-Wincompatible-pointer-types]
   59 |         multiplication(a1, a2);
      |                            ^~
      |                            |
      |                            int (*)[y]
matrixmult.c:5:38: note: expected 'int **' but argument is of type 'int (*)[y]'
    5 | void multiplication(int **arr, int **arr1)
      |                                ~~~~

OUTPUT:

Enter the rows and column for matrix 1
2
2
Enter the rows and column for matrix 2
2
2
Enter the value for matrix 1

1
2
1
2
Enter the value for matrix 2

1
2
1
2
I am in function
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • 1
    `int j = 0; i < n; j++)` – Gerhardh Apr 26 '22 at 07:00
  • 1
    Welcome to SO. For future questions please also add your input and the output you get, including what output you expect. – Gerhardh Apr 26 '22 at 07:02
  • 2
    A pointer to an array is not the same as a pointer to a pointer. You tell your compiler that `arr` points to `int*` which is not true. It points to an array of `int`s. – Gerhardh Apr 26 '22 at 07:05

3 Answers3

1

You treat an array as if it was the same as a pointer. This is not true.

Your array holds n*m integers that are stored in memory at consecutive addresses. You tell the compiler that parameter arr holds the address of a pointer to an integer. This means, if you write arr[i][j] will dereference your pointer and read an address from memory that is also dereferenced. This address is actually an int in memory, not a pointer. Taking an integer and use as address causes undefined behaviour.

Luckily your compiler already told you that these types do not match. It also provides the correct type of your argument. With this information you can fix the signature:

void multiplication(int n, int y, int (*arr)[n], int (*arr1)[y])

or (inspired by Lundin's answer)

void multiplication(int x, int y, int z, int arr1[x][y], int arr2[y][z])

Then update your function call accordingly.

Also you have a typo in one of your loops:

for (int j = 0; i < n; j++)

That should be j < n.

Additionally, the ranges in your loops are not correct. You create 2 arrays with different dimensions. You only require that n==x. That means your arrays are defined as int arr[x][y] and int arr1[y][z]. Also the resulting array is defined as int result[x][z].

There is no indication that x==y or y==z might be true.

Yet you use identical ranges for all arrays:

result[i][j] = (arr[i][j]) * (arr1[i][j]);

This will only work if all ranges are the same. Otherwise you will either access out of bounds or not touch all elements.

A correct version applying algorithm for matrix multiplication could look like this (not tested):

void multiplication(int x, int y, int z, int arr1[x][y], int arr2[y][z])
{
    printf("I am in function");
    int result[x][z];

    printf("calculating");
    for (int i = 0; i < x; i++)
    {
        for (int j = 0; j < z; j++)
        {
            int cell = 0;
            for (int k = 0; k < y; k++)
            {
                cell += arr1[i][k] * arr2[k][j];
            }          
            result[i][j] = cell;
        }
    }
    printf("printing");
    for (int i = 0; i < x; i++)
    {
        for (int j = 0; j < z; j++)
        {
            printf("%d", result[i][j]);
            printf("\t");
        }
        printf("\n");
    }
}
Gerhardh
  • 11,688
  • 4
  • 17
  • 39
1
  1. Avoid global variables. That is, the declarations of x, y, m, n should be placed inside main() and then passed as parameters to the function.
  2. Pointer-to-pointer has absolutely nothing to do with 2D arrays.

After fixing these problems, your function might look like this instead:

void multiplication (int x, int y, int arr1[x][y], int arr2[x][y])

In case the function isn't going to modify either array, it is custom to declare it with const correctness:

void multiplication (int x, int y, const int arr1[x][y], const int arr2[x][y])
Lundin
  • 195,001
  • 40
  • 254
  • 396
1

Along with two excellent answers above:

  1. Since you're new to C you can avoid pointers altogether, C has a provision for that.

  2. Split the problem into multiple sections for reuse. Define a function to print matrix like :

void matrix_print (const int rows, const int cols, const int mat[rows][cols]) {
    for (int ri = 0; ri < rows; ++ri) {
        for (int ci = 0; ci < cols; ++ci)
            printf ("%10d ", mat[ri][ci]);
        putchar ('\n'); // for pretty matrix print
    }
}

As pointed out by @gerhardh & @lundin, rows & cols should precede before usage in mat[rows][cols].

  1. Then to read a matrix you'll have: Note, how we need to check return value of scanf() to detect errors in input.
#define ERR_INV_NUM_STR  "ERROR: Invalid Number\n"

int matrix_read (const int rows, const int cols, int mat[rows][cols]) {
    for (int ri = 0; ri < rows; ++ri) {
        for (int ci = 0; ci < cols; ++ci)
            if (1 != scanf("%d", &mat[ri][ci])) {
                fputs (ERR_INV_NUM_STR, stderr);
                return 1;
            }
    }
    return 0;
}
  1. As noted already, your matrix-multiplication logic is false. Correct method is :
// Note: we've established 'acols = brows'
void matrix_multiply (const int arows, const int acols, int A[arows][acols],
                      const int bcols, const int B[acols][bcols], int C[arows][bcols]) {
    for (int ri = 0; ri < arows; ri++) {
        for (int ci = 0; ci < bcols; ci++) {
            C[ri][ci] = 0;
            for (int ki = 0; ki < acols; ki++)
                C[ri][ci] += A[ri][ki] * B[ki][ci];
        }
    }
}
  1. Then to wrap up, your main() becomes :

int main() {

    printf ("Enter the order of Matrix A (p x q):\n");
    int arows, acols;
    if (2 != scanf ("%d %d", &arows, &acols)) {
        fputs (ERR_INV_NUM_STR, stderr);
        return 1;
    }

    printf ("Enter the order of Matrix B (r x s):\n");
    int brows, bcols;
    if (2 != scanf ("%d %d", &brows, &bcols)) {
        fputs (ERR_INV_NUM_STR, stderr);
        return 2;
    }

    if (acols != brows) {
        printf ("Cant multiply these matrices\n");
        return 3;
    }

    int A[arows][acols];    // using VLA, nice
    printf ("Enter the values for Matrix A:\n");
    if (matrix_read (arows, acols, A)) {
        printf ("ERROR: Reading Matrix A\n");
        return 4;
    }

    int B[brows][bcols];    // using VLA, nice
    printf ("Enter the values for Matrix B:\n");
    if (matrix_read (brows, bcols, B)) {
        printf ("ERROR: Reading Matrix B\n");
        return 5;
    }

    int C[arows][bcols];    // A(p,q) * B(r,s) = C(p,s) when q = r
    matrix_multiply (arows, acols, A, bcols, B, C);

    printf ("\nMatrix A:\n");
    matrix_print (arows, acols, A);

    printf ("\nMatrix B:\n");
    matrix_print (brows, bcols, B);

    printf ("\nMatrix C: (A * B) \n");
    matrix_print (arows, bcols, C);

    return 0;
}

Sample tests:

Enter the order of Matrix A (p x q):
1 5
Enter the order of Matrix B (r x s):
5 1
Enter the values for Matrix A:
1 2 3 4 5
Enter the values for Matrix B:
5 4 3 2 1

Matrix A:
         1          2          3          4          5 

Matrix B:
         5 
         4 
         3 
         2 
         1 

Matrix C: (A * B) 
        35 

And

Enter the order of Matrix A (p x q):
5 1     
Enter the order of Matrix B (r x s):
1 5
Enter the values for Matrix A:
1 2 3 4 5
Enter the values for Matrix B:
5 4 3 2 1

Matrix A:
         1 
         2 
         3 
         4 
         5 

Matrix B:
         5          4          3          2          1 

Matrix C: (A * B) 
         5          4          3          2          1 
        10          8          6          4          2 
        15         12          9          6          3 
        20         16         12          8          4 
        25         20         15         10          5 

Note: Compilers throw warnings for const qualifiers for arrays:

warning: pointers to arrays with different qualifiers are incompatible in ISO C [-Wpedantic]
   78 |     matrix_print (arows, acols, A);
...
warning: pointers to arrays with different qualifiers are incompatible in ISO C [-Wpedantic]
   75 |     matrix_multiply (arows, acols, A, bcols, B, C);

GCC (GNU C Compiler) honours it, but ISO C standard doesn't cover it. SO - Pointer to array with const qualifier in C & C++

जलजनक
  • 3,072
  • 2
  • 24
  • 30