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