rainversion_3
rainversion_3

Reputation: 957

Adding 2 matrices using pointers

I can acheive it by passing (c,a,b) to add_mat function, where result of a,b is stored in c like,

void add_mat(int c[][3], int a[][3], int b[][3], int m, int n)

What should be the return type of add_mat if I want to construct the funtion in this way

?? add_mat(int a[][3], int b[][3], int m, int n)

Below is a sample code

#include<stdio.h>

void read_mat(int a[][3], int m, int n){
    //scan data
    for(int i=0; i<m; i++){
        for(int j=0; j<n; j++){
            printf("[%d][%d] : ",i,j);
            a[i][j]=i+j;
        }
    }   
}
int* add_mat(int a[][3], int b[][3], int m, int n){
    int c[3][3];
    for(int i=0; i<m; i++){
        for(int j=0; j<n; j++){
            c[i][j]=a[i][j]+b[i][j];
        }
    }
    return c;
}

int main(){
    int a[3][3];
    int m=2,n=2; //mxn of a matrix

    read_mat(a, m, n);

    //add
    int b[3][3];
    read_mat(b, m, n);
    int* c[3][3];
    c = add_mat(a,b,m,n);

    return 0;
}

Like passing or pointing the calculated value c inside add_mat function to variable in main function.

Upvotes: 2

Views: 4679

Answers (3)

boriaz50
boriaz50

Reputation: 858

In your code add_mat returns the pointer to the variable which lives while the function executes only. You can accomplish your goal with dynamically allocated matrix.

In C it is common to pass a dynamically allocated matrix via pointer to pointers to the rows of matrix as a first parameter:

void foo(int** matrix, size_t m, size_t n);

Here matrix is a pointer to the array of pointers. Every pointer in this array points to the row of matrix. So, matrix[0] points to the array containing the first row of matrix.

And it is common to use size_t type for any sizes of arrays.

If you need create matrix dynamically, be careful with memory. Every dynamically allocated block should be released. Otherwise you will get memory leaks, that may cause the program crash. Therefore, when you allocate rows of matrix, you should check if allocation of current row was successfull. If not, you should release all previously allocated rows.

There is a working code for your question:

#include <stdio.h>
#include <stddef.h>
#include <malloc.h>

void free_mat(int** a, size_t m) {
    if (!a) {
        return;
    }

    for (size_t i = 0; i < m; ++i) {
        free(a[i]);
    }

    free(a);
}

int** create_mat(size_t m, size_t n) {
    int** rows = calloc(m, sizeof(int*));
    if (!rows) {
        return NULL;
    }

    for (size_t i = 0; i < m; i++) {
        rows[i] = malloc(n * sizeof(int));
        if (!rows[i]) {
            free_mat(rows, m);
            return NULL;
        }
    }

    return rows;
}

void read_mat(int** a, size_t m, size_t n) {
    for (size_t i = 0; i < m; i++) {
        for (size_t j = 0; j < n; j++) {
            printf("[%d][%d]: ", i, j);
            scanf("%d", a[i] + j);
        }
    }
}

void print_mat(const int* const* a, size_t m, size_t n) {
    for (size_t i = 0; i < m; ++i) {
        for (size_t j = 0; j < n; ++j) {
            printf("[%d][%d]: %d\n", i, j, a[i][j]);
        }
    }
}

int** add_mat(const int* const* a, const int* const* b, size_t m, size_t n) {
    int** c = create_mat(m, n);
    if (c) {
        for (size_t i = 0; i < m; ++i) {
            for (size_t j = 0; j < n; ++j) {
                c[i][j] = a[i][j] + b[i][j];
            }
        }
    }
    return c;
}

int main() {
    size_t m = 3;
    size_t n = 3;

    int** a = create_mat(m, n);
    int** b = create_mat(m, n);

    if (!a || !b) {
        printf("error when allocating matrix\n");
    }
    else {
        read_mat(a, m, n);
        read_mat(b, m, n);

        int** c = add_mat(a, b, m, n);
        if (!c) {
            printf("error when allocating matrix\n");
        }
        else {
            print_mat(c, m, n);
            free_mat(c, m);
        }
    }

    free_mat(a, m);
    free_mat(b, m);

    return 0;
}

But you would be more flexible, if add_mat didn't create a new matrix. It is common to pass a pointer to the result matrix as a function parameter:

void add_mat(int** c, const int* const* a, const int* const* b, size_t m, size_t n);

Upvotes: 1

Binarus
Binarus

Reputation: 4395

Oh yes, the pointers ...

In C, locally declared arrays usually are allocated on the stack (not on the heap) which means they are not valid outside the respective scope.

In other words, in your function add_mat(), c technically can be returned, but the address it points to will only contain meaningful matrix data as long as the function is executed.

After having returned from the function, the return value of the function is a pointer which still contains (points to) the address where the matrix was stored during execution of the function, but the contents of that location, i.e. the matrix data, can contain arbitrary garbage now.

So what you are doing is technically possible (i.e. throws no compile errors), but is definitely not what you want.

Secondly, your line int* c[3][3]; probably is not what you intend it to be. You are declaring c to be a two-dimensional array (matrix) of pointer to int here. This is not correct since you want to process int values, but not pointers to int values (which are addresses).

To solve both problems, just write int c[3][3]; instead of int* c[3][3]; and change your add_mat() function as follows:

void add_mat(int a[][3], int b[][3], int c[][3], int m, int n){

    for(int i=0; i<m; i++){
        for(int j=0; j<n; j++){
            c[i][j]=a[i][j]+b[i][j];
        }
    }
}

Then call that function like that:

add_mat(a,b,c,m,n);

Upvotes: 1

gsamaras
gsamaras

Reputation: 73366

You cannot do that, since the memory of the c matrix will be gone when the function terminates.

You need to dynamically allocate it with malloc(), in order for the memory not to be free'd, unless you call free(). I have some examples for that in 2D dynamic array (C), if you want to take a look.

With your previous function, you would create the matrix c outside the function (in main()), that's why dynamic memory allocation was not required.


PS: You should compile with warnings enabled:

prog.c: In function 'add_mat':
prog.c:19:12: warning: returning 'int (*)[3]' from a function with incompatible return type 'int *' [-Wincompatible-pointer-types]
     return c;
            ^
prog.c:19:12: warning: function returns address of local variable [-Wreturn-local-addr]
prog.c: In function 'main':
prog.c:32:7: error: assignment to expression with array type
     c = add_mat(a,b,m,n);
       ^
prog.c:31:10: warning: variable 'c' set but not used [-Wunused-but-set-variable]
     int* c[3][3];
          ^

Here is a working example, which is just for demonstrative purposes:

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

void read_mat(int a[][2], int n, int m){
    //scan data
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
            a[i][j] = i + j ;
        }
    }
}

int **get(int N, int M) /* Allocate the array */
{
    /* Check if allocation succeeded. (check for NULL pointer) */
    int i, **table;
    table = malloc(N*sizeof(int *));
    for(i = 0 ; i < N ; i++)
        table[i] = malloc( M*sizeof(int) );
    return table;
}

void print(int** p, int N, int M) {
    int i, j;
    for(i = 0 ; i < N ; i++)
        for(j = 0 ; j < M ; j++)
            printf("array[%d][%d] = %d\n", i, j, p[i][j]);
}

void free2Darray(int** p, int N) {
    int i;
    for(i = 0 ; i < N ; i++)
        free(p[i]);
    free(p);
}

int** add_mat(int a[][2], int b[][2], int m, int n){
    int** c = get(n, m);
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
            c[i][j]=a[i][j]+b[i][j];
        }
    }
    return c;
}

int main(){

    int n = 2, m = 2; //nxm of a matrix
    int a[n][m];

    read_mat(a, n, m);

    //add
    int b[n][m];
    read_mat(b, n, m);
    int** c;
    c = add_mat(a, b, n, m);

    print(c, n, m);
    free2Darray(c ,n);

    return 0;
}

Output:

array[0][0] = 0
array[0][1] = 2
array[1][0] = 2
array[1][1] = 4

PPS: If you really want to use static arrays, then I recommend using int c[3][3]; add_mat(c, a, b, m, n);

Upvotes: 2

Related Questions