In MEX, how do I populate an array within a struct within plhs?
Show older comments
Presently, I am trying to pass back a struct via plhs[0] out of a C mex file back to MATLAB. Within that struct, I have a double array called PIP that is of size 3, and it is the 8th value within the struct. It crashes at the memcpy line. If any help can be given, it would be appreciated.
double *arrTest = {1, 2, 3};
int pipNumDims = 2;
int pipDims[2] = {3, 1};
mxArray *pipPtr;
size_t pipBytesToCopy;
pipPtr = mxCreateNumericArray(pipNumDims, pipDims, mxDOUBLE_CLASS, mxREAL);
mexPrintf("Set up numeric array\n");
double *startOfPipPtr = (double *)mxGetPr(pipPtr);
pipBytesToCopy = pipDims[0] * mxGetElementSize(pipPtr);
mexPrintf("Pulled start of array\n");
memcpy(startOfPipPtr, arrTest, pipBytesToCopy);
mexPrintf("memory copied from double arr to mex arr\n");
mxSetField(plhs[0],7,"PIP",pipPtr);
mexPrintf("Set mex arr to plhs\n");
double* output7 = (double *)mxGetData(mxGetField(plhs[0],7,"PIP"));
mexPrintf("plhs[0]_PIP: {%f, %f, %f}\n", output7[0], output7[1], output7[2]);
Answers (1)
James Tursa
on 17 Aug 2018
Edited: James Tursa
on 17 Aug 2018
I don't have MATLAB or a C compiler handy at the moment, but here are some suggestions:
1) Don't make assumptions with API function signatures, particularly the pointers. Always use exactly what the doc states:
mxArray *mxCreateNumericArray(mwSize ndim, const mwSize *dims,
mxClassID classid, mxComplexity ComplexFlag);
2) Allocate arrTest properly.
3) You don't show any code creating plhs[0] as a struct. If you have it but didn't post it, then fine. Otherwise you will need to create it using mxCreateStructMatrix or mxCreateStructArray.
E.g.,
double arrTest[] = {1, 2, 3}; // changed to an array (this change is critical)
mwSize pipNumDims = 2; // changed to mwSize (this change not really needed)
mwSize pipDims[2] = {3, 1}; // changed to mwSize (this change could be critical)
The first one could be the cause of the crash, or that last one could be the cause of the crash if an int is not the same length as an mwSize.
To elaborate on that first one, here is your code:
double *arrTest = {1, 2, 3};
You obviously think that this statement will initialize the pointer to point to an area of memory that was allocated and held three double values (1.0, 2.0, 3.0). But this line doesn't do that at all.
This line defines a scalar variable arrTest that is of type ( double * ). Whatever initial values you list on the right hand side will be assigned directly to arrTest. In this case, you assigned it the value 1 (obviously an invalid memory address). Since it is a scalar variable, it only takes one initial value, but you give it three. On some compilers (e.g. MSVC) this statement in and of itself will cause a compile error with a message stating "too many initializers". On other compilers (e.g. MinGW64) this will assign the value 1 to arrTest with only a warning about "int to pointer" conversion and "too many initializers". But in this case the compiler actually hurt you. Instead of getting a compile error that you could fix, it bombed in real time (trying to access memory at address 1).
When you get these types of problems, it helps to mex the file with the -v option (verbose mode) so that you can see all of the warning messages. That would have clued you in to what was happening and why things weren't working as expected.
Categories
Find more on Write C Functions Callable from MATLAB (MEX Files) in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!