A
我之前使用 .mat 文件在 Matlab 中保存了多维数组(例如,大小为 100x100x100 的数组),效果非常好。
在 C 中保存此类多维数组的最佳方法是什么?我能想到的唯一方法是将其存储为二维数组(例如,将 KxNxM 数组转换为 KNxM 数组)并小心记住它是如何保存的。
还希望以稍后可以在 Matlab 中打开以进行后处理/绘图的方式保存它。
A
我之前使用 .mat 文件在 Matlab 中保存了多维数组(例如,大小为 100x100x100 的数组),效果非常好。
在 C 中保存此类多维数组的最佳方法是什么?我能想到的唯一方法是将其存储为二维数组(例如,将 KxNxM 数组转换为 KNxM 数组)并小心记住它是如何保存的。
还希望以稍后可以在 Matlab 中打开以进行后处理/绘图的方式保存它。
C 做 3D 数组就好了:
double data[D0][D1][D2];
...
data[i][j][k] = ...;
尽管对于非常大的数组(例如您的示例),您可能希望动态分配数组,而不是auto
像上面那样将它们声明为变量,因为变量的空间auto
(通常是堆栈,但并非总是如此)可能非常有限。
假设您的所有维度在编译时都是已知的,您可以执行以下操作:
#include <stdlib.h>
...
#define DO 100
#define D1 100
#define D2 100
...
double (*data)[D1][D2] = malloc(sizeof *data * D0);
if (data)
{
...
data[i][j][k] = ...;
...
free(data);
}
这将从堆中分配一个 D0xD1xD2 数组,您可以像访问任何常规 3D 数组一样访问它。
如果直到运行时才知道您的尺寸,但您正在使用支持可变长度数组的 C99 编译器或 C2011 编译器,则可以执行以下操作:
#include <stdlib.h>
...
size_t d0, d1, d2;
d0 = ...;
d1 = ...;
d2 = ...;
...
double (*data)[d1][d2] = malloc(sizeof *data * d0);
if (data)
{
// same as above
}
如果直到运行时才知道您的尺寸,并且您正在使用不支持可变长度数组的编译器(C89 或更早版本,或不支持 VLA 的 C2011 编译器),您将需要采用不同的方法。
如果需要连续分配内存,则需要执行以下操作:
size_t d0, d1, d2;
d0 = ...;
d1 = ...;
d2 = ...;
...
double *data = malloc(sizeof *data * d0 * d1 * d2);
if (data)
{
...
data[i * d0 * d1 + j * d1 + k] = ...;
...
free(data);
}
请注意,您必须将 、 和 索引映射i
到j
单个k
索引值。
如果内存不需要连续,您可以像这样进行零碎分配:
double ***data;
...
data = malloc(d0 * sizeof *data);
if (data)
{
size_t i;
for (i = 0; i < d0; i++)
{
data[i] = malloc(d1 * sizeof *data[i]);
if (data[i])
{
size_t j;
for (j = 0; j < d1; j++)
{
data[i][j] = malloc(d2 * sizeof *data[i][j]);
if (data[i][j])
{
size_t k;
for (k = 0; k < d2; k++)
{
data[i][j][k] = initial_value();
}
}
}
}
}
}
并将其释放为
for (i = 0; i < d0; i++)
{
for (j = 0; j < d1; j++)
{
free(data[i][j]);
}
free(data[i]);
}
free(data);
顺便说一句,这不是推荐的做法;即使它允许您data
像 3D 数组一样进行索引,但要权衡的是更复杂的代码,特别是如果malloc
在分配循环中途失败(那么您必须退出到目前为止所做的所有分配)。它也可能会导致性能损失,因为不能保证内存被很好地定位。
编辑
至于将这些数据保存在文件中,这取决于您需要做什么。
最便携的是将数据保存为格式化文本,例如:
#include <stdio.h>
FILE *dat = fopen("myfile.dat", "w"); // opens new file for writing
if (dat)
{
for (i = 0; i < D0; i++)
{
for (j = 0; j < D1; j++)
{
for (k = 0; k < D2; k++)
{
fprintf(dat, "%f ", data[i][j][k]);
}
fprintf(dat, "\n");
}
fprintf(dat, "\n");
}
}
这会将数据作为浮点数序列写出,每行末尾有一个换行符,每个“页面”末尾有两个换行符。读回数据基本上是相反的:
FILE *dat = fopen("myfile.dat", "r"); // opens file for reading
if (dat)
{
for (i = 0; i < D0; i++)
for (j = 0; j < D1; j++)
for (k = 0; k < D2; k++)
fscanf(dat, "%f", &data[i][j][k]);
}
请注意,这两个片段都假定数组具有已知的固定大小,并且不会随运行而改变。如果不是这种情况,您显然必须在文件中存储其他数据以确定数组需要多大。也没有类似于错误处理的东西。
我留下了很多东西,因为我不确定你的目标是什么。
好吧,您当然也可以将其存储为 C 中的 3D 数组。不知道为什么你觉得你必须转换为 2D:
double data[100][100][100];
这当然需要相当多的内存(假设 64 位大约需要 7.6 MB double
),但在 PC 上应该没问题,例如。
不过,您可能希望避免将这样的变量放入堆栈。
C 可以很好地处理多维数组 ( double array[K][M][N];
),它们与一维数组一样连续存储在内存中。事实上,写入double* onedim = &array[0][0][0];
并使用与 3-D 和 1-D 数组相同的内存区域是合法的。
要将其从 C 语言导入 matlab,您可以fwrite(array, sizeof array[0][0][0], K*M*N*, fptr)
在 C 和array = fread(fileID, inf, 'real*8')
MatLab 中使用。您可能会发现该reshape
功能很有帮助。
三重指针:
double*** X;
X= (double***)malloc(k*sizeof(double**));
for(int i=0; i<k;i++)
{
X[i]=(double**)malloc(n*sizeof(double*));
for(int j=0; j<n;j++)
{
X[i][j]=(double*)malloc(m*sizeof(double));
}
}
这种方式访问每个值的方法非常直观:X[i][j][k]。
如果你愿意,你可以使用一个唯一的数组:
double* X;
X=(double*)malloc(n*m*k*sizeof(double));
您可以通过以下方式访问每个元素:
X[i*n*m+j*n+k]=0.0;
如果您使用三重指针,请不要忘记释放内存。