4

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)

Mihu
  • 69
  • 6
  • The usual way to "return" arrays from functions in C is for the caller to allocate the array and pass a pointer to it as an argument to the function. The function then populates the array with the correct values. – TypeIA Nov 01 '18 at 21:19
  • 1
    How about passing the result matrix to `matrix_add`, such as `matrix_add(matrixA, matrixB, matrixResult, column, line)`? `matrix_add` can populate `matrixResult`. – Fiddling Bits Nov 01 '18 at 21:19
  • could you please show the main function or the function where matrixRes is getting copied? – Asheesh Sahu Nov 01 '18 at 21:21
  • I've added the main function – Mihu Nov 01 '18 at 21:29
  • @FiddlingBits I'm not sure how an array which exists only in the function can also be an argument of that function? – Mihu Nov 01 '18 at 21:30
  • @Mihu In this case, the array doesn't only exist in the function because you're passing the address of the array to the function. – Fiddling Bits Nov 01 '18 at 21:40
  • Ok, I understood @FiddlingBits solution and it worked. I still wonder what would the correct implementation of my approach look like (if anyone has the time and wants to present it, feel free) but my problem is solved, thank you very much! – Mihu Nov 01 '18 at 21:42

2 Answers2

3

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.

TypeIA
  • 16,916
  • 1
  • 38
  • 52
2

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.

Fiddling Bits
  • 8,712
  • 3
  • 28
  • 46
  • Thank you, this solves the problem. There's only one thing that still bothers me. Am I correct in thinking that if I declare any function in C, I automatically pass the addresses of the arguments, and not their values? As in I don't have to put the "&" sign - just everytime there is an argument, the compiler takes it's address into the function and then, knowing the address, takes the value? – Mihu Nov 01 '18 at 21:58
  • 1
    Arrays are passed by address implicitly. Most other things but be passed by address explicitly. – Fiddling Bits Nov 01 '18 at 22:01