MEX 函数不初始化左侧值

MEX function doesn't initialise left-hand value

我必须使用 MEX 函数,它应该分配一个矩阵并填充它(例如,制作一个单位矩阵)。这是一个代码示例:

#include <stdlib.h>
#include "mex.h"

void sample(int n, double** T)
{
     (*T) = (double*)malloc(n*n*sizeof(double));  
     int i, j;
     if ((*T) == NULL)
     {
        return;
    }
    else
    {
        for (i = 0; i < n; i++)
        {
            for (j = 0; j < n; j++)
            {
                if (i != j)
                    (*T)[i*n + j] = 0;
                else 
                    (*T)[i*n + j] = 1;
             }
        }
    }
}

void mexFunction( int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[] )
{
    mwSize n = *(mwSize*)mxGetData(prhs[0]);
    double *T;

    plhs[0] = mxCreateDoubleMatrix(1, (size_t)n*(size_t)n, mxREAL);

    T = mxGetPr(plhs[0]);

    sample(n, &T);  
}

我是这样使用的:

n = 5;
T = [];
T = sample(5, T);

这调用 returns 一个 1×0 空矩阵。因此,它不会分配 n×n 矩阵,也不会填充它。

您有三个非常严重的错误和一些小问题:

  1. 此行:mwSize n = *(mwSize*)mxGetData(prhs[0]); 在 MEX 函数的开头。

    这完全没有意义。我们可以清楚地看到输入是一个整数。 mxGetData actually gets a pointer to the actual data that is coming in as inputs into the MEX function, yet you are casting the pointer to mwSize then dereferencing it. I have absolutely no idea what this would give you, but it's definitely not right. What you can do instead is get the actual pointer to the data using mxGetPr 其中指针将为您提供符合 double 精度实数类型的数据。因为这将是一个整数,所以您可以将其转换为 int:

    int n = (int) *mxGetPr(prhs[0]);
    
  2. 由于 (1) 的更正,您现在可以分配矩阵,而无需使用 size_t 显式转换。这我不会称之为错误,但它更像是一种风格更正:

    plhs[0] = mxCreateDoubleMatrix(1, n*n, mxREAL);
    
  3. 最重要的错误。

    请注意,您的 MEX 代码中的 sample 函数接受指向内存中 double 指针的指针,用于修改您在主 MEX 网关中创建的矩阵(即 mexFunction).但是,您首先为要写入输出的矩阵分配内存,但在 sample 函数中 再次分配内存 。因此,您实际上是在创建 另一个 指向内存的指针并将数据写入此指针,而不是使用您传递给函数的原始指针。具体来说,在 sample 中你有这个代码:

    (*T) = (double*)malloc(n*n*sizeof(double));
    

    因此,退出该函数后,您要修改的内存并没有被修改。关键是不需要函数内部的分配,因为您已经在函数外部分配了矩阵的内存。这可以从您的代码中删除。

  4. 这在内存访问方面非常重要。请记住,MATLAB 是一种基于 column-major 的语言,这意味着矩阵的列以连续的方式排列,而不是像 C 等语言中的行那样排列。因此,您访问矩阵的方法是您的矩阵大小为 m x n,行 m,列 n 应该是 (*T)[j*m + i],其中索引 i 访问行,索引 j 访问列.现在您已将其设置为 (*T)[i*n + j]。现在,由于您的矩阵共享相同的行和列,并且您正在创建一个单位矩阵,因此两种访问方式都是相同的,但要厌倦矩形大小的矩阵。

    因此,您的 sample 函数的更正代码是:

    void sample(int n, double** T)
    {     
        int i, j;
    
        if (*T == NULL)
        {
             return;
        }
    
        for (i = 0; i < n; i++)
        {
            for (j = 0; j < n; j++)
            {
                if (i != j)
                    (*T)[j*m + i] = 0;
                else 
                    (*T)[j*m + i] = 1;
            }
        }
    }
    

    一旦您 运行 这段代码,它现在就会产生所需的结果。但是,您创建了 n*n 行向量而不是 n x n 矩阵,但我假设您是故意这样做的。为了达到 运行,我将您的源代码放在一个名为 sample.c 的文件中,然后对其进行编译 运行:

    >> mex -O sample.c
    Building with 'gcc'.
    MEX completed successfully.
    >> n = 5;
    >> T = sample(n)
    
    T =
    
      Columns 1 through 19
    
     1     0     0     0     0     0     1     0     0     0     0     0     1     0     0     0     0     0     1
    
      Columns 20 through 25
    
     0     0     0     0     0     1
    

    如果您希望创建一个 n x n 矩阵,请将调用更改为 mxCreateDoubleMatrix,以便将第一个和第二个参数都设置为 n:

    plhs[0] = mxCreateDoubleMatrix(n, n, mxREAL);
    
  5. 这不是错误,但值得挑剔。您的函数只需要 1 个输入,因此无需提交 T 作为第二个参数。您的代码无论如何都不会检查第二个参数。此外,您需要为要编译的代码包含正确的 headers:

    #include <stdlib.h> /* For malloc */
    #include "mex.h" /* For the MEX library */
    

修正后的最终代码为:

#include <stdlib.h>
#include "mex.h"

void sample(int n, double** T)
{     
    int i, j;
    if (*T == NULL)
    {
        return;
    }

    for (i = 0; i < n; i++)
    {
        for (j = 0; j < n; j++)
        {
            if (i != j)
                (*T)[j*m + i] = 0;
            else 
                (*T)[j*m + i] = 1;
         }
    }
}

void mexFunction( int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[] )
{
    int n = (int) *mxGetPr(prhs[0]);
    double *T;

    plhs[0] = mxCreateDoubleMatrix(1, n*n, mxREAL);
    /* Change to this line if you wish to have a n x n matrix */
    /* plhs[0] = mxCreateDoubleMatrix(n, n, mxREAL); */

    T = mxGetPr(plhs[0]);

    sample(n, &T);  
}

只是为了争论,如果改变 mxCreateDoubleMatrix 输出一个 n x n 矩阵,就会发生这种情况:

>> mex -O sample.c
Building with 'gcc'.
MEX completed successfully.
>> n = 5;
>> T = sample(n)

T =

     1     0     0     0     0
     0     1     0     0     0
     0     0     1     0     0
     0     0     0     1     0
     0     0     0     0     1