2017-01-03 2 views
2

Ich muss eine MEX-Funktion verwenden, die eine Matrix zuweisen und füllen soll (z. B. eine Identitätsmatrix erstellen). Hier ist ein Codebeispiel:MEX-Funktion initialisiert den linken Wert nicht

#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); 
} 

ich es wie folgt verwendet werden:

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

Dieser Aufruf gibt eine 1-by-0 leere Matrix. Daher weist es keine n-mal-n-Matrix zu und füllt sie nicht.

Antwort

7

Sie haben drei sehr wichtige Fehler und ein paar kleinere Problemchen:

  1. Diese Zeile: mwSize n = *(mwSize*)mxGetData(prhs[0]); zu Beginn Ihrer MEX-Funktion.

    Das macht absolut keinen Sinn. Wir können deutlich sehen, dass die Eingabe eine einzelne ganze Zahl ist. mxGetData erhält tatsächlich einen Zeiger auf die tatsächlichen Daten, die als Eingaben in die MEX-Funktion kommen, aber Sie werfen den Zeiger auf mwSize dann Dereferenzierung es. Ich habe absolut keine Ahnung was dir das geben würde, aber es ist definitiv nicht richtig. Stattdessen können Sie den tatsächlichen Zeiger auf die Daten mithilfe von mxGetPr abrufen, wobei der Zeiger Daten bereitstellen würde, die einem präzisen reellen-Typ entsprechen. Denn dies würde eine ganze Zahl sein, können Sie dies zu int Stimmen:

    int n = (int) *mxGetPr(prhs[0]); 
    
  2. Aufgrund der Korrektur mit (1), können Sie jetzt Ihre Matrix, ohne explizit zu Gießen mit size_t zuordnen. Dies würde ich einen Fehler nicht nennen, aber es ist eher eine Art Korrektur:

    plhs[0] = mxCreateDoubleMatrix(1, n*n, mxREAL); 
    
  3. Der wichtigste Fehler von allen.

    Beachten Sie, dass Ihre sample Funktion in Ihrem MEX Code einen Zeiger auf einen double Zeiger im Speicher für die Zwecke der Modifizierung der Matrix, die Sie in Ihrem Haupt-MEX-Gateway (das heißt mexFunction) erstellt akzeptiert. Sie ordnen jedoch zuerst den Speicher für die Matrix zu, die in den Ausgang geschrieben werden soll, sind aber und weisen den Speicher erneut innerhalb Ihrer sample-Funktion zu. Aus diesem Grund erstellen Sie tatsächlich einen anderen Zeiger auf den Speicher und schreiben die Daten in diesen Zeiger und nicht mit dem ursprünglichen Zeiger, den Sie an die Funktion übergeben hatten. Insbesondere innerhalb sample haben Sie diesen Code:

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

    daher beim Verlassen dieser Funktion wird der Speicher, den Sie ändern soll nicht verändert wurde. Der Punkt ist, dass die Zuweisung innerhalb der Funktion nicht erforderlich ist, da Sie den Speicher der Matrix bereits außerhalb der Funktion zugewiesen haben. Dies kann aus Ihrem Code entfernt werden.

  4. Dies ist sehr wichtig in Bezug auf Speicherzugriff. Denken Sie daran, dass MATLAB eine auf Spalten basierende Sprache ist, was bedeutet, dass die Spalten einer Matrix zusammenhängend statt wie in Sprachen wie C angeordnet sind. Daher ist Ihre Methode, auf die Matrix zuzugreifen, wenn Ihre Matrix ist der Größe m x n mit m Zeilen und n Spalten sollte (*T)[j*m + i] sein, wobei der Index i auf die Zeilen zugreift und j auf die Spalten zugreift.Jetzt haben Sie es auf (*T)[i*n + j] eingestellt. Für den Moment, da Ihre Matrix die gleichen Zeilen und Spalten teilt und Sie eine Identitätsmatrix erstellen, ist jede Art des Zugriffs die gleiche, aber der Matrizen von rechteckiger Größe überdrüssig.

    Daher ist der korrigierte Code für Ihre sample Funktion so:

    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; 
         } 
        } 
    } 
    

    Wenn Sie diesen Code ausführen, produziert sie nun die gewünschten Ergebnisse. Sie haben jedoch einen n*n Zeilenvektor und keine n x n Matrix erstellt, aber ich nehme an, dass Sie dies absichtlich getan haben. Um dies auszuführen, legte ich Ihre Quelle in einer Datei sample.c genannt, kompiliert es dann lief:

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

    Wenn Sie stattdessen eine n x n Matrix erstellen, um den Anruf zu mxCreateDoubleMatrix ändern, so dass sowohl die erste und zweite Argumente sind auf n:

    plhs[0] = mxCreateDoubleMatrix(n, n, mxREAL); 
    
  5. Dies ist kein Fehler, sondern im wert von rund Erbsenzählerei. Ihre Funktion erwartet nur 1 Eingabe, so dass keine T als zweiter Parameter eingegeben werden muss. Ihr Code sucht sowieso nicht nach einem zweiten Parameter. Darüber hinaus müssen Sie die richtigen Header für Ihren Code kompilieren umfassen:

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

Der endgültige Code, der korrigiert wird, ist somit:

#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); 
} 

Gerade im Interesse der Argument, das ist, was passiert, wenn die Änderung mxCreateDoubleMatrix, so dass es eine n x n Matrix ausgibt:

>> 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 
Verwandte Themen