Writing mat file from C++ using API, empty matrix
13 vues (au cours des 30 derniers jours)
Afficher commentaires plus anciens
Alexander Lytchier
le 3 Juil 2017
Commenté : James Tursa
le 14 Nov 2023
I wish to write an Eigen type Matrix to a mat file as seen in this code. To simplify things, in the code below I'm simply attempting to write the content of the vector vTest. After running the code, the .mat file variable contains a 1 x 5 matrix, however all entires are 0! When calling mxCreateDoubleMatrix I know that all entires are initialised to 0; I think this means none of the data is copied by memcpy()?
Note that by simply looping through data2 I can tell that it indeed contains 1,2,3,4,5 before memcpy() is called. I also tried with a one dimensional array (data2) - same problem.
(I'm using Visual Studio 2015)
Can anyone suggest why this isn't working?
void matLink::matWrite(const char *file, const char* varName, Eigen::MatrixXd data)
{
std::vector<double> vTest = { 1, 2, 3, 4, 5 };
MATFile *pMat = matOpen(file, "w");
if (pMat == NULL) { std::cerr << "matOpen: Failed to open mat file for writing\n"; return; }
mxArray * pArr;
const int rows = 1;
const int columns = vTest.size();
pArr = mxCreateDoubleMatrix(rows, columns, mxREAL);
double **data2 = new double*[rows];
for (int i = 0; i < rows; i++) {
data2[i] = new double[columns];
}
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
data2[i][j] = vTest[j];
}
}
memcpy((void*)mxGetPr(pArr), (void*)data2, sizeof(data2));
if (matPutVariable(pMat, varName, pArr) != 0) {
std::cerr << "matPutVariable: ERROR" << std::endl;
}
mxDestroyArray(pArr);
if (matClose(pMat) != 0) {
std::cerr << "matWrite: ERROR closing file " << file << std::endl;
}
}
2 commentaires
James Tursa
le 14 Nov 2023
The answer and comments below describe how to use memcpy. That technique could be used to avoid the loops also.
Réponse acceptée
James Tursa
le 3 Juil 2017
Modifié(e) : James Tursa
le 3 Juil 2017
Some problems:
1) data2 doesn't point to any of your double data ... it points to pointer_to_double values. So using memcpy with this pointer isn't going to copy any of your double data.
2) Even if data2 did point to your double data (it doesn't), the method you are using to allocate your rows of double data does not guarantee that the memory for the rows will be contiguous in memory ... in fact they could be scattered all over in memory. So attempting to copy all of the rows as one contiguous block of data using memcpy could easily seg fault.
I have never been a fan of allocating array data like you are doing. It prevents you from doing anything reliably downstream in your code that expects the data to be contiguous. It is better IMO to just allocate the entire block of memory up front to make sure it is contiguous and then to set up your row pointers accordingly if that is the syntax you really want to use in your code (which btw I am also not a fan of).
3) You didn't delete any of your new allocations (the row pointers and the row data).
4) You don't copy the correct number of bytes in this line:
memcpy((void*)mxGetPr(pArr), (void*)data2, sizeof(data2));
Remember, data2 is a pointer, not an array. So sizeof(data2) is just the size of a pointer ... it is not the size of the data that it points to. You will need to supply a manual calculation for that argument. (Side point: the conversion to pointer_to_void will happen automatically ... you don't have to explicitly cast that)
-------
E.g., I prefer something like this if you insist on the [ ][ ] syntax in your code:
double *data1 = new double[rows*columns]; // Ensures data is contiguous
double **data2 = new double*[rows];
data2[0] = data1; // Point to first row
for (int i = 1; i < rows; i++) {
data2[i] = data2[i-1] + columns; // Point to subsequent rows
}
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
data2[i][j] = vTest[j];
}
}
Then for the memcpy, use data1:
memcpy( mxGetPr(pArr), data1, sizeof(*data1)*rows*columns ); // Manually calculate #bytes
Then at the end you only have data2 and data1 to delete.
3 commentaires
James Tursa
le 3 Juil 2017
Modifié(e) : James Tursa
le 3 Juil 2017
Yes indeed, that was a typo on my part! (Dangers of typing a response on the fly without testing ...) But your version is not correct either. It needs to be this:
memcpy( mxGetPr(pArr), data1, sizeof(*data1)*rows*columns );
I have corrected my code above based on this. Thanks.
Plus de réponses (0)
Voir également
Catégories
En savoir plus sur MATLAB Support for MinGW-w64 C/C++ Compiler dans Help Center et File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!