GeekCat
GeekCat

Reputation: 409

Calling C++ function in Matlab, deal with 2-dimensional array, pointer of pointer?

I am trying to call a function in C++ in Matlab, I thought I have written my functions properly. The function I want to call, looks like this, it has 8 arguments as input.

void LimitedPrice(double &dMarketPosition, double** dmatLimitPrice, 
                  char* FileID, double* dvecOpen, double* dvecClose, 
                  double** dmatTempData, int tick, double dMaxBarBack)
 {Bla, Bla, Bla}

I want to get 2 values after running this function. Which stored in dMarketPosition, and dmatLimitPrice since they are pointers.

In this function, I have to use some ** (double pointers) to represent my Matrix.

After running this function, dMarketPosition, dmatLimitPrice will store what I want, since they are pointers. I have tested my function and I believed my function are written properly.

Now I am ready to write my mexFunction(). My mex function somehow looks like this

void mexFunction(int nlhs, mxArray *plhs[],
             int nrhs,const mxArray *prhs[])
{
    if(nrhs!=8){
          mexErrMsgIdAndTxt("LimitPrice: ","I want to 8 inputs");
    }
    // I want two output
    if(nlhs!=2) {
        mexErrMsgIdAndTxt("LimitPrice: ","I want to 2 outputs");
    }

   //The first input is a scalar
   double dmarketposition;
   dmarketposition = mxGetScalar(prhs[0]);

   //The second input is a 2-dimensional Matrix
   double **dmatlimitprice;
   *dmatlimitprice = mxGetPr(prhs[1]);

   /*****Assuming I have checked other inputs here properly*****/
   // I want to define my outputs
   // Create 1*1 matrix as output, which is the double value I want 
   plhs[0] = mxCreateDoubleMatrix(1,1,mxREAL);
   //The second output is a two dimensional matrix
   plhs[1] = mxCreateDoubleMatrix(2,(mwSize)4,mxREAL);
   dmarketposition = mxGetScalar(plhs[0]);
   *dmatlimitprice = mxGetPr(plhs[0]);
   // Call the function
   LimitedPrice(dmarketposition, dmatlimitprice, fileid,
   dvecopen, dvecclose, dmattempdata, tick, dmaxbarback);
}

The above function does not seem to work... It seems that in mexFunction(), We would better only pass one-dimensional array, which is double *a like thing.

My key issue is "How can we deal with 2-dimensional array, which is a matrix" in mexFunction().

Upvotes: 1

Views: 1646

Answers (2)

chappjc
chappjc

Reputation: 30579

The only thing that makes an array 2D (or any size other than 1D) is the shape of the array as stored in the mxArray structure. All the data is contiguous. The stride, or step in bytes between columns, of a 2D array in MATLAB (and mxArrays) is always number_of_rows * element_size. For a column-major storage system, that's a way of saying that a contiguous data buffer is used to store all arrays.

Take the basic functions for reading from a mxArray:

double* mxGetPr(const mxArray*);    // get pointer to start of double buffer
void*   mxGetData(const mxArray*);  // get pointer to start of any data-type buffer
size_t  mxGetM(const mxArray*);     // get number of rows
size_t  mxGetN(const mxArray*);     // get number of columns

There is no function like OpenCV's T* ptr<T>(int i) to get a pointer to specified row (or column in MATLAB's case). To get an element, you just have to access location irow + icol*numRows. This is why it is common to have a sub2ind-like function in C/C++:

inline mwSize sub2ind(mwSize irow, mwSize icol, mwSize numRows) {
    return irow + icol*numRows; }

That was generic advice, nothing specific to your code. I'm hesitant to to make specific suggestions since semantics of LimitedPrice() is not clear. The syntax is clear -- it needs a pointer to a pointer -- but often a ** is used to return a new pointer (internally allocated result) rather than to manage a 2D array. If it's 2D data then usually there will be two integral types with it to specify dimensions, but I don't see that.

For the reasons above it's hard to provide more specific help, but here here is a big issue to address:

double **dmatlimitprice;
*dmatlimitprice = mxGetPr(prhs[1]);  // dereferencing uninitialized pointer, ERROR

You could make a double** that acts as an index into the columns of the input matrix (if that is what you actually need!). For example:

size_t numCols = mxGetN(prhs[1]);
double *dlimitBuffer = mxGetPr(prhs[1]);
// Simulate a 2D array:
std::vector<double*> dlimitvec(numCols);
double **dmatlimitprice = &dlimitvec[0]; // or = new double*[numCols]; if you delete[]
for (size_t i=0; i < numCols; ++i)
    datalimitprice[i] = dlimitBuffer + i*numRows;

That's assuming you need a double** where each double* points to the individual columns of some matrix, which is likely not correct, so treat this as an example. You may need to transpose the matrix too.

Also, you make the invalid assignment to *dmatlimitprice twice so it's hard to tell whether you want this as the input or output array.

Upvotes: 1

Shai
Shai

Reputation: 114786

In memory, Matlab stores all mxArrays as one chunk of contiguous memory column by column. In that respect, there is no difference beteween a 1D vector and N-D array, they are all stored as a single chunk of memory.
Consider, for example, the following chunk in memory: { 1, 2, 3, 4, 5, 6, 7, 8 }
It can be treated as a 1-by-8, 8-by-1, 2-by-4, 4-by-2 or even 2-by-2-by-2 array. Changing the shape (reshape-ing) of the array does not require any change to the actual memory where the data is stored, only to the "header" of the mxArray.

What you can do is allocate a 2D matrix internally, call LimitedPrice and then copy the result into the output mxArray converting it from the internal double** representation to double* mxArray representation.


A side note, in your example code you assign dmarketposition and dmatlimitprice twice: once from the first and second inputs and once from the newly allocated outputs - the second assignment simply overrides the first and it seems like your function LimitedPrice will not get the information stored in the mexFunction inputs.

Upvotes: 2

Related Questions