Reputation: 807
I have saved multidimensional arrays in Matlab before (e.g. an array A
that has size 100x100x100) using a .mat file and that worked out very nicely.
What is the best way to save such multidimensional arrays in C? The only way I can think of is to store it as a 2D array (e.g. convert a KxNxM array to a KNxM array) and be careful in remembering how it was saved.
What is also desired is to save it in a way that can be opened later in Matlab for post-processing/plotting.
Upvotes: 3
Views: 4366
Reputation: 283664
C handles multidimensional arrays (double array[K][M][N];
) just fine, and they are stored contiguously in memory the same as a 1-D array. In fact, it's legal to write double* onedim = &array[0][0][0];
and then use the same exact memory area as both a 3-D and 1-D array.
To get it from C into matlab, you can just use fwrite(array, sizeof array[0][0][0], K*M*N*, fptr)
in C and array = fread(fileID, inf, 'real*8')
in MatLab. You may find that the reshape
function is helpful.
Upvotes: 2
Reputation: 123468
C does 3D arrays just fine:
double data[D0][D1][D2];
...
data[i][j][k] = ...;
although for very large arrays such as in your example, you would want to allocate the arrays dynamically instead of declaring them as auto
variables such as above, since the space for auto
variables (usually the stack, but not always) may be very limited.
Assuming all your dimensions are known at compile time, you could do something like:
#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);
}
This will allocate a D0xD1xD2 array from the heap, and you can access it like any regular 3D array.
If your dimensions are not known until run time, but you're working with a C99 compiler or a C2011 compiler that supports variable-length arrays, you can do something like this:
#include <stdlib.h>
...
size_t d0, d1, d2;
d0 = ...;
d1 = ...;
d2 = ...;
...
double (*data)[d1][d2] = malloc(sizeof *data * d0);
if (data)
{
// same as above
}
If your dimensions are not known until runtime and you're working with a compiler that does not support variable-length arrays (C89 or earlier, or a C2011 compiler without VLA support), you'll need to take a different approach.
If the memory needs to be allocated contiguously, then you'll need to do something like the following:
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);
}
Note that you have to map your i
, j
, and k
indices to a single index value.
If the memory doesn't need to be contiguous, you can do a piecemeal allocation like so:
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();
}
}
}
}
}
}
and deallocate it as
for (i = 0; i < d0; i++)
{
for (j = 0; j < d1; j++)
{
free(data[i][j]);
}
free(data[i]);
}
free(data);
This is not recommended practice, btw; even though it allows you to index data
as though it were a 3D array, the tradeoff is more complicated code, especially if malloc
fails midway through the allocation loop (then you have to back out all the allocations you've made so far). It may also incur a performance penalty since the memory isn't guaranteed to be well-localized.
EDIT
As for saving this data in a file, it kind of depends on what you need to do.
The most portable is to save the data as formatted text, such as:
#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");
}
}
This writes the data out as a sequence of floating-point numbers, with a newline at the end of each row, and two newlines at the end of each "page". Reading the data back in is essentially the reverse:
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]);
}
Note that both of these snippets assume that the array has a known, fixed size that does not change from run to run. If that is not the case, you will obviously have to store additional data in the file to determine how big the array needs to be. There's also nothing resembling error handling.
I'm leaving a lot of stuff out, since I'm not sure what your goal is.
Upvotes: 6
Reputation: 33273
c can handle 3-dimensional arrays, so why don't use that?
Writing it on a .mat
file is a little bit of work, but it doesn't seem too difficult.
The .mat
format is described here.
Upvotes: 2
Reputation: 21966
Triple pointer:
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));
}
}
This way the method to access at each value if quite intuitive: X[i][j][k].
If instead you want, you can use an unique array:
double* X;
X=(double*)malloc(n*m*k*sizeof(double));
And you access to each element this way:
X[i*n*m+j*n+k]=0.0;
If you use a triple pointer, don't forget to free the memory.
Upvotes: -1
Reputation: 399833
Well, you can of course store it as a 3D array in C, too. Not sure why you feel you must convert to 2D:
double data[100][100][100];
This will of course require quite a bit of memory (around 7.6 MB assuming a 64-bit double
), but that should be fine on a PC, for instance.
You might want to avoid putting such a variable on the stack, though.
Upvotes: 2