How do I resize an mxArray
1 visualización (últimos 30 días)
Mostrar comentarios más antiguos
Tim
el 18 de Nov. de 2016
Editada: James Tursa
el 18 de Nov. de 2016
I'm trying to write a C program that reads some data and writes to a mat-file. But I don't know how many elements to allocate for the mxArrays until all of the data has been read. I'm thinking I would allocate the mxArrays in chunks, growing their size as needed but I don't see any mx API function that would do this. Here's a skeleton:
/* Open MAT output file */
pmat = matOpen(ofile, "w"));
NROWS = 10000;
mxA = mxCreateDoubleMatrix(NROWS,1,mxREAL);
a = mxGetPr(mxA);
/* read all data and populate mxArray */
nrec = 0;
while (!EOF)
{
/* read some data from file... */
/* increase size of mxArray if needed */
if (nrec > mxGetM(mxA))
{
mxSetM(mxA,mxGetM(mxA)+NROWS); /* but this doesn't increase the size of the pr array */
???
}
/* add value to my mxArray */
a[nrec++] = mydata;
}
/* write to mat-file */
mxSetM(mxA, nrec);
matPutVariable(pmat, "a", mxA);
matClose(pmat);
mxDestroyArray(mxA);
I know there is mxRealloc, but that allocates by number of bytes. I have tried
mxSetM(mxA,mxGetM(mxA)+NROWS);
mxRealloc((void*)a, mxGetM(mxA)*sizeof(double))
Doesn't work. Program crashes. I would think there must be an easy way to do this by the number of elements but can't seem to find an answer. What am I missing?
0 comentarios
Respuesta aceptada
James Tursa
el 18 de Nov. de 2016
Editada: James Tursa
el 18 de Nov. de 2016
You are missing a step. After you do the mxRealloc, you need to set this new pointer into the mxArray. E.g.,
a = mxRealloc(a, mxGetM(mxA)*sizeof(double));
mxSetPr(mxA,a);
Also, your test is inconsistent. The variable nrec is a 0-based index for C array indexing, but the result of mxGetM is 1-based for MATLAB array indexing. So you should change this:
if (nrec > mxGetM(mxA))
to this:
if (nrec == mxGetM(mxA))
I.e., with your current code nrec is allowed to be equal to mxGetM(mxA), but this is 1 index beyond the actual memory allocated for 0-based indexing.
2 comentarios
James Tursa
el 18 de Nov. de 2016
Editada: James Tursa
el 18 de Nov. de 2016
"... documentation for mxSetDimensions states, "mxSetDimensions allocates heap space to hold the input size array." But then a few lines later states, "mxSetDimensions does not allocate or deallocate any space for the pr or pi arrays." So what does it allocate for? ..."
At the C level, the mxArray structure contains fields for the array size. E.g., a snippet of parts of the structure at the low level looks something like this:
struct mxArray {
:
size_t ndim;
:
union {
size_t M; /* Row size for 2D matrices, or */
size_t *dims; /* Pointer to dims array for nD > 2 arrays */
} Mdims;
size_t N; /* Column size for 2D matrices */
void *pr; /* Pointer to real data (or pointer to cell or field elements */
void *pi; /* Pointer to imag data (or pointer to field information */
:
};
When the object is 2D (i.e., ndim = 2) there are simply numbers stored in the M and N fields. But when the object is nD (i.e., ndims > 2) there is actually memory allocated elsewhere that contains all of the dimensions and the mxArray structure contains a pointer dims to this memory (i.e., a pointer is actually stored in the memory location where the M would have been stored inside the mxArray structure). So if you use mxSetDimensions to change a 2D to a 3D, then an allocation must take place for the dimensions to be stored behind dims. Likewise if you change a 3D to a 2D then a deallocation will take place for the memory behind dims. As a C programmer using the API functions you don't really need to be concerned with this background allocation/deallocation since it will be handled automatically by the API function mxSetDimensions.
This raises the question, what does mxGetDimensions return? For a 2D it will simply return &M (the address of the M field) in the mxArray structure. For a 3D (or higher) array it will return the value of the dims field. There is one exception to this. If you have compiled a mex routine with COMPAT32 on a 64-bit system, then the dimension data inside the mxArray will be 64-bit integers, but the mxGetDimensions routine will return a pointer to 32-bit integers. In this case, the 64-bit integer dimension data must be copied into a 32-bit integer array and the address of that is what is returned. (I suspect this is a newly allocated memory block but I can't confirm this).
The pr and pi fields, as the documentation states, must be manually handled by the programmer for any reallocation. This can actually be a benefit to the C programmer, since that allows you to do things like snip columns off of the end of the array (by changing only N) without physically reallocating any data ... so it is extremely fast.
"... So in my example, am I supposed to use mxFree or mxDestroyArray? ..."
In your example, mxA should have been declared as an (mxArray *) type, so you should be using mxDestroyArray (which you correctly are). You would NOT use mxFree(a) since the memory behind "a" is part of the mxArray mxA (i.e., mxDestroyArray(mxA) will automatically free anything behind pr, pi, jr, jc, dims also).
Más respuestas (0)
Ver también
Categorías
Más información sobre Resizing and Reshaping Matrices en Help Center y File Exchange.
Productos
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!