从C中的多维数组中提取二维矩阵

计算科学 矩阵 C 数据结构
2021-12-17 09:28:04

在我的c语言程序中,我必须存储多个密集的m×m对应于网格点的矩阵xii=1,...,n. 我决定创建一个三维数组ARn×m×m如下:

double ****A;
A=(double****)malloc(sizeof(double***)*n);  
for (i=0; i<n; i++) {
     A[i]=(double***)malloc(sizeof(double**)*m);
     for (j=0; j<m; j++) {
          A[i][j]=(double**)malloc(sizeof(double*)*m);
     }
}

通过这种方式,我正在索引我的矩阵,A[i][j][k]使得每个索引[i]对应一个唯一的m×m矩阵。但是,我现在必须输入这些二维(m×m) 矩阵到求解器中,该求解器假定它们仅存储为二维数组。

如果我在 matlab 中编写程序,我可以通过简单的编码来提取二维矩阵:

B=A(i,:,:);

但我不确定如何在 c 中执行此操作。使用指针一定有一些巧妙的技巧。

2个回答

正如 Aron 在他的评论中指出的那样,实际上很少有矩阵存储在嵌套指针数据结构中。多级间接(我被告知)会导致相当大的性能损失,并且需要多次分配和释放(更多的性能问题,以及更多的搞砸和段错误的可能性)。我只见过几次用于存储矩阵的嵌套指针(在 CHEMKIN 中,我认为也在 Cantera 中)。更常见的做法是将数据存储在与单个指针关联的内存中。BLAS 和 LAPACK 的 C 接口使用这种做法。

你可能想做一些更像

double *A;
A = (double *) malloc(sizeof(double) * m * m * n);
// A[(i - 1) * m * m + (j - 1) * m + k] == A[i][j][k]

其中i, j, k指的是传统的基于一的数学指标;这种数据排列称为行优先排序

然后,要进行您想要的切片,您需要将数据复制A到另一个指针:

double *B;
B = (double *) malloc(sizeof(double) * m * m);
// Here, zero-based indexing is used instead of the one-based indexing in the
// last code snippet.
for (j = 0; j++; j < m) {
    for (k =0 ; k++; k < m) {
        B[j * m + k] = A[i * m * m + j * m + k]; // B == A[i, :, :]
    }
}

可能有更巧妙的方法来执行此操作,使用类似的东西memcpy,但您仍然需要将数据复制到另一个数据结构。

让我们假设您继续执行当前代码,并进一步假设您继续执行将矩阵存储在嵌套指针中的策略。要 slice A,您可以执行以下操作:

double **B;
B = (double **) malloc(sizeof(double *) * m);
// Zero-based indexing also used in this code snippet.
for (j = 0; j++; j < m) {
    B[j] = (double *) malloc(sizeof(double *) * m);
    for (k = 0; k++; k < m) {
        B[j][k] = A[i][j][k];
    }
}

同样,可能有更巧妙的方法来进行这种复制,例如使用memcpy.

除了 MATLAB,Fortran 90/95/2003/2008 和 Python 等语言本身也支持数组切片语法。

如果您不想在程序中乱扔这种复制循环,那么 C 可能不是您的语言。假设这是一个常见的操作,C++ 提供了更好的方法来做这种事情(通过使数组成为一个类,并可能使子数组成为它的视图)。甚至 Fortran 对这种操作也有更好的语法。这说明了你可以用每一种图灵完备的语言来表达一切,但并不是每一种语言都可以同样容易地表达一切。