I've been trying to find documentation on how the field names are managed with the structure creating functions in mex. Are the field name character arrays copied before being stored internally. Do the character array pointers need to point to the first character of Matlab managed memory (e.g. initialized via mxMalloc)? The only example I could find online was the phonebook.c, which took the string from another Matlab managed variable.
MATLAB: MxCreateStructArray and mxCreateStructMatrix field name memory management
mex
Related Solutions
Here is an example of a MEX-file that creates a MATLAB structure with two fields and passes it to the output argument when called with one. The MEX-file MYMEX should be able to create a structure that has two fields: a double array and a character array. Data is assigned to these and returned to the MATLAB workspace.
//This program creates a structure and returns it to MATLAB.#include "mex.h"void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[]){ //DATA mxArray *mydouble,*mystring; double *dblptr; int i; const char *fieldnames[2]; //This will hold field names. //PROGRAM if((nlhs!=1)||(nrhs!=0)) { mexErrMsgTxt("One output and no input needed"); return; } //Create mxArray data structures to hold the data //to be assigned for the structure. mystring = mxCreateString("This is my char"); mydouble = mxCreateDoubleMatrix(1,100, mxREAL); dblptr = mxGetPr(mydouble); for(i = 0; i<100; i++) dblptr[i] = (double)i; //Assign field names fieldnames[0] = (char*)mxMalloc(20); fieldnames[1] = (char*)mxMalloc(20); memcpy(fieldnames[0],"Doublestuff",sizeof("Doublestuff")); memcpy(fieldnames[1],"Charstuff", sizeof("Charstuff")); //Allocate memory for the structure plhs[0] = mxCreateStructMatrix(1,1,2,fieldnames); //Deallocate memory for the fieldnames mxFree( fieldnames[0] ); mxFree( fieldnames[1] ); //Assign the field values mxSetFieldByNumber(plhs[0],0,0, mydouble); mxSetFieldByNumber(plhs[0],0,1, mystring); //NOTE: mxSetFieldByNumber(..) will automatically take care // of allocating required memory for the fields. }//mexFunction(..)
You can't re-use mxArray variables like you are doing when you are building a cell or struct array in a mex routine. There is an official way to fix this, and an unofficial way to fix this. The official way, which has the downside of requiring a deep data copy, is:
mxSetField(subMexMsg, 0, "field3", inputMxArray); mxSetField(mexMsg, 0, "field1", subMexMsg); mxSetField(mexMsg, 0, "field2", mxDuplicateArray(inputMxArray));
That is, every time you re-use a variable as a cell or struct element, you must actually use a deep data copy of it. Not very memory efficient if you have large variables, but that is the way it is. The reason your code is seg faulting is because when the 1st reference to inputMxArray gets destroyed, the memory for it is actually free'd. Then when the 2nd reference to inputMxArray gets destroyed, the memory for it has already been free'd so invalid memory is accessed. MATLAB didn't know there was another reference to the variable in memory when the 1st reference was destroyed.
MATLAB can, and does at the m-file level, re-use variables the way you are doing, but it increments a "reference count" for the variable to keep track of how many copies are around in cell and struct variables. It does this automatically in the background. That way, when variables get cleared, memory doesn't actually get free'd until the last reference copy gets cleared. I.e., when the 1st reference to inputMxArray gets destroyed, the only thing that happens is the reference count gets decremented by 1. No memory is free'd. When the 2nd reference to inputMxArray gets destroyed, the memory actually gets free'd since it is the last copy in memory.
There is no official way to duplicate this behavior in a mex routine using only official API routines. There is an unofficial mex routine called mxCreateReference, that will do this for you (i.e., increment the reference count by 1 instead of creating a deep data copy). To use it, simply include the prototype and call it (but you will be departing from official library code). The mxCreateReference function is intended specifically for re-using variables in cell or struct variables. E.g.,
mxArray *mxCreateReference( mxArray * ); : mxSetField(subMexMsg, 0, "field3", inputMxArray); mxSetField(mexMsg, 0, "field1", subMexMsg); mxSetField(mexMsg, 0, "field2", mxCreateReference(inputMxArray));
The return value (mxArray address) is the same as the input value.
Unfortunately, TMW has removed mxCreateReference in later versions of MATLAB. The only recourse left to the programmer at this point would be to hack into the mxArray to bump up the reference count manually. Let me know if you need this.
For comparison, mxSetField, mxSetFieldByNumber, and mxSetCell do the following to the input variable:
1) Changes the variable type to 3 (SUB_ELEMENT)2) Removes the variable address from the garbage collection
Best Answer