Reputation: 21
I am using MEX to interface my C++ code with MATLAB. My C++ code requires the output be of type vector . Since I am new to C++ I am extremely confused with how the pointers work. I will take an input array from MATLAB
int *data_array_ptr
data_array_ptr=(int *)mxGetData(prhs[0]);
a = mxGetM(prhs[0]);
int int_data[a];
copy(*data_array_ptr, *data_array_ptr+ a, int_data);
Now, int_data is supposed to have all the data that is stored at the location of data_array_ptr... Does it do this?
Then,
double *data_out_ptr;
plhs[0]= mxCreateDoubleMatrix( (mwSize)m, (mwSize)n, mxREAL);
data_out_ptr= mxGetPr(plhs[0]);
len6=mxGetM(plhs[0]);
vector<double> data_out_data(*data_out_ptr,*data_out_ptr+len6);
This should put the contents of the empty output matrix into a vector named data_out_data. Does it do this?
Then, I want to pass both data_out_data and int_data to a c++ function. However, I want to pass data_out_data as a pointer so that the c++ function will fill the vector with data and then when the function finishes, the MEX function will see the now filled vector and be able to convert it back to an array of doubles that can fill plhs[0].
So, something like
mexFunction(plhs[],prhs[]){
int *data_array_ptr
data_array_ptr=(int *)mxGetData(prhs[0]);
a = mxGetM(prhs[0]);
int int_data[a];
copy(*data_array_ptr, *data_array_ptr+ a, int_data);
double *data_out_ptr;
plhs[0]= mxCreateDoubleMatrix( (mwSize)m, (mwSize)n, mxREAL);
data_out_ptr= mxGetPr(plhs[0]);
len6=mxGetM(plhs[0]);
vector<double> data_out_data(*data_out_ptr,*data_out_ptr+len6);
foo(int_data, *data_out_data)
copy(data_out_data.begin(), data_out_data.end(), data_out_ptr);
}
and on the return of foo, data_out_data will be filled. My function has no return arguments an data_out_data must be of type vector. How do I pass the vector to foo so that foo can edit the data?
Thanks!!
Upvotes: 1
Views: 1526
Reputation: 109109
I'm not sure I understand your question correctly. I believe you want to pass an array from MATLAB to your mex function, the mex function then calls a C++ function that operates on this data array, and a vector
. The vector
then contains the result of whatever the C++ function does, and you want to pass this data back to MATLAB.
First, let's deal with getting the data from MATLAB into your MEX function
int const *data_in = static_cast<int const *>(mxGetData(prhs[0]));
Now, data_in
points to the data that you passed in. By the way, are you sure the array contains int
s? By default, MATLAB uses double
for everything.
Is your C++ function going to modify this array? If not, you can just call it with the pointer and the number of elements, instead of performing a copy.
For instance, if the signature of foo
is
foo( int const *data_in, mwSize num_data_in, std::vector<double> *data_out );
you can call it as
foo( data_in, mxGetNumberOfElements(prhs[0]), &data_out );
If you do need to modify the data, and / or cannot modify foo
, just create a vector to hold a copy of the data.
std::vector<int> data_in_vec( data_in, data_in + mxGetNumberOfElements(prhs[0]) );
foo( data_in_vec.data(), data_out );
As for the foo
function, does it need for the vector to be sized correctly before you call it? If so,
std::vector<double> data_out( m * n ); // creates a vector with m * n elements
foo( data_in_vec.data(), &data_out );
If possible, modify foo
to accept a std::vector<double>&
instead of std::vector<double> *
. Then you can call it as
foo( data_in_vec.data(), data_out );
Also, given a choice, I'd have foo
resize the vector as needed instead of requiring the caller to do so.
Now, getting the data back to MATLAB.
plhs[0] = mxCreateDoubleMatrix( m, n, mxReal );
std::copy( data_out.data(), data_out.data() + data_out.size(), mxGetPr(plhs[0]) );
The above line assumes that the size of the vector is not greater than m * n
Remember that MATLAB stores matrices in column-major format, unlike C & C++. Depending on how the foo
function works, you may have to transpose the returned vector, in which case you cannot use std::copy
to do the copying, you'll have to write nested loops.
Upvotes: 2
Reputation: 63471
You are dereferencing your pointers more than you should...
int *data_array_ptr;
// ...
copy(*data_array_ptr, *data_array_ptr+ a, int_data);
When you are asked to provide a begin- and end-pointer to copy
, you need to do this:
copy(data_array_ptr, data_array_ptr+ a, int_data);
Now you have provided two memory addresses. The first, data_array_ptr
, is the address of the start of your array. The second, data_array_ptr+a
is the address of the element just after the end of your array.
If you dereference the pointer (*data_array_ptr
) then you are asking for the value (an int
) of the first element of the array. Likewise, *data_array_ptr+a
will first take the value of the first array element and then add a
to it. This is not what you want.
So, change all your calls to copy
as suggested, as well as your vector
constructor.
As for your question about your foo
function, if you need to pass a vector then declare it like this:
void foo( int * int_data, std::vector<double> & data_out_data )
Assuming definitions of these variables that you have provided above. I take it you are calling like this:
// ...
int int_data[a];
copy(*data_array_ptr, *data_array_ptr+ a, int_data);
// ...
vector<double> data_out_data(data_out_ptr, data_out_ptr+len6);
// ...
foo( int_data, data_out_data );
Note that if you don't know the length of your int_data
array inside foo
(based on the length of data_out_data
) you should also require a size in the argument list of foo
:
foo( int_data, a, data_out_data );
Upvotes: 1