1

I've been at this for a couple days now, have tried every variation I can think of, and looked at countless examples. I just can't get it working.

I'm trying to make a mexFunction to call from matlab. This mexFunction calls into another C function I have, lets call it retrieveValues, and returns an array and the length of that array. I need to return both of those back to the matlab function, which as I understand it, means I need to put them in the plhs array.

I call my mexFunction from matlab like this:

[foofooArray, foofooCount] = getFoo();

Which to my understanding, means that nlhs = 2, plhs is an array of length 2, nrhs = 0, and prhs just a pointer.

Here's my code for the mexFunction:

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray* prhs[]) 
{
    foo* fooArray
    int fooCount

    plhs = mxCreateNumericMatrix(1, 2, mxUINT64_CLASS, mxREAL);  
    //feels like I shouldn't need this

    retrieveValues(&fooArray, &fooCount);

    plhs[0] = fooArray;
    plhs[1] = fooCount;
}

Running the matlab program gets me One or more output arguments not assigned during call

I've tested and confirmed that the values are being returned from retrieveValues correctly.

Nealon
  • 2,213
  • 6
  • 26
  • 40
  • As declared in the C code, `plhs` and `prhs` are arrays of pointers, not pointers to arrays. Also, when you assign to `plhs` you only change the *local* variable `plhs`, not what the calling function passed to you. – Some programmer dude Jan 23 '14 at 13:51
  • @JoachimPileborg meaning...? – Nealon Jan 23 '14 at 13:55
  • Maybe you should go back and read some of the documentation about mex-files and have a look at the numerous examples. Most importantly, you can't return anything else to matlab but `mxArray`s. Neither objects of type `foo` or primitive types such as `int`. – sebastian Jan 23 '14 at 14:18
  • @sebastian I know that for a fact to be false, as I have read the documentation, examples, and have several working examples that return both arrays and `int`s – Nealon Jan 23 '14 at 14:21

2 Answers2

6

You are correct that the plhs = mxCreateNumericMatrix(...) is not needed. Also, note that nlhs is the number of left-hand-sides you supply in MATLAB - so in your case, you're calling it with 2 left-hand-sides. Here's how to return trivial scalar values:

plhs[0] = mxCreateDoubleScalar(2);
plhs[1] = mxCreateDoubleScalar(3);

To handle your actual return values, you'll need to do something to copy the values out of foo and into a newly-created mxArray. For example, if your function returned doubles, you might do this:

double * values;
int numValues;
myFcn(&values, &numValues);

/* Build a 1 x numValues real double matrix for return to MATLAB */
plhs[0] = mxCreateDoubleMatrix(1, numValues, mxREAL);

/* Copy from 'values' into the data part of plhs[0] */
memcpy(mxGetPr(plhs[0]), values, numValues * sizeof(double));

EDIT Of course someone somewhere needs to de-allocate values in both my example and yours.

EDIT 2 Complete executable example code:

#include <string.h>
#include "mex.h"

void doStuff(double ** data, int * numData) {
    *numData = 7;
    *data = (double *) malloc(*numData * sizeof(data));
    for (int idx = 0; idx < *numData; ++idx) {
        (*data)[idx] = idx;
    }
}

void mexFunction( int nlhs, mxArray * plhs[],
                  int nrhs, const mxArray * prhs[] ) {
    double * data;
    int numData;
    doStuff(&data, &numData);
    plhs[0] = mxCreateDoubleMatrix(1, numData, mxREAL);
    memcpy(mxGetPr(plhs[0]), data, numData * sizeof(double));
    free(data);
    plhs[1] = mxCreateDoubleScalar(numData);
}
Edric
  • 23,676
  • 2
  • 38
  • 40
  • extrapolating, to get `numValues` back, I would do `memcpy(mxGetPr(plhs[1]), numValues, int);`? – Nealon Jan 23 '14 at 14:10
  • You could do it more simply by doing `plhs[1] = mxCreateDoubleScalar(numValues);` – Edric Jan 23 '14 at 14:23
  • Not surprising. It's meant as an example. You need to carefully adapt it to your situation, and make sure you're allocating and deallocating memory in the right places. – Edric Jan 23 '14 at 14:36
  • I'm kind of lost, which is why I'm asking in the first place, could you possibly go into more detail? I believe I gave enough information, and if not, please tell me what more you need. – Nealon Jan 23 '14 at 14:39
  • I posted similar code few minutes after you. +1 for being first :) – Amro Jan 23 '14 at 15:28
2

Here is an example:

testarr.cpp

#include "mex.h"
#include <stdlib.h>
#include <string.h>

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray* prhs[])
{
    // validate number of arguments
    if (nrhs != 0 || nlhs > 2) {
        mexErrMsgTxt("Wrong number of arguments");
    }

    // create C-array (or you can recieve this array from a function)
    int len = 5;
    double *arr = (double*) malloc(len*sizeof(double));
    for(int i=0; i<len; i++) {
        arr[i] = 10.0 * i;
    }

    // return outputs from MEX-function
    plhs[0] = mxCreateDoubleMatrix(1, len, mxREAL);
    memcpy(mxGetPr(plhs[0]), arr, len*sizeof(double));
    if (nlhs > 1) {
        plhs[1] = mxCreateDoubleScalar(len);
    }

    // dellocate heap space
    free(arr);
}

MATLAB:

>> mex -largeArrayDims testarr.cpp
>> [a,n] = testarr
a =
     0    10    20    30    40
n =
     5
Amro
  • 123,847
  • 25
  • 243
  • 454
  • holy hell, that worked, mind telling me the difference between yours and Edrics solution? – Nealon Jan 23 '14 at 15:42
  • its pretty much the same. Not that I'm complaining, but why accept my answer over his? he was the first to post the answer with more explanations :) – Amro Jan 23 '14 at 15:47
  • yours worked and his didnt, I really don't know why, I'm testing things now. – Nealon Jan 23 '14 at 15:48
  • I don't know, both are working fine for me... Are you compiling with a C89 compiler? those can be annoying about where you are allowed to put variable declarations: http://stackoverflow.com/a/8474123/97160 – Amro Jan 23 '14 at 16:00
  • I just ran his again and it worked, sorry, but im gonna give him the credit on this one :D – Nealon Jan 23 '14 at 16:03