Adding up matrices/ returning an array

Viewed 57

I'm a begginer to C and I've got some problems with programming a function which would take two matrices, add them up and return the result as a third matrix. The fundamental problem is making a function return an array.

I found some solutions online on how to return an array by returning a pointer to the first element of the array, but couldn't apply it to my situation with two-dimensional array. I know how to add matrices in main function, but I need to break the program down into several functions.

Here is my code

float matrix_add(float matrixA[MAX_SIZE][MAX_SIZE], float matrixB[MAX_SIZE][MAX_SIZE], int column, int line)
{
   float matrixRes[MAX_SIZE][MAX_SIZE];
    for (int i=0; i<column; i++)
    {
        for (int j=0; j<line; j++)
        {
            matrixRes[i][j]=matrixA[i][j]+matrixB[i][j];
        }
    }
    return matrixRes;
}

I've tried one of the solutions I've found online:

float *matrix_add(float matrixA[MAX_SIZE][MAX_SIZE], float matrixB[MAX_SIZE][MAX_SIZE], int column, int line)
{
   static float *matrixRes[MAX_SIZE][MAX_SIZE];
    for (int i=0; i<column; i++)
    {
        for (int j=0; j<line; j++)
        {
            *matrixRes[i][j]=matrixA[i][j]+matrixB[i][j];
        }
    }
    return matrixRes;

But there are a few problems with it - I don't understand it, and the function still doesn't work - it returns false results and there is a warning in the compiler "return from incompatible pointer type". Also, I'm not sure how to call it (maybe that's the problem with the solution I found?). I wanted to get some specific value from the array and called the function like this

matrix_add(matrixA, matrixB, column, line)[value][value]);

Where matrixA and B are some 2d arrays, column and line are integer variables. This returns an error (subscripted value is neither array nor pointer nor a vector)

Can you point me in the right direction and tell me how to make this function work (and explain the solution)? MAX_SIZE is predefined value (10) as in this assignment I'm supposed to use static memory allocation (but if you can help me by using dynamic allocation, that's fine) The main function looks like this

int main()
{
    int column_num[2], line_num[2];
    float matrixA[MAX_SIZE][MAX_SIZE], matrixB[MAX_SIZE][MAX_SIZE];
        scanf("%d", &column_num[0]);
        scanf("%d", &line_num[0]);
        matrix_load_val(matrixA, column_num[0], line_num[0]);
        scanf("%d", &column_num[1]);
        scanf("%d", &line_num[1]);
        matrix_load_val(matrixB, column_num[1], line_num[1]);


    }
    for (int i=0; i<column_num[0]; i++)
    {
        for(int j=0; j<line_num[0]; j++)
        {
            printf("%0.5g\n", matrix_add(matrixA, matrixB, i, j));
        }
    }

matrix_load_val is a procedure which asks the user for values and puts them in a resultant matrix (it works for sure, tested)

2 Answers

Your attempt isn't too far off. You have a viable idea to declare a static array and "return it," but first we need to understand what that means.

In C, array types are strange beasts. You can't directly return an array of values like you can in other languages. Instead, you return a pointer. We say the array type decays to a pointer. For one-dimensional arrays, this isn't too scary:

float *get_array(void) {
    static float my_array[2] = { 1, 2 };
    return my_array;
}

float *result = get_array();

For multidimensional arrays, the decay is much trickier and uglier:

Note that when array-to-pointer decay is applied, a multidimensional array is converted to a pointer to its first element (e.g., a pointer to its first row or to its first plane): array-to-pointer decay is applied only once.

To return a pointer to a two-dimensional array, the syntax is:

float (*get_array(void))[2] {
    static float my_array[2][2] = { { 1, 2 }, { 3, 4 } };
    return my_array;
}

float (*result)[2] = get_array();

Applying this, we can tweak your code to make it work (some braces omitted for brevity):

float (*matrix_add(float matrixA[MAX_SIZE][MAX_SIZE], float matrixB[MAX_SIZE][MAX_SIZE], int column, int line))[MAX_SIZE]
{
    static float matrixRes[MAX_SIZE][MAX_SIZE];
    for (int i = 0; i < column; ++i)
        for (int j = 0; j < line; ++j)
            matrixRes[i][j] = matrixA[i][j] + matrixB[i][j];
    return matrixRes;
}

However, a more idiomatic C pattern for this type of thing is to have the caller pass in a pointer to the output array. The function then populates this array. This is called an output parameter. This also eliminates the static variable and its associated issues (such as thread safety and subsequent calls clobbering the results of previous calls).

void matrix_add(
    const float matrixA[MAX_SIZE][MAX_SIZE], /* "input parameter" */
    const float matrixB[MAX_SIZE][MAX_SIZE], /* "input parameter" */
    float matrixRes[MAX_SIZE][MAX_SIZE], /* "output parameter" */
    int column,
    int line)
{
    for (int i = 0; i < column; ++i)
        for (int j = 0; j < line; ++j)
            matrixRes[i][j] = matrixA[i][j] + matrixB[i][j];
}

Notice we've also made the input parameters const to reflect the fact that the function doesn't modify those arrays. This makes it clear from the function's prototype which are the input and which are output parameters.

* I also took the liberty of reformatting a bit, and of changing i++ to ++i because it's a good habit, although it makes no difference in this particular case.

I recommend that you pass another matrix to the function which can be used to populate the result:

void matrix_add(float matrixA[MAX_SIZE][MAX_SIZE], float matrixB[MAX_SIZE][MAX_SIZE], float matrixRes[MAX_SIZE][MAX_SIZE], int column, int line)
{
    for (int i=0; i<column; i++)
    {
        for (int j=0; j<line; j++)
        {
            matrixRes[i][j]=matrixA[i][j]+matrixB[i][j];
        }
    }
}

After you call matrix_add, matrixRes will have the results. This works because you're passing the address of matrixRes to matrix_add, that is, matrixRes is not local to matrix_add as in the case of column and line.

Related