以前、.mat ファイルを使用して多次元配列 (たとえば、A
サイズが 100x100x100 の配列) を Matlab に保存したことがあり、非常にうまく機能しました。
このような多次元配列を C で保存する最良の方法は何ですか? 私が考えることができる唯一の方法は、それを2D配列として保存し(たとえば、KxNxM配列をKNxM配列に変換する)、保存方法を覚えておくことです。
また、後処理/プロットのためにMatlabで後で開くことができる方法で保存することも望まれます。
以前、.mat ファイルを使用して多次元配列 (たとえば、A
サイズが 100x100x100 の配列) を Matlab に保存したことがあり、非常にうまく機能しました。
このような多次元配列を C で保存する最良の方法は何ですか? 私が考えることができる唯一の方法は、それを2D配列として保存し(たとえば、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);
これは推奨される方法ではありません。3D 配列であるかのようにインデックスを付けることができますが、特に割り当てループの途中で失敗した場合data
、トレードオフはより複雑なコードになります (その後、これまでに行ったすべての割り当てを元に戻す必要があります)。また、メモリが適切にローカライズされていることが保証されていないため、パフォーマンスが低下する可能性があります。 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");
}
}
これにより、データが一連の浮動小数点数として書き出されます。各行の最後に改行があり、各「ページ」の最後に 2 つの改行があります。データを読み戻すことは、基本的に逆です。
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 は多次元配列 ( double array[K][M][N];
) を適切に処理し、1 次元配列と同じようにメモリに連続して格納されます。実際、double* onedim = &array[0][0][0];
3 次元配列と 1 次元配列の両方とまったく同じメモリ領域を書き込んで使用することは合法です。
C から matlab に取り込むにはfwrite(array, sizeof array[0][0][0], K*M*N*, fptr)
、C とarray = fread(fileID, inf, 'real*8')
MatLab で使用するだけです。このreshape
機能が役立つ場合があります。
もちろん、C で 3D 配列として格納することもできます。2D に変換する必要があると感じる理由がわからない:
double data[100][100][100];
もちろん、これにはかなりの量のメモリ (64 ビットを想定すると約 7.6 MB double
) が必要ですが、たとえば PC では問題ないはずです。
ただし、そのような変数をスタックに置くことは避けたいと思うかもしれません。
トリプルポインター:
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;
トリプル ポインターを使用する場合は、メモリを解放することを忘れないでください。