Writing ints and unsigned ints to .mat files in a C++ program

2 views (last 30 days)
Hello, I have a question about the "proper" way to write a variable that was declared in C++ as an or an unsigned int and saving it to .mat file. All examples I have seen are for strings or doubles and when I follow that explicitly I am generating runtime errors. Here is my current code which seems to work when time_step is a double. However if time_step is an int or an unsigned int, I seem to get runtime errors.
MATFile *mfile;
mfile = matOpen(file, "w");
tempMat=mxCreateDoubleMatrix(1,1,mxREAL);
sprintf(name_buff,"time_step");
mxSetPr(tempMat, &time_step);
status = matPutVariable(mfile, name_buff, tempMat);
Should I be using casting to change my int into a double? Eg.
MATFile *mfile;
mfile = matOpen(file, "w");
tempMat=mxCreateDoubleMatrix(1,1,mxREAL);
double double_time_step = static_cast<double>(time_step);
sprintf(name_buff,"time_step");
mxSetPr(tempMat, &double_time_step);
status = matPutVariable(mfile, name_buff, tempMat);
Is this type of conversion recommended or is there an mx command that I have missed that handles this?
Thanks for your time!

Answers (4)

James Tursa
James Tursa on 14 Nov 2011
You need to show more of your code. E.g., what is time_step? How is it declared and initialized? It needs to be MATLAB allocated memory (i.e., with a mxMalloc or similar) and not a native C++ variable if you are attaching it to an mxArray. The fact that you use &time_step in the mxSetPr call leads me to believe that you are doing this wrong. You need to allocate a pointer with one of the MATLAB API functions and fill the data at that memory before you can safely attach it to an mxArray. Since tempMat was created as a double mxArray, MATLAB expects there to be 8 bytes worth of data at the mxGetPr location. If you put an address of an int there it is likely only 4 bytes, so writing out this mxArray to the mat file will access invalid memory. Also, you should use mxFree first on the mxGetPr address before using mxSetpr to avoid a memory leak.
If you are just trying to save a scalar variable out to the mat file then a simpler way is to use mxCreateDoubleMatrix as you have done, then use mxGetPr to get the data pointer, then use that pointer to fill the value in directly (e.g. *pr = time_step):
mxArray *tempMat;
double *pr;
:
tempMat=mxCreateDoubleMatrix(1,1,mxREAL);
pr = mxGetPr(tempMat);
*pr = time_step;
The above could be used for arrays as well. If you really only have a scalar then you can do this:
tempMat = mxCreateDoubleScalar(time_step);
What about name_buff, how is it declared? Etc. etc. Until we see all of the relevant code we cannot correct all of your mistakes.
  1 Comment
Kaustubha Govind
Kaustubha Govind on 14 Nov 2011
In addition, note that mxCreateDoubleMatrix and mxCreateDoubleScalar must be used to create variables of double type only. For other types, use mxCreateNumericArray or mxCreateNumericMatrix.

Sign in to comment.


James Tursa
James Tursa on 14 Nov 2011
Consider these lines from your code (in particular the last line):
mxArray *tempMat;
tempMat=mxCreateDoubleMatrix(1,1,mxREAL);
int dx = 10;
double temp;
double tstep = 2.5;
int status =0;
char* name_buff = new char[50];
sprintf(name_buff,"dx");
temp = static_cast<double>(dx);
mxSetPr(tempMat, &(temp));
You create a double scalar mxArray and put the pointer into tempMat. All well and good. At this point the real data pointer for this array (call it pr) points to an 8-byte section of memory to hold a double value that the MATLAB API functions have allocated (key point). The MATLAB memory manager knows about this memory ... the C/C++ memory manager (new & delete) doesn't.
In the last line above you try to stuff an address of a regular C/C++ variable into the mxArray data pointer spot via mxSetPr. Early versions of MATLAB will let you do this and then bomb later on when they attempt to free this memory. Later versions of MATLAB will simply bomb at this point because the address doesn't match anything it knows about. This is a no-no in either event ... you have attempted to mix MATLAB API allocated memory with regular C/C++ memory. When tempMat gets destroyed the MATLAB API memory manager will attempt to free the memory at the temp location ... an obvious no-no. Do the following instead of your last line:
*mxGetPr(tempMat) = temp;
The value of temp gets copied into the data area of tempMat.
Side note: You should check the value of tempMat before using it (make sure it is not NULL).

Cole Van Vlack
Cole Van Vlack on 14 Nov 2011
Hi James, Thanks for the prompt response. Everything you are highlighting leads me to think I am doing this wrong. Here is my code,
#include <iostream>
#include "mat.h"
#include "mex.h"
using namespace std;
int main(int argc, char *argv[]) {
/*Open the .mat file*/
string name = "test_case.mat";
char *name_char;
name_char=new char[name.length()+1];
name.copy(name_char, name.length());
name_char[name.length()]=0;
const char *file = name_char;
MATFile *mfile;
mfile = matOpen(file, "w");
if(mfile==NULL)
{ //Make sure it opened
printf("%s : Error opening file %s on line %d\n", __FILE__, file,__LINE__);
}
/*Initialize Data and Write to file*/
mxArray *tempMat;
tempMat=mxCreateDoubleMatrix(1,1,mxREAL);
int dx = 10;
double temp;
double tstep = 2.5;
int status =0;
char* name_buff = new char[50];
sprintf(name_buff,"dx");
temp = static_cast<double>(dx);
mxSetPr(tempMat, &(temp));
status = matPutVariable(mfile, name_buff, tempMat);
if(status!=0)
cout<<__FILE__<<" : Error writing variable on line "<<__LINE__<<endl;
sprintf(name_buff,"tstep");
mxSetPr(tempMat, &tstep);
status = matPutVariable(mfile, name_buff, tempMat);
if(status!=0)
cout<<__FILE__<<" : Error writing variable on line "<<__LINE__<<endl;
if (matClose(mfile) != 0) {
cout<<__FILE__<<" : Error closing file \""<<file<<"\" on line "<<__LINE__<<endl;
}
delete[] name_buff;
delete[] name_char;
return 0;
}
This code gives me my expected error,
terminate called without an active exception
Aborted
What my goal is, is to open a .mat file and write the data from each of my C++ classes to the .mat file. I have obviously stripped out everything related to the classes but above is the general approach I have been using. I am also sure there are many things above that will make you cringe! Thanks again for the help.
Cole

Cole Van Vlack
Cole Van Vlack on 16 Nov 2011
Hi James, thanks for all of the help. So by the same reasoning the following code should crash or at least have a memory leak.
#include <iostream>
#include "mat.h"
#include "mex.h"
using namespace std;
int main(int argc, char *argv[]) {
/*Open the .mat file*/
string name = "test_case.mat";
char *name_char;
name_char=new char[name.length()+1];
name.copy(name_char, name.length());
name_char[name.length()]=0;
const char *file = name_char;
MATFile *mfile;
mfile = matOpen(file, "w");
if(mfile==NULL)
{ //Make sure it opened
printf("%s : Error opening file %s on line %d\n", __FILE__, file,__LINE__);
}
/*Initialize Data and Write to file*/
mxArray *tempMat;
//mexMakeArrayPersistent(tempMat);
int status =0;
char* name_buff = new char[50];
/**********************************************************************/
/*******************Begin New Section**********************************/
/**********************************************************************/
unsigned int dims = 3;
mwSize *dimslist = new mwSize[dims];
dimslist[0] = 2;
dimslist[1] = 4;
dimslist[2] = 5;
double *multi_d_array;
multi_d_array = new double [dimslist[0]*dimslist[1]*dimslist[2]];
for(unsigned int i=0;i<dimslist[0];i++){
for(unsigned int j=0;j<dimslist[1];j++){
for(unsigned int k=0;k<dimslist[2];k++){
multi_d_array[i+dimslist[0]*j+dimslist[1]*k] =(i+1)*(j+1)*(k+1);
}}}
tempMat=mxCreateNumericArray(dims,dimslist,mxDOUBLE_CLASS,mxREAL);
sprintf(name_buff,"Radiant_cell_indexes");
mxSetPr(tempMat, multi_d_array);
status = matPutVariable(mfile, name_buff, tempMat);
delete[] multi_d_array;
/**********************************************************************/
/*******************End New Section************************************/
/**********************************************************************/
if (matClose(mfile) != 0) {
cout<<__FILE__<<" : Error closing file \""<<file<<"\" on line "<<__LINE__<<endl;
}
delete[] name_buff;
delete[] name_char;
cout<<"exiting"<<endl;
return 0;
}
This is because mxSetPr tries to manage the memory pointed to by tempMat and multi_d_array and then I delete the memory again using delete[]. I had originally thought I should be just following your above suggestions and changing,
mxSetPr(tempMat, multi_d_array);
again to
*mxGetPr(tempMat) = multi_d_array;
However, the compiler definitely did not like that and without the change the code seems to runs fine. Am I creating a memory leak with the delete[] multi_d_array and just getting lucky?
Again, thanks for all the help. I have learned more from this conversation than in hours reading the documentation.
  1 Comment
James Tursa
James Tursa on 18 Nov 2011
This line is definitely causing a memory leak:
mxSetPr(tempMat, multi_d_array);
since the pr pointer existing in tempMat is overwritten with multi_d_array (i.e., you lost your only pointer to that dynamically allocated data memory).
If you want to write out an array, I would suggest re-ordering your code and work with the pr pointer directly instead of copying from or using multi_d_array. E.g.,
tempMat=mxCreateNumericArray(dims,dimslist,mxDOUBLE_CLASS,mxREAL);
multi_d_array = mxGetPr(tempMat);
// insert code to use multi_d_array here
mxDestroyArray(tempMat); // once you are done with it.
And get rid of your multi_d_array new allocation and corresponding delete []. Also get rid of your mxSetPr call.

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!