Matrix转换从Java移植到C,不兼容的类型问题

And*_*eaF 4 c java porting matrix

我必须在C中移植一些Java方法,有一个Java背景但我在C编程中是一个总的菜鸟

在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;
}
Run Code Online (Sandbox Code Playgroud)

我的C移植尝试

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;
}
Run Code Online (Sandbox Code Playgroud)

这不起作用,并获得不兼容的类型错误.

我的2个问题

1)我应该如何修复我的代码?谷歌搜索我已经看到一些关于在C中返回矩阵的问题,但不是很清楚,并且在大多数情况下建议使用一种不暗示使用返回的方法.

2)我已经看到,C中的这种操作通常是在没有返回类型方法的情况下编写的,例如,对常量进行操作的void方法或者直接在main中编写代码.为什么?

编辑

按照我的建议,我试图编码

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;
}
Run Code Online (Sandbox Code Playgroud)

但不幸的是,当我调用trasposition方法时程序崩溃了.

PS我想用标准C编译代码(不是在C99中)

Fil*_*ves 6

严格来说,使用指向浮点指针的答案在技术上并不正确,因为浮点数的二维数组与指向浮点数的指针不同.

这将是等效的C代码:

#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;
}
Run Code Online (Sandbox Code Playgroud)

这适用于指针:函数内的第一行为5000 x 3000的2D数组分配空间,在Java代码中生成副本,并返回指向新数组的指针.请注意,完成后必须释放内存(通过调用free()).

该函数返回一个指向数组的指针,这意味着你必须像这样使用它:

float (*array)[5000][3000] = transpose(m, n, Xy);
Run Code Online (Sandbox Code Playgroud)

然后你可以使用i,j从新数组访问元素(*array)[i][j].

要免费,请执行以下操作:

free(array);
Run Code Online (Sandbox Code Playgroud)

最后,请记住使用C99支持编译它 - 由于Xy参数列表中的可变长度数组,您需要它.如果你正在使用gcc,这可以实现-std=c99

在其他答案中提出的解决方案可能足以满足您的目的,但请记住,使用float **一个2D数组有一些警告和"陷阱".例如,使用该float **解决方案,您必须array[i]在释放array自己之前手动释放每个位置; sizeof不会告诉你"模拟"2D数组的真实大小,并且浮点数不会连续存储在内存中.

2)我已经看到,C中的这种操作通常是在没有返回类型方法的情况下编写的,例如,对常量进行操作的void方法或者直接在main中编写代码.为什么?

关于直接编写代码的部分main()并不常见.也许您刚看到一些教程示例.在较大的程序中,一般而言,这当然不在内部main().

如果您不想分配内存,那么在没有返回类型的情况下编写它可能很有用:您可以将其留给调用者.这很重要,因为您不会释放释放在调用者上分配的内存的负担.相反,您会收到一个指向已分配的内存缓冲区的指针,由调用者提供给您,并将结果写入其中.在内存管理方面,这通常是一种优越的方法,但当然,许多设计选择和少量细节都可以迅速改变这一点.

更新(如何在没有C99支持的情况下编译它):

好吧,这里的问题是Xy可能是一个任意长度的2D数组,也就是说,你想transpose()任何 2D数组调用(这就是你给它mn维度的原因).

C没有将任意大小的2D数组传递给函数的直接方法.在C99中添加了这种支持.如果你想在C89中这样做,一个已知的解决方法是使用数组在连续的内存位置线性布局的事实,因此使用它就好像它是1D m*n浮点数组.换句话说,您可以滚动自己的索引.由于C数组以行主顺序存储,Xy[i][j]因此相同Xy_flat[i*n+j].因此,实际上,transpose()接收指向第一个元素的指针Xy,并将其视为Xy一维数组.我们只需要替换Xy[i][j]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;
}
Run Code Online (Sandbox Code Playgroud)

对于来自Java的人来说,这可能看起来很奇怪而且微不足道,但C通常在较低级别工作.

要使用此函数,您必须为其指定第一个元素Xy.这是一个例子:

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);
Run Code Online (Sandbox Code Playgroud)

如果(*array)[5000][3000]由于固定的硬编码维度而不想遍布整个代码,您当然可以在其他答案中使用这些解决方案,但始终要记住指向指针的指针float和2D数组之间的差异.彩车.由于您似乎更喜欢这种方法,因此以下是代码的外观:

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;
}
Run Code Online (Sandbox Code Playgroud)

我冒昧地改变你allocate_mem_m()只接收尺寸,然后用指定的内存返回指针.我认为当你使用它时会开始变得有点过于复杂float ***.这不是必要的.

作为建议,我同样会添加一个free_mem_m()来简化释放已分配内存的过程:

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

这是完整的代码清单:

#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;
}
Run Code Online (Sandbox Code Playgroud)

并举例说明:

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;
}
Run Code Online (Sandbox Code Playgroud)

请注意,transpose()假设为方形矩阵(因为您nm浮点数分配了一个位置块).如果要将其与矩形矩阵一起使用,则必须分配m块来保存n浮点数.

现场演示工作:http://ideone.com/CyNdpn

最后的注意事项:将2D阵列视为一维阵列的黑客行为既旧又棘手; 它通常被认为是不好的做法(在我看来),你应该避免这种聪明的代码.但是如果你不想使用C99功能,那么这就是你剩下的.

对于感兴趣的读者,冒着成为垃圾邮件发送者的风险,我在我的博客中写了两篇关于将这个想法概括为具有N维的任意数组的文章.它更深入地说明了为什么需要这样做,以及如何做到这一点:http://codinghighway.com/?p = 1159http://codinghighway.com/?p=1206