can we use matlab engine from a inside a function in C++

1 view (last 30 days)
I compiled a C++ program to sort double values(matlab does the sorting). it works fine. however when i move the code related to matlab computation to a function, it gives erroneous results.
following is the code with both the formats in a single file. when i execute matlab functions from main it works, when i execute the matlab part from a function(call_matlab_processing) it gives random results.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "engine.h"
#include <iostream>
#include <vector>
#define BUFSIZE 256
int call_matlab_processing(double double_array[], int size_double_array,double * sorted, double * indices_cpp)
{
for (int i=0;i<size_double_array;i++)
{
std::cout << "double array at "<< i << " "<< double_array[i]<<std::endl;
}
Engine *ep;
mxArray *T = NULL, *result = NULL, *indices=NULL;
/*
* Call engOpen with a NULL string. This starts a MATLAB process
* on the current host using the command "matlab".
*/
if (!(ep = engOpen(""))) {
fprintf(stderr, "\nCan't start MATLAB engine\n");
return 1;
}
T = mxCreateDoubleMatrix(1,size_double_array, mxREAL);
memcpy((void *)mxGetPr(T), (void *)double_array, sizeof(double_array));
/** Place the variable T into the MATLAB workspace */
engPutVariable(ep, "T", T);
engEvalString(ep, "[D I] = sort(T,'descend')");
engEvalString(ep, "dlmwrite('myFile.txt',D)");
result = engGetVariable(ep,"D");
indices = engGetVariable(ep,"I");
sorted=(double *)mxGetData(result);
indices_cpp=(double *)mxGetData(indices);
/* for (int i=0;i<10;i++)
{
std::cout << "sorted= " <<*sorted << " indices= " << *indices_cpp <<std::endl;
sorted++;
indices_cpp++;
}*/
mxDestroyArray(T);
mxDestroyArray(result);
mxDestroyArray(indices);
engEvalString(ep, "close;");
engClose(ep);
return 0;
}
int main()
{
int size_double_array=10;
double double_array[10]={ 0, 5, 2, 7, 3, 9, 1, 6, 8, 4 };
double * sorted;
double * indices_cpp;
Engine *ep;
mxArray *T = NULL, *result = NULL, *indices=NULL;
if (!(ep = engOpen(""))) {
fprintf(stderr, "\nCan't start MATLAB engine\n");
return 1;
}
T = mxCreateDoubleMatrix(1,size_double_array, mxREAL);
memcpy((void *)mxGetPr(T), (void *)double_array, sizeof(double_array));
engPutVariable(ep, "T", T);
engEvalString(ep, "[D I] = sort(T,'descend')");
engEvalString(ep, "dlmwrite('myFile.txt',D)");
result = engGetVariable(ep,"D");
indices = engGetVariable(ep,"I");
sorted=(double *)mxGetData(result);
indices_cpp=(double *)mxGetData(indices);
mxDestroyArray(T);
mxDestroyArray(result);
mxDestroyArray(indices);
engEvalString(ep, "close;");
engClose(ep);
// int result=call_matlab_processing(double_array,10,sorted,indices_cpp);
for (int i=0;i<10;i++)
{
std::cout << "sorted= " <<*sorted << " indices= " << *indices_cpp <<std::endl;
sorted++;
indices_cpp++;
}
std::cout << "Done"<< std::endl;
return EXIT_SUCCESS;
}
  2 Comments
Abdelmoumen Bacetti
Abdelmoumen Bacetti on 18 Nov 2015
Please, use "{}code" to format your code.
I'm sure if you refer to one of Matlab's examples, you will find a clue.
shome
shome on 18 Nov 2015
Edited: shome on 18 Nov 2015
i have not come across that format. can you kindly refer to an example. i checked imread.m. icould find {} but nothing like {}code.
are you speaking about code formating wrt indentation
i am unable to understand. plz help. i can make my code simpler if my code looks ugly.but can you please be specific as to why the code in the function is giving wrong results.

Sign in to comment.

Accepted Answer

James Tursa
James Tursa on 18 Nov 2015
Edited: James Tursa on 18 Nov 2015
You have a fundamental flaw in your code. You free the memory behind the pointers that you use downstream in your code. E.g.,
result = engGetVariable(ep,"D"); // <-- Creates the mxArray result, including the data area
indices = engGetVariable(ep,"I"); // <-- Creates the mxArray indices, including the data area
sorted=(double *)mxGetData(result); // <-- Gets pointer to data area of result
indices_cpp=(double *)mxGetData(indices); // <-- Gets pointer to data area of indices
mxDestroyArray(T);
mxDestroyArray(result); // <-- Wipes out result, *and* the memory behind sorted
mxDestroyArray(indices); // <-- Wipes out indices, *and* the memory behind indices_cpp
// So at this point in the code, both of the pointers sorted and indices_cpp are *invalid*
engEvalString(ep, "close;");
engClose(ep);
// Code downstream of here uses *invalid* pointers. Anything can happen.
// Could get lucky good results, or random bad results, or even a program bomb.
// int result=call_matlab_processing(double_array,10,sorted,indices_cpp);
for (int i=0;i<10;i++)
{
std::cout << "sorted= " <<*sorted << " indices= " << *indices_cpp <<std::endl;
sorted++;
indices_cpp++;
}
You need to delay executing these two lines until after you are done using their data areas:
mxDestroyArray(result);
mxDestroyArray(indices);
  3 Comments
James Tursa
James Tursa on 18 Nov 2015
Can you post the current code you are using that gets the wrong result so I can look at it? To answer your question directly, the answer is YES you can call the MATLAB Engine from inside a function. (Strictly speaking, main is a function also)
James Tursa
James Tursa on 18 Nov 2015
Edited: James Tursa on 18 Nov 2015
Oh, I just noticed these lines:
int call_matlab_processing(double double_array[], int size_double_array,double * sorted, double * indices_cpp)
{
:
memcpy((void *)mxGetPr(T), (void *)double_array, sizeof(double_array));
The first argument of the function call_matlab_processing is the variable double_array. It turns out that this variable is of type "pointer to double" (i.e., double * ). I know it looks like you have declared it as an array, but that syntax is misleading. When used in a function argument, the notation
double variable_name[]
is equivalent to the notation
double *variable_name
In fact, even if you had use an explicit size it would have made no difference to the compiler. I.e., this notation in a function argument
double variable_name[10]
is also equivalent to the notation
double *variable_name
That is, the compiler sees that argument as a pointer, not as an array (you can't pass whole arrays in C/C++ function arguments this way). So downstream in your code when you use sizeof(double_array), it is equivalent to doing sizeof(double * ). The result will be either 4 (on 32-bit) or 8 (on 64-bit). So you are definitely not copying all of the elements in that memcpy call. You need to do this instead:
memcpy((void *)mxGetPr(T), (void *)double_array, size_double_array*sizeof(double));
Note that this is entirely different from what you have in main:
double double_array[10]={ 0, 5, 2, 7, 3, 9, 1, 6, 8, 4 };
:
memcpy((void *)mxGetPr(T), (void *)double_array, sizeof(double_array));
Here in main double_array is in fact an array, so sizeof(double_array) will be the full memory for this array, i.e. 10*8 = 80 bytes.
Also, FYI you don't really need the (void *) casts since converting pointers to/from void * is something the C/C++ compiler will automatically do for you.

Sign in to comment.

More Answers (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!