2

I have a function that takes two 2d matrices of variable dimensions and returns a matrix of equal dimensions.

double (*sumOfMatrices(size_t rows, size_t columns, double matrixA[][columns], double matrixB[][columns]))[] {
    double (*result)[columns]= malloc(rows * sizeof *result);
    for (size_t i = 0; i < rows; i++)
    {
        for (size_t j = 0; j < columns; j++)
        {
            result[i][j]= matrixA[i][j] + matrixB[i][j];
        }
    }
    return result;
}

Then I declare a variable like this

 double (*sumResult)[n]= sumOfMatrices(m, n, matrixA, matrixB);

Is this undefined behavior? The compiler doesn't say anything, yet I feel that initializing a double(*)[n] with a double(*)[] is implicitly promoting the data type. Is there a way that I can return double(*)[columns] instead?

  • 1
    I've never seen anything like this (the `[]` at the end) before: `double (*sumOfMatrices(...))[]{...}` – Fiddling Bits Jun 16 '22 at 19:36
  • A 2-dimensional array is not the same as an array of pointers. You can't initialize one with the other. – Barmar Jun 16 '22 at 19:36
  • @Barmar To my understanding, double(\*)[] is a "pointer to an array of unknown size of doubles" and double(\*)[n] is a "pointer to an array of n doubles." Which is not the same as a pointer to an array of doubles. – Fullaccess Jun 16 '22 at 19:41
  • Right, I misread the code. I thought you wrote `malloc(rows * sizeof (*double))` – Barmar Jun 16 '22 at 19:44
  • 1
    BTW, if you want to put little bits of code in comments, put backticks around it. `*` is used for italic markdown. – Barmar Jun 16 '22 at 19:44
  • @FiddlingBits Tbh, nor have I. I recently learned about them in this [post](https://stackoverflow.com/questions/2828648/how-to-pass-a-multidimensional-array-to-a-function-in-c-and-c) and I'm experimenting a bit. – Fullaccess Jun 16 '22 at 19:45
  • Where do you see it in that question? I searched for all `[]` and didn't see anything that looked like that. – Barmar Jun 16 '22 at 19:47
  • @Barmar That's true, I had to google the syntax to return double(*)[] separately. Let me check my history. [Here](https://stackoverflow.com/questions/10794825/how-to-return-a-two-dimensional-pointer-in-c) it is. – Fullaccess Jun 16 '22 at 19:52
  • @Fullaccess Perhaps it's just me but, even if that's legal, I'd hate to use/see that syntax. – Fiddling Bits Jun 16 '22 at 19:56
  • @Barmar yeah I agree, but I'm trying to familiarize myself with the syntax, so this is just an experiment. I don't think I would ever use this, yet I do want to understand it. – Fullaccess Jun 16 '22 at 20:00
  • Consider using `typeof` to make the declaration more digestible: `typeof(double[])* sumOfMatrices(...)` – tstanisl Jun 16 '22 at 21:44

1 Answers1

3

This code is valid.

The return type of the function is double (*)[], i.e. a pointer to an array of unspecified size of type double. The return statement in this function is converting a double (*)[columns] to that type, and the assignment of the return value in the calling function performs the opposite conversion.

Two pointer types are compatible if they point to compatible types. So now we compare the types double [columns] and double []. Two arrays are compatible if the element types are compatible and, if both specify a size, that the sizes are the same. Since only one specifies a size, the array types are compatible, and therefore so are the pointers to the arrays.

Sections 6.7.6.1p2 and 6.7.6.2p6 of the C standard spell out this compatibility in more detail:

6.7.6.1p2

For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.

6.7.6.2p6

For two array types to be compatible, both shall have compatible element types, and if both size specifiers are present, and are integer constant expressions, then both size specifiers shall have the same constant value. If the two array types are used in a context which requires them to be compatible, it is undefined behavior if the two size specifiers evaluate to unequal values.

So let's say n is 5. The function then creates a pointer to an array whose type is double (*)[5]. This type is converted to double (*)[] when it is returned from the function, then converted back to double (*)[5] when assigned to sumResult whose type matches the original type.

So both conversions are valid, and use of sumResult is valid.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • ty for the answer. I have a question though, given that I could not find this in the c99 standard, Does that mean that I have to cast `double(*)[]` to `double(*)[n]` before assigning it for this code to be c99 compliant? – Fullaccess Jun 16 '22 at 21:00
  • @Fullaccess No cast needed since the types are compatible. – dbush Jun 16 '22 at 21:01
  • You passed a link to the c2x standard. I couldn't find those sections (6.7.6.1) in the [c99](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf) standard, so I was wondering if the same reasoning still applies. – Fullaccess Jun 16 '22 at 21:03
  • @Fullaccess In c99 the sections are 6.7.5.1p2 and 6.7.5.2p6. – dbush Jun 16 '22 at 21:05