Data from MEX-File to MATLAB
1 view (last 30 days)
Show older comments
Hi folks!
Suppose I want to find all divisors of an input to a MEX-File and return them to the user within MATLAB.
I have written the following simple program (I know it is not the most efficient implementation):
int i;
int counter = 0;
for(i=1;i <=input;i++){
if((input% i) == 0){
plhs[counter] = mxCreateDoubleScalar(i);
counter++;
}
}
Unfortunately, this does not seem to work. What am I doing wrong? What do I need to do to add multiple scalars to the output and why?
Thanks a lot, Jay
3 Comments
Jan
on 6 Jul 2011
Please explain, what "this does not seem to work" means. Does it only seem, that it does not work, but it works? What results do you get? How do you call the function? How many outputs do you try to export?
Accepted Answer
James Tursa
on 6 Jul 2011
Regarding your crash question, consider this line:
plhs[0] = mxCreateNumericArray((input/2)+1,mxGetDimensions(prhs[0]),mxDOUBLE_CLASS, mxREAL);
Here the mxCreateNumericArray function is expecting the first argument to be the desired number of dimensions. Suppose your input was the single number 10 as in your earlier example. Then you would be telling mxCreateNumericArray that the desired number of dimensions of your output will be (10/2)+1 = 6. Now look at the second argument. This needs to be an array of at least size 6, or a pointer to a memory location with at least 6 elements. But what did you pass it? You passed it a pointer to a memory location that has only 2 elements, namely the 1 x 1 dimensions of your input. So mxCreateNumericArray tried to read 6 elements where there were only 2 elements, reads past valid memory, and bombs.
1 Comment
James Tursa
on 6 Jul 2011
P.S. To use dims properly you need to match it up in size with the ndims parameter. e.g.,
mwSize ndims = 3;
mwSize dims[3] = {2,3,4};
plhs[0] = mxCreateNumericArray(ndim,dims,mxDOUBLE_CLASS,mxREAL);
The above would create a 3D double array of size 2 x 3 x 4 initially filled in with zeros.
More Answers (2)
James Tursa
on 6 Jul 2011
The prhs[ ] is an array of input variables, and plhs[ ] is an array of output variables. MATLAB will allocate a fixed number of them based on the calling sequence. You can't go over that amount in your C code. e.g., for the calling sequence on the MATLAB side:
[A B C] = mymexfunction(X,Y)
you will get a prhs array that has been allocated to contain exactly two variables. prhs[0] will be the X input and prhs[1] will be the Y input. The nrhs will tell you how many inputs were on the function call on the MATLAB side, 2 in this case. Likewise, the plhs array will have been allocated to contain exactly three variables, which need to be filled in by you the programmer. So nlhs would be 3 and you would need to create plhs[0], plhs[1], and plhs[2] in your C code and then they would become A, B, and C once the mex functioins returns to MATLAB. In this loop that you show above:
for(i=1;i <=input;i++){
if((input%i) == 0){
plhs[counter] = mxCreateDoubleScalar(i);
counter++;
}
If you pass in a single value of 10 you would end up creating outputs for plhs[1], plhs[2], plhs[5], and plhs[10]. i.e., the user would have had to request 11 separate outputs for this to make sense (and even then you would not be setting 7 other outputs).
What you should be doing instead is creating a single output vector, plhs[0], then use mxGetPr on that to get a pointer to the data area, then use that to fill in values. The tricky part for you will be determining how large to make the output vector. This won't necessarily be easy for a large input value. If this is just a practice mex function you are writing then I would suggest doing something slightly different that has a size that is easy to calculate up front and then work that problem instead.
0 Comments
Jay
on 6 Jul 2011
2 Comments
James Tursa
on 6 Jul 2011
Add this line at the end:
mxSetN(plhs[0],counter);
That will set the size to what you want, but of course the memory is still being used. This will not cause any problems in MATLAB that will crash, but it does use more memory than necessary. If you want to you could copy the data to a new smaller memory block. I would normally advise using mxRealloc in conjunction with mxGetPr and mxSetPr here, but mxRealloc has a bug for some versions of MATLAB and will not recover the memory. So you may need to do this manually via mxMalloc and memcpy.
See Also
Categories
Find more on Additional Math and Discrete in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!