Matlab crashed when call mexCallMATLAB

I want to create a new sparse matrix and pass the value of the input sparse matrix to it, and then call mexCallMATLAB to get its transpose. The code crashed,
#include <stdio.h>
#include <stdlib.h>
#include <mex.h>
#include <math.h>
#include <time.h>
#include <string.h>
extern void mexFunction(int iNbOut, mxArray *pmxOut[],
int iNbIn, const mxArray *pmxIn[])
{
mxArray *A, *B;
double *d,*p,*pin,*out;
mwSize m,n,nzmax;
mwIndex *ir, *jc;
m = mxGetM(pmxIn[0]);
n = mxGetN(pmxIn[0]);
nzmax = mxGetNzmax(pmxIn[0]);
ir = mxGetIr(pmxIn[0]);
jc = mxGetJc(pmxIn[0]);
pin = mxGetPr(pmxIn[0]);
A = mxCreateSparse(m, n, nzmax, mxREAL);
mxSetIr(A, ir);
mxSetJc(A, jc);
mxSetPr(A, pin);
d = mxGetPr(A);
B = mxCreateSparse(m, n, nzmax, mxREAL);
mexCallMATLAB(1, &B, 1, &A, "transpose");
p = mxGetPr(B);
pmxOut[0] = mxCreateNumericArray(1 , nzmax, mxSINGLE_CLASS,mxREAL);
out = mxGetPr(pmxOut[0]);
for(mwSize i = 0; i < nzmax; i++)
{
out[i] = p[i];
mexPrintf("pmxOut = %f", out[i]);
}
}

 採用された回答

James Tursa
James Tursa 2017 年 3 月 7 日
編集済み: James Tursa 2017 年 3 月 7 日

1 投票

(1) These lines are wrong:
ir = mxGetIr(pmxIn[0]);
jc = mxGetJc(pmxIn[0]);
pin = mxGetPr(pmxIn[0]);
A = mxCreateSparse(m, n, nzmax, mxREAL);
mxSetIr(A, ir);
mxSetJc(A, jc);
mxSetPr(A, pin);
You cannot attach pointers (pr,pi,ir,jc,dims) obtained from one mxArray to another mxArray. This is in effect creating a type of "shared data copy" of the mxArray, but you are doing it in a manner that the MATLAB Memory Manager knows nothing about. When the first mxArray gets destroyed, all of the data pointers become invalid because they are freed. So when the second mxArray gets used or destroyed, those invalid data pointers get accessed and MATLAB crashes. If you really needed a shared data copy of the mxArray (which it does not appear that you really do), here is how to go about it using an undocumented API function:
mxArray *mxCreateSharedDataCopy(const mxArray *); /* Undocumented API function prototype */
:
A = mxCreateSharedDataCopy(pmxIn[0]);
(2) The output of mexCallMATLAB is not something you create ahead of time. E.g., these lines:
B = mxCreateSparse(m, n, nzmax, mxREAL);
mexCallMATLAB(1, &B, 1, &A, "transpose");
B will be created from scratch by the mexCallMATLAB call. You do not create a "place-holder" for it ahead of time. The only thing you have done with the above code is to create a memory leak because the handle to the sparse matrix B created by the mxCreateSparse call gets overwritten by the mexCallMATLAB call. (Actually, the memory leak is temporary because the garbage collection will clean up this error for you). Get rid of that first line.
If you are just trying to get the transpose of the input, then do it directly (no need for the "A" copy). E.g.,
mexCallMATLAB(1, &B, 1, (mxArray **)pmxIn, "transpose");
(3) This will crash MATLAB:
double *d,*p,*pin,*out;
:
pmxOut[0] = mxCreateNumericArray(1 , nzmax, mxSINGLE_CLASS,mxREAL);
out = mxGetPr(pmxOut[0]);
for(mwSize i = 0; i < nzmax; i++)
{
out[i] = p[i];
mexPrintf("pmxOut = %f", out[i]);
}
You create a single class mxArray pmxout[0], but then use a double pointer to access its data area in a loop. That will give garbage results at first and then crash MATLAB because you will run off the end of the allocated memory. You can't use a double pointer to access single data. Also you should be using mxCreateNumericMatrix with those inputs, not mxCreateNumericArray.
It seems like this is all you are trying to do:
mxArray *B;
double *p;
float *out;
mwSize nzmax;
nzmax = mxGetNzmax(pmxIn[0]);
mexCallMATLAB(1, &B, 1, (mxArray **)pmxIn, "transpose");
p = mxGetPr(B);
pmxOut[0] = mxCreateNumericMatrix(1 , nzmax, mxSINGLE_CLASS,mxREAL);
out = (float *) mxGetData(pmxOut[0]);
for(mwSize i = 0; i < nzmax; i++)
{
out[i] = p[i];
mexPrintf("pmxOut = %f\n", out[i]);
}
mxDestroyArray(B);

その他の回答 (2 件)

bo bo
bo bo 2017 年 3 月 7 日

0 投票

Thanks James very much! In fact, my problem is as follows: I have two temporary sparse array variable d and b in my code. d and b have the same sparse structure as the input sparse matrix prhs[0], and in the following code the transpose of d and b will be used. So I create the new sparse array d and b by using : d = mxCreateSparse(m,n,nzmax,mxREAL), and set corresponding Ir, Jc, Pr, however, as you mentioned, it is wrong! If I need to create such a sparse array, how can I do it ?
And I also have to get the transpose of d, if I denote the transpose of d as dt, can I use the following code ?
mxArray *dt;
mexCallMATLAB(1, &dt, 1, (mxArray )d, "transpose");

1 件のコメント

James Tursa
James Tursa 2017 年 3 月 7 日
編集済み: James Tursa 2017 年 3 月 7 日
Can you write out, in pseudo-code or descriptions, line by line, what it is you want to do?
The mxCreateSparse function simply gives a bare bones sparse matrix. To get a specific structure you have to manually assign values to the Ir, Jc, Pr, and Pi (if applicable) parts. So if you are trying to duplicate the sparse structure of an existing sparse matrix, you would need to copy over all of the Ir and Jc stuff (as opposed to merely copying the pointers over as you tried to do). A simple way to accomplish all this is to use mxDuplicateArray (but that will copy over all of the Pr and Pi values as well, which may do more work than you want).
If d is a pointer to an existing valid mxArray, you can get its transpose by simply
mxArray *dt;
:
mexCallMATLAB(1, &dt, 1, &d, "transpose");

サインインしてコメントする。

bo bo
bo bo 2017 年 3 月 7 日

0 投票

Hi, James, the following code in your answer still crashed.
#include <stdio.h>
#include <stdlib.h>
#include <mex.h>
#include <math.h>
#include <time.h>
#include <string.h>
extern void mexFunction(int iNbOut, mxArray *pmxOut[],
int iNbIn, const mxArray *pmxIn[])
{
mxArray *B;
double *p;
float *out;
mwSize nzmax;
nzmax = mxGetNzmax(pmxIn[0]);
mexCallMATLAB(1, &B, 1, (mxArray **)pmxIn, "transpose");
p = mxGetPr(B);
pmxOut[0] = mxCreateNumericArray(1 , nzmax, mxSINGLE_CLASS,mxREAL);
out = (float *) mxGetData(pmxOut[0]);
for(mwSize i = 0; i < nzmax; i++)
{
out[i] = p[i];
mexPrintf("pmxOut = %f\n", out[i]);
}
mxDestroyArray(B);
}

2 件のコメント

James Tursa
James Tursa 2017 年 3 月 7 日
編集済み: James Tursa 2017 年 3 月 7 日
Typo on my part. Use mxCreateNumericMatrix, not mxCreateNumericArray.
Also, I suppose I should point out that nzmax is simply the max amount of non-zeros that can be stored using currently allocated memory. It does not represent how many non-zeros the sparse matrix actually has. To get that number you would do this instead:
mwIndex *jc;
size_t n, nnz;
:
jc = mxGetJc(pmxIn[0]);
n = mxGetN(pmxIn[0]);
nnz = jc[n]; /* The number of non-zero entries in the sparse matrix */
bo bo
bo bo 2017 年 3 月 9 日
Thanks, it will never crash by mxCreateNumericMatrix.

サインインしてコメントする。

カテゴリ

ヘルプ センター および File ExchangeWrite C Functions Callable from MATLAB (MEX Files) についてさらに検索

質問済み:

2017 年 3 月 7 日

コメント済み:

2017 年 3 月 9 日

Community Treasure Hunt

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

Start Hunting!

Translated by