1

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!!

2 Answers2

2

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 ints? 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.

Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • From Matlab, the array will already be sized correctly so that isnt a problem, I have other classes that are called inside foo that will fill the data in the data_out vector. The classes are already written and only accept vectors, I was hoping to possibly pass a pointer into foo for the vector data_out and then call the classes with the empty vector, and then after the classes fill data_out, the pointer now sees the new data and therefore so will my MEX function. – user1586097 Aug 08 '12 at 23:39
  • @user1586097 You cannot pass the vector back to MATLAB or make both the vector and the matrix created by `mxCreateDoubleMatrix` share the same data buffer. After `foo` is done operating on the vector you'll have to copy the contents of the vector back into the matrix in `plhs[0]`. – Praetorian Aug 09 '12 at 00:22
  • If I call foo like you say: _If possible, modify foo to accept a std::vector& instead of std::vector *. Then you can call it as_ `foo( data_in_vec.data(), data_out )` If I were to pass data_out to another class, will it be the address of the first element of the data vector or will it be the actual data? My class requires an actual vector. But I also want the vector that the class edits to be seen on the return of foo in MEX. – user1586097 Aug 09 '12 at 02:36
  • @user1586097 [Here's an answer](http://stackoverflow.com/questions/57483/what-are-the-differences-between-pointer-variable-and-reference-variable-in-c) explaining the difference between a pointer and a reference. A reference refers to the original variable and so you can do whatever with it that you could've using the original variable. Also, if you make modifications to the reference it modifies the original variable also (since they're both the same anyway) – Praetorian Aug 09 '12 at 16:02
  • Thank you. Now my problem is with the `copy(data_array_ptr, data_array_ptr+ a, int_data)` This line should be taking the entire array that data_array_ptr is pointing to, and recasting it to whatever int_data is, which is in this case an array of integers. So then int_data would have the data from data_array_ptr but casted as type int.However, the compiler tells me that int_data is of type int* – user1586097 Aug 09 '12 at 16:17
  • @user1586097 If `data_array_ptr` is not an `int *` you cannot use `std::copy` to perform the copying. Use a for loop, or you can use `std::for_each` along with a lambda function (if you have a C++11 compiler) or a functor. – Praetorian Aug 09 '12 at 16:22
  • Ok now I have something like `int *a_ptr=(int *)mxGetData(a_input); size_t b = mxGetM(a_input); int a_data[b]; for(int i=0; i < b; i++) { a_data[i]=(int)a_ptr[i]; }` But i am still getting the error, the problem is that I have to pass the actual data to foo I have a pre-written class that requires actual data and not a pointer. – user1586097 Aug 09 '12 at 16:25
  • You can't do `int a_data[b];` in C++, since the value of `b` is not known to the compiler at compile time. Use an `std::vector` or `mxCalloc` to dynamically allocate an array. Don't forget to `mxFree` it if you're using the latter. – Praetorian Aug 09 '12 at 16:30
  • So this `for` loop will work in saving data to an array, except I just wasnt allocating memory correctly? thanks! – user1586097 Aug 09 '12 at 16:36
  • if I cant do `int a_data[b]`, why can i say `m = mxGetM(a_input); n = mxGetN(a_input); prhs[0]= mxCreateDoubleMatrix( (mwSize)m, (mwSize)n, mxREAL);`? A pointer can be dynamically adjusted, but an array cannot? mxCalloc will return a pointer to the memory that it has allocated,so I will loop through that memory and fill that memory with my data, and then copy that memory to a new non-pointer array? – user1586097 Aug 09 '12 at 16:52
  • @user1586097 [An array and a pointer are not the same thing](http://stackoverflow.com/questions/1641957/is-array-name-a-pointer-in-c). Array is a type that contains size information, but a pointer doesn't. You can dynamically allocate memory and make a pointer point to that memory to access, which is what `prhs[0] = mxCreateDoubleMatrix( m, n, mxREAL);` does. I don't understand what you mean by *then copy that memory to a new non-pointer array*. If you have some destination array already allocated, there's no need to involve the intermediate copy step, just fill the destination with your data. – Praetorian Aug 09 '12 at 17:03
1

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 );
paddy
  • 60,864
  • 6
  • 61
  • 103
  • this was super helpful thanks! If I need to call foo with a pointer to the vector so that inside foo, the pointer can be dereferenced, then classes will be called with the dereferenced data, then the classes will return new data, and then teh pointer will point to the new data for the MEX function to see at the return of foo. – user1586097 Aug 08 '12 at 23:42
  • Well that's fine. I specified a reference to the vector instead of a pointer. You can use pointer if you like, but reference is more common when passing STL containers around. You can still take the address of the reference object inside `foo` to get a pointer (*ie* `&data_out_data`). The point here is that you are passing into foo a reference to your local copy of the vector. So any changes made to the vector during the call to `foo` will be there when `foo` returns. – paddy Aug 08 '12 at 23:56
  • if I call foo like `foo(int_data, &data_out_data)` and foo is defined as `foo(int int_data[], vector *data_out_data)` then the address of the first element of data_out_data will be dereferenced into foo? Or do I still need to do something to pass that vector reference onto another class? Or should foo be defined as &data_out_data instead of *data_out_data? @paddy – user1586097 Aug 09 '12 at 02:21
  • @user1586097 No, `data_out_data` is a vector of doubles. So you are not passing a pointer to the first element - you are passing a pointer to the vector (an instance of the class `vector`). The function call and declaration you gave there are fine, if you want to pass your vector as a pointer. A reference is almost the same as a pointer, except syntactically you use it as if it wasn't a pointer. So to append to a vector pointer you'd use `v->push_back()`, but if it was a vector reference you'd use `v.push_back()`. You don't have to explicitly reference or dereference references! – paddy Aug 09 '12 at 03:44
  • OK so if I pass a vector by reference do I need to make a new copy of the vector inside foo to allow me to send the vector to get processed in another class? then on the return of the class `v.pushback` to set the reference to thenow filled copied vector? – user1586097 Aug 09 '12 at 13:46
  • ok im sorry, i went back and read your first comments and looked up references, and I understand now. Thank you. Now my problem is with the `copy(data_array_ptr, data_array_ptr+ a, int_data)` This line should be taking the entire array that data_array_ptr is pointing to, and recasting it to whatever int_data is, which is in this case an array of integers. However, the compiler tells me that int_data is of type int*. – user1586097 Aug 09 '12 at 15:42