Matrix transposition porting from Java to C, incompatible types issue

c, java, matrix, porting

Solution

Strictly speaking, the answers about using pointer to pointer to float are not technically correct, because a 2D array of floats is not the same as a pointer to pointer to float.

This would be the equivalent C code:

#include <stdlib.h>

float (*transpose(int m, int n, float Xy[m][n]))[5000][3000] {
    float (*result)[5000][3000] = malloc(sizeof(*result));
    for(int i = 0; i < m; i++) {
        for(int j = 0; j < n; j++) {
            (*result)[i][j] = Xy[j][i];
        }
    }
    return result;
}

This works with pointers: the first line inside the function allocates space for a 2D array of 5000 by 3000, makes the copy as you have in your Java code, and returns the pointer to the new array. Note that you have to free the memory once you are done with it (by calling `free()`).

The function returns a pointer to an array, which means you'll have to use it like this:

float (*array)[5000][3000] = transpose(m, n, Xy);

And then you can access element `i,j` from the new array using `(*array)[i][j]`.

To free, you do this:

free(array);

Finally, remember to compile this with C99 support - you need it because of the variable length array `Xy` in the parameters list. If you're using gcc, this can be achieved with `-std=c99`

The solution proposed in the other answers may be enough for your purposes, but keep in mind that using a `float **` as a 2D array has a few caveats and 'gotchas'. For example, with the `float **` solution, you'll have to manually free every position in `array[i]` before freeing `array` itself; `sizeof` will not tell you the true size of the "simulated" 2D array, and floats will not be stored in memory contiguously.

2) I have seen that usually this kind of operations in C are written without return type approach e.g. void methods that operate on constants or the code is written directly in main. Why?

The part about code being written directly in `main()` is not very common. Maybe you just saw some tutorial examples. In bigger programs, and in general, this is, of course, not inside `main()`.

Writing it without a return type can be useful if you don't want to have to allocate memory: you leave that up to the caller. This is important, because you don't place the burden of freeing memory you allocated on the caller. Instead, you receive a pointer to an already allocated memory buffer, given to you by the caller, and write the results in there. This is generally a superior approach when it comes to memory management, but of course, lots of design choices and little details can quickly change this.

UPDATE (how to compile it without C99 support):

Well, the problem here is that `Xy` may be a 2D array of arbitrary length, i.e., you want to call `transpose()` with any 2D array (that's why you're giving it `m` and `n` for the dimensions).

C has no direct way of passing arbitrarily sized 2D arrays to a function. Such support was added in C99. If you want to do this in C89, a known workaround is to use the fact that arrays are linearly layed out in contiguous memory positions, and thus use it as if it were a 1D array of `m*n` floats. In other words, you roll your own indexing. Since C arrays are stored in row-major order, `Xy[i][j]` is the same as `Xy_flat[i*n+j]`. So, in effect, `transpose()` receives a pointer to the first element in `Xy`, and treats `Xy` as a 1D array. We just have to replace `Xy[i][j]` with `Xy[i*n+j]`:

/* C89 version */
#include <stdlib.h>

float (*transpose2(int m, int n, float Xy[]))[5000][3000] {
    float (*result)[5000][3000] = malloc(sizeof(*result));
    int i, j;
    for(i = 0; i < m; i++) {
        for(j = 0; j < n; j++) {
            (*result)[i][j] = Xy[j*n+i];
        }
    }
    return result;
}

This may seem weird and non trivial for someone coming from Java, but C usually works at a lower level.

To use this function, you have to give it a pointer to the first element of `Xy`. Here's an example:

float matrix[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
float (*transposed)[5000][3000] = transpose(3, 3, &matrix[0][0]);
/* Use (*transposed)[i][j]... */
free(transposed);

If you don't want to hang around with `(*array)[5000][3000]` all over the code because of the fixed hardcoded dimensions, you can certainly use the solutions in the other answers, but always keeping in mind the differences between a pointer to pointer to `float` and a 2D array of floats. Since you seem to prefer this approach, here's how the code would look like:

float **allocate_mem_m(int m, int n)
{
 int i;
 float **arr = malloc(n*sizeof(*arr));
 for(i=0;i<n;i++)
   {
     arr[i]=malloc(m*sizeof(**arr));
   }
 return arr;
} 


float **transpose(int m, int n, float Xy[]) {
  int i,j;
  float **result = allocate_mem_m(m,n);
  for(i = 0; i < m; i++) {
    for(j = 0; j < n; j++) {
      result[i][j] = Xy[j*n+i];
    }
  }
  return result;
}

I took the liberty to change your `allocate_mem_m()` to receive the dimensions only, and return the pointer with the allocated memory. I think it starts to get a little overly complex when you use `float ***`. That's not necessary.

As a word of advice, I would equally add a `free_mem_m()` to ease the process of freeing the allocated memory:

void free_mem_m(int m, float **array) {
  int i;
  for (i = 0; i < m; i++) {
    free(array[i]);
  }
  free(array);
}

Here's the full code listing:

#include <stdlib.h>

float **allocate_mem_m(int m, int n)
{
 int i;
 float **arr = malloc(n*sizeof(*arr));
 for(i=0;i<n;i++)
   {
     arr[i]=malloc(m*sizeof(**arr));
   }
 return arr;
} 

void free_mem_m(int m, float **array) {
  int i;
  for (i = 0; i < m; i++) {
    free(array[i]);
  }
  free(array);
}

float **transpose(int m, int n, float Xy[]) {
  int i,j;
  float **result = allocate_mem_m(m,n);
  for(i = 0; i < m; i++) {
    for(j = 0; j < n; j++) {
      result[i][j] = Xy[j*n+i];
    }
  }
  return result;
}

And an example usage:

int main(void) {
  float Xy[3][3] = { { 0, 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 } };
  float **transposed = transpose(3, 3, &Xy[0][0]);
  int i, j;
  for (i = 0; i < 3; i++)
    for (j = 0; j < 3; j++)
      printf("%f ", transposed[i][j]);
  printf("\n");
  free_mem_m(3, transposed);
  return 0;
}

Note that `transpose()` assumes a square matrix (because you allocate a block of `n` positions for `m` floats). If you want to use this with rectangular matrixes, you would have to allocate `m` blocks to hold `n` floats instead.

Live demo working: http://ideone.com/CyNdpn

Final note: The hack to treat a 2D array as 1D array is old and tricky; it is generally considered bad practice (in my opinion), and you should avoid this kind of clever code. But if you don't want to use C99 features, this is all you're left with.

For interested readers, at the risk of being a bit of a spammer, I have written 2 articles in my blog about generalizing this idea to arbitrary arrays with N dimensions. It goes a little bit deeper in the technical explanation of why you need to do it, and how to do it: http://codinghighway.com/?p=1159 and http://codinghighway.com/?p=1206

Problem

I have to port some Java methods in C, have a Java background but I'm a total noob in C programming In java ``` float[][] traspose(float Xy[][]) { float result[][]=new float[5000][3000]; for(int i = 0; i < m; i++) { for(int j = 0; j < n; j++) { result[i][j] = Xy[j][i]; } } return result; } ``` My C porting attempt ``` float traspose(int m, int n, float Xy[m][n]) { int i,j; float result[5000][3000]; for(i = 0; i < m; i++) { for(j = 0; j < n; j++) { result[i][j] = Xy[j][i]; } } return result; } ``` This doesn't work and get incompatible types error. My 2 questions 1) How should I fix my code? Googling I have seen some questions about returning matrix in C but not very clear and in most case was suggested to use an approach that doesn't imply the use of return. 2) I have seen that usually this kind of operations in C are written without return type approach e.g. void methods that operate on constants or the code is written directly in main. Why? EDIT Following the suggestions I have tried to code this ``` float **transpose(int m, int n, float Xy[]) { int i,j; float **result = allocate_mem_m(m,n); for(i = 0; i < m; i++) { for(j = 0; j < n; j++) { result[i][j] = Xy[j*n+i]; } } return result; } int main(int argc, char **argv) { printf("Hello World!"); float matrix[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}}; printf("Matrix created\n"); int size=3; print(size, size, matrix); float **transposedmat = transpose(size, size, &matrix[0][0]); printMat(size, size, transposedmat); return 0; } ``` But unfortunately the program crashes when I invoke trasposition method. PS I want to compile the code in standard C (not in C99)

Original source

Related problems