2

My c code for matrix addition is given below:

mat(int n,int a[][5],b[][5] ){
   int i,c[5][5];

   for(i=0;i<5;i++){
       for(j=0;j<5;j++)
           c[i][j]=a[i][j]+b[i][j];

    return c;
}

When I compile this my compiler caught error:

||warning: command line option '-Wzero-as-null-pointer-constant' is valid for C++/ObjC++ but not for C [enabled by default]|
C:\Users\Amir Khasru\Desktop\retuturn_a_matrix.c|2|warning: return type defaults to 'int' [-Wreturn-type]|
C:\Users\Amir Khasru\Desktop\retuturn_a_matrix.c|2|warning: no previous declaration for 'mat' [-Wmissing-declarations]|
C:\Users\Amir Khasru\Desktop\retuturn_a_matrix.c||In function 'mat':|
C:\Users\Amir Khasru\Desktop\retuturn_a_matrix.c|8|error: return makes integer from pointer without a cast|
||=== Build failed: 1 error(s), 3 warning(s) (0 minute(s), 0 second(s)) ===|
Nick
  • 9,962
  • 4
  • 42
  • 80
Amir Khasru
  • 74
  • 1
  • 3
  • 10
  • 1
    In your program there are many other errors that are not related to your question. Start correcting them first. – Jabberwocky Apr 07 '16 at 08:35

2 Answers2

2

This is your code (just formatted and added a missing closing brace):

#include <stdio.h>

mat(int n, int a[][5], b[][5] )
{
    int i, c[5][5];

    for(i=0; i<5; i++) {
        for(j=0; j<5; j++) {
            c[i][j] = a[i][j] + b[i][j];
        }
        return c;
    }
}

I compile with: $ gcc -std=c99 -Wall -Wextra -Wpedantic -Wconversion -Wno-sign-compare -Wshadow test.c -o test and first thing I get is:

test.c:3:24: error: unknown type name ‘b’
 mat(int n, int a[][5], b[][5] )

Let's fix that (add int before b and j):

#include <stdio.h>

mat(int n, int a[][5], int b[][5] )
{
    int i, c[5][5];

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

Now we get:

test.c:3:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
 mat(int n, int a[][5], int b[][5] )
 ^
test.c: In function ‘mat’:
test.c:11:10: warning: return makes integer from pointer without a cast [-Wint-conversion]
   return c;
          ^
test.c:11:10: warning: function returns address of local variable [-Wreturn-local-addr]
test.c:3:9: warning: unused parameter ‘n’ [-Wunused-parameter]
 mat(int n, int a[][5], int b[][5] )
         ^
test.c:13:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^

So what to we get:

  • mat() returns int because it's a default fallback that dates to before C99, but no is not standard anymore. It seems though, that you are compiling on Visual Studio which basically implements C89 + some C99 for C++ compatibility -- but still, fix it.
  • Then you return c, which is definitely not of type int.
  • Also you don't use n, I guess it's meant to be the number of rows?
  • You return after the first inner loop is done -- that's probably not wanted.

What to do instead:
Generally you usually want the caller to give space for the result, as you return c which is local to mat() it is undefined behavior what happens after mat() finishes. Instead use the following declaration for mat():

void mat(int r, int c, int m1[r][c], int m2[r][c], int mr[r][c]);

where r is rows, c is columns, m1, m2 are the input matrices, mr is the result matrix.

The code would then be:

void mat(int r, int c, int m1[r][c], int m2[r][c], int mr[r][c])
{
        for(int i = 0; i < r; i++) {
                for(int j = 0; j < c; j++) {
                        mr[i][j] = m1[i][j] + m2[i][j];
                }
        }
}

You do not need to return anything -- you write to an object the caller provided (hopefully). If you feel brave you can check for m1 == NULL || m2 == NULL || mr == NULL before.

Let's see how this works using this test code:

void print_mat(int r, int c, int m[r][c]);

int main() {
        int m1[2][5] = {
                {0,1,2,3,4},
                {1,2,3,4,5}
        };
        int m2[2][5] = {
                {10,11,12,13,14},
                {11,12,13,14,15}
        };

        printf("printing matrix m1:\n");
        print_mat(2,5,m1);
        printf("printing matrix m1:\n");
        print_mat(2,5,m2);

        int c[2][5];
        mat(2,5,m1,m2,c);

        printf("printing matrix m1+m2:\n");
        print_mat(2,5,c);
}

void print_mat(int r, int c, int m[r][c])
{
        for (int i = 0; i < r; i++) {
                for (int j = 0; j < c; j++) {
                        printf("\t%d", m[i][j]);
                }
                printf("\n");
        }
        return;
}

I get:

printing matrix m1:
        0       1       2       3       4
        1       2       3       4       5
printing matrix m1:
        10      11      12      13      14
        11      12      13      14      15
printing matrix m1+m2:
        10      12      14      16      18
        12      14      16      18      20

which is exactly what it's supposed to be.

In the end:

  • State the types specifically, it helps.
  • Turn on all warnings if you are unsure.
  • Usually don't acquire memory in a subfunction, let the caller do this.
  • If you are unsure with pointers/arrays, try to avoid them and write small understandable test-cases; do research!
ljrk
  • 751
  • 1
  • 5
  • 21
  • I love this syntax. Did not know is possible `void print_mat(int r, int c, int m[r][c]);` – Nick Apr 07 '16 at 09:53
  • @Nick Yep it's nice; just be sure to have `r` and `c` in the declaration before the array using it! – ljrk Apr 07 '16 at 10:03
  • is this original C99 or C11 ? – Nick Apr 07 '16 at 10:50
  • 1
    @Nick pretty sure C99, I compile with `-std=c99` and I've used it on many compilers, some of which at least don't support all of C11. – ljrk Apr 07 '16 at 11:04
  • I found why I don't know this syntax - this is C99. C++ can not compile this. `x.cc:3:31: error: use of parameter outside function body before ‘]’ token void test(int const n, int a[n]){` – Nick Apr 07 '16 at 11:10
  • `[nmmm@zenbook asyncore_cpp]$ gcc x.c -std=c89 -Wpedantic x.c:3:1: warning: ISO C90 forbids variable length array ‘a’ [-Wvla] void test(int const n, int a[n]){` – Nick Apr 07 '16 at 11:12
  • 1
    @Nick Yep, apparently it's a feature of C99, made optional in C11 (see here: http://stackoverflow.com/questions/25551779/intnm-where-n-and-m-are-known-at-runtime). Also it ain't in C++ O.o – ljrk Apr 07 '16 at 11:15
-1

You can pass by reference.

I can not do it with your matrix, because I don't think code is 100% correct. Code would look like this.

int mat(int x, int y, const int *m_a, const int *m_b, int *m_out);

where:

  • int that function returns is kind of status code.
  • x and y are width and height of the matrix.
  • m_a, m_b are the input matrix. they are const.
  • m_out is the output matrix.

You can "upgrade" the function by return the matrix like this:

int *mat(int x, int y, const int *m_a, const int *m_b, int *m_out){
    // do some work
    if (something is not OK)
        return NULL;
    else
        return m_out;
}

// in main()
int a[5 * 6];
int b[5 * 6];
int result[5 * 6];
mat(5, 6, a, b, result);
// use result.

Third option, probably worse one - allocate the memory, and return allocated memory. Later memory needs to be freed.

int *mat(int x, int y, const int *m_a, const int *m_b){
    int *m_out = malloc( x * y * sizeof int);

    if (m_out == NULL)
        return NULL;

    // do some work

    if (something is not OK){
        free(m_out);
        return NULL;
    }else
        return m_out;
}

// in main()
int *m = mat(5, 6, a, b);
// use m
free(m);

Comment if you have question.

In all examples, I assume single dimension array. You can easily translate two dimension coordinates into single dimension, check here:

How to map the indexes of a matrix to a 1-dimensional array (C++)?

Here are complete, working example made the way I would do it.

#include <stdio.h>

int *mat(int x, int y, const int *m_a, const int *m_b, int *m_out){
    int i;
    for(i = 0; i < x * y; ++i)
        m_out[i] = m_a[i] + m_b[i];

    return m_out;
}

void print_mat(int x, int y, const int *m){
    int i, j;
    for(i = 0; i < x; ++i){
        for(j = 0; j < y; ++j)
            printf("| %4d ", m[i * y + j]);

        printf("|\n");
    }
}

#define X   2
#define Y   2

int main(){
    int a[X * Y] = { 1, 2, 3, 4 };
    int b[X * Y] = { 1, 2, 3, 4 };
    int result[X * Y];

    int *r = mat(X, Y, a, b, result);

    print_mat(X, Y, r);

    return 0;
}

Here are the output:

[nmmm@zenbook HM3]$ gcc -Wall -Wpedantic x.c
[nmmm@zenbook HM3]$ ./a.out 
|    2 |    4 |
|    6 |    8 |
[nmmm@zenbook HM3]$
Community
  • 1
  • 1
Nick
  • 9,962
  • 4
  • 42
  • 80
  • Why -1? I don't see any problems with my code – Nick Apr 07 '16 at 08:45
  • Not my downvote, but `int a[5, 6];` is wrong. The function arguments can still be fixed-size arrays as in the OP if that's all that's needed, although making them a pointer+size does make things more generic. – interjay Apr 07 '16 at 08:48
  • typo, fixed. This is why you need typedefs, but I decided not to add confusion. – Nick Apr 07 '16 at 08:48
  • Ok, now it even compiles. (homework done for free) – Nick Apr 07 '16 at 09:02
  • Hey Nick, can I declare variable dimension array in c.... like "int array[n][n]?" – Amir Khasru Apr 07 '16 at 10:41
  • yes, pls check the other answer from larkey. In my way I try to do it as generic as possible, with one dimension array – Nick Apr 07 '16 at 10:58