wsj
wsj

Reputation: 717

Dereference Pointer to MxArray

I am confronting some pointer confusion:

I have some (Numerical Recipes) C-function fitexy(in, &out) that I would like to compile as a .mex file to call it from matlab. However, I can not get the gateway routine to access the Pointer to out so that it is passed to plhs[0], how do I do that?

The closest I get (in the sense of the least confusing error message) is this:

void mexFunction( int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[]){
float *in;
float out;

in      = (float *)mxGetData(prhs[0]);
plhs[0] = mxCreateNumericMatrix(1,1,mxSINGLE_CLASS,mxREAL);
out     = (float *)mxGetData(plhs[0]);

fitexy(in, &out);

printf("out = %lf", &out); /*Prints the correct result to the screen*/
}

This results in an error message on compiling:

error: incompatible types when assigning to type ‘float’ from type ‘float *’

Which in not too surprising to me, but not very helpful either. I tried to cast / dereference the output of mxGetData(plhs[0]),

out     = (float &)mxGetData(plhs[0]);

which seems to be kind of nonsense,

out     = (float)mxGetData(plhs[0]);

which conflicts with out being a variable and mxGetData(plhs[0]) a pointer.

I already found Save a variable (float *) to plhs and How to return a float value from a mex function, and how to retrieve it from m-file?, but they both deal with casting rather than dereferencing .

I understand cannot convert parameter 2 from 'mxArray **' to 'mwArray &', but it does not help me, because I can not (i.e. would prefer not to) change the call to my C-routine.

Any help is warmly appreciated, thank a lot!

Upvotes: 2

Views: 657

Answers (2)

Amro
Amro

Reputation: 124563

Suppose you have a C function fit_line with the following signature:

void fit_line(float x[], float y[], int n, float *a, float *b);

It takes two input data arrays x and y of length n, and fits a straight line y = a*x + b in the least-squares sense by computing the quatities a and b.

Here is how I would write the MEX function:

mex_fit_line.c

#include "mex.h"

EXTERN_C void fit_line(float x[], float y[], int n, float *a, float *b);

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    /* validate inputs */
    if (nrhs!=2 || nlhs>2)
        mexErrMsgIdAndTxt("mex:err", "wrong num args");
    if (!mxIsSingle(prhs[0]) || mxIsComplex(prhs[0]) || mxIsSparse(prhs[0]) ||
        !mxIsSingle(prhs[1]) || mxIsComplex(prhs[1]) || mxIsSparse(prhs[1]))
        mexErrMsgIdAndTxt("mex:err", "expecting dense real single arrays");
    if (mxGetNumberOfElements(prhs[0]) != mxGetNumberOfElements(prhs[1]))
        mexErrMsgIdAndTxt("mex:err", "length dont match");

    /* get data arrays */
    mwSize len = mxGetNumberOfElements(prhs[0]);
    float *x = (float*) mxGetData(prhs[0]);
    float *y = (float*) mxGetData(prhs[1]);
    if (x==NULL || y==NULL) mexErrMsgIdAndTxt("mex:err", "null ptr");

    /* call external function */
    float a, b;
    fit_line(x, y, len, &a, &b);

    /* assign output */
    plhs[0] = mxCreateNumericMatrix(1, 1, mxSINGLE_CLASS, mxREAL);
    *((float*) mxGetData(plhs[0])) = a;
    if (nlhs>1) {
        plhs[1] = mxCreateNumericMatrix(1, 1, mxSINGLE_CLASS, mxREAL);
        *((float*) mxGetData(plhs[1])) = b;
    }
}

After we compile it, we can call the MEX function from MATLAB as:

% some random data
x = randn(100,1,'single');
y = -1.5*x + 1 + randn(size(x),class(x))*0.9;

% fit least-square line
[a,b] = mex_fit_line(x,y);

% plot data and fitted line
xx = linspace(min(x), max(x), 50);
yy = a*xx + b;
plot(x, y, 'b.')
line(xx,yy, 'Color','r')
axis equal, legend({'data', 'LS line'})
title(sprintf('y = %.2f*x + %.2f', a, b)), xlabel('X'), ylabel('Y')

plot

Upvotes: 2

glglgl
glglgl

Reputation: 91017

Why don't you just define out to be a pointer?

float * out;

This way you can easily do

out     = (float *)mxGetData(plhs[0]);

and you can use the out for writing a result value. If I am not mistaken about the fitexy() function, you can call it with

fitexy(in, out);

.

Upvotes: 3

Related Questions