Frage

Ich habe einige C-Code läuft auf OS X 10.6, geschrieben, die langsam sein passiert, so bin ich mit valgrind für Speicherlecks zu überprüfen, etc. Eines der Dinge, die ich bemerkt haben, während dies zu tun:

Wenn ich Speicher zuweisen zu einem 2D-Array wie folgt:

double** matrix = NULL;
allocate2D(matrix, 2, 2);

void allocate2D(double** matrix, int nrows, int ncols) {
    matrix = (double**)malloc(nrows*sizeof(double*));
    int i;
    for(i=0;i<nrows;i++) {
        matrix[i] = (double*)malloc(ncols*sizeof(double));
    }
}

Überprüfen Sie dann die Speicheradresse der Matrix ist es 0x0.

Allerdings, wenn ich

double** matrix = allocate2D(2,2);

double** allocate2D(int nrows, int ncols) {
    double** matrix = (double**)malloc(nrows*sizeof(double*));
    int i;
    for(i=0;i<nrows;i++) {
        matrix[i] = (double*)malloc(ncols*sizeof(double));
    }
return matrix;
}

Das funktioniert gut, das heißt der Zeiger auf den neu erstellten Speicher zurückgeführt wird.

Wenn ich habe auch eine free2D Funktion den Speicher freizugeben. Es scheint nicht richtig zu befreien. D. h der Zeiger nach wie vor Aufruf auf gleiche Adresse verweisen, nicht 0x0 (was ich dachte, vielleicht Verzug).

void free2D(double** matrix, int nrows) {
    int i;
    for(i=0;i<nrows;i++) {
        free(matrix[i]);
    }
free(matrix);
}

Meine Frage ist: Bin ich Mißverständnis wie malloc / free Arbeit? Andernfalls kann jemand vorschlagen, was los ist?

Alex

War es hilfreich?

Lösung

Wenn Sie einen Zeiger freizugeben, wird der Wert des Zeigers nicht ändern tut, wird explizit auf 0 setzen haben, wenn Sie es wollen null sein.

Andere Tipps

Im ersten Beispiel haben Sie nur den von malloc in einer lokalen Variablen zurückgegebene Zeiger gespeichert. Es ist verloren, wenn die Funktion zurückkehrt.

Übliche Praxis in der C-Sprache ist die Funktion des Rückgabewert zu verwenden, um den Zeiger auf ein reserviertes Objekt zurück an den Aufrufer übergeben. Wie Arme wiesen darauf hin, können Sie auch einen Zeiger übergeben, wo die Funktion seine Ausgabe gespeichert werden sollte:

void Allocate2D(double*** pMatrix...)
{
   *pMatrix = malloc(...)
}

, aber ich denke, die meisten Leute so schnell schreien würden, wie sie *** sehen.

Sie könnten auch erwägen, dass Arrays von Zeigern sind keine effiziente Implementierung von Matrizen. jede Zeile separat Zuteilen trägt zur Speicherfragmentierung, malloc Overhead (da jede Zuordnung eine Buchhaltung beinhaltet, nicht die zusätzlichen Zeiger Sie speichern müssen zu schweigen), und Cache-Misses. Und jeder Zugriff auf ein Element der Matrix umfasst zwei Zeiger dereferenziert und nicht nur eine, die Stände vorstellen kann. Schließlich haben Sie viel mehr Arbeit, die Matrix zu tun Zuteilung, da man für das Scheitern jeder malloc und Bereinigung alles zu überprüfen haben Sie bereits getan, wenn eine von ihnen nicht.

Ein besserer Ansatz ist ein eindimensionales Array zu verwenden:

double *matrix;
matrix = malloc(nrows*ncols*sizeof *matrix);

dann Zugriffselement (i, j) als matrix[i*ncols+j]. Die möglichen Nachteile sind die Multiplikation (das langsam auf alten CPUs ist aber schnell auf modernere) und die Syntax.

Ein noch besserer Ansatz ist es nicht überschüssige Allgemeinheit zu suchen. Die meist Matrix-Code auf SO ist nicht für fortgeschrittene numerische Mathematik, wo beliebige Matrixgrößen benötigt werden könnten, aber für 3D-Spiele, wo 2x2, 3x3 und 4x4 sind die einzigen Matrixgrößen von praktischem Nutzen. Wenn das der Fall ist, versuchen Sie so etwas wie

double (*matrix)[4] = malloc(4*sizeof *matrix);

und dann können Sie Element zugreifen (i, j) als matrix[i][j] mit einem einzigen dereferenzieren und eine extrem schnellen Multiplikation mit konstant. Und wenn Ihr matrix nur bei lokalen Bereich oder innerhalb einer Struktur benötigt wird, erklären sie wie:

double matrix[4][4];

Wenn Sie mit dem C-Typ-System nicht sehr versiert sind und die Erklärungen oben, könnte es am besten sein, nur alle Ihre Matrizen in structs wickelt sowieso:

struct matrix4x4 {
    double x[4][4];
};

Dann Erklärungen, Zeiger Abgüsse, Zuweisungen usw. werden viel mehr vertraut. Der einzige Nachteil ist, dass Sie so etwas wie matrix.x[i][j] oder matrix->x[i][j] (je nachdem, ob matrix ist eine Struktur der Zeiger auf struct) anstelle von matrix[i][j].

tun müssen

Edit: Ich glaube an eine nützliche Eigenschaft Ihrer Matrizen als Arrays von Zeilenzeiger Umsetzung - es Permutation der Zeilen eine triviale Operation macht. Wenn Ihre Algorithmen benötigen viel Reihenpermutation auszuführen, kann dies von Vorteil sein. Beachten Sie, dass der Nutzen nicht viel für kleine Matrizen sein wird, aber, und als Spaltenpermutation nicht auf diese Weise optimiert werden kann.

In C ++ Sie sollten den Mauszeiger über einen Verweis :)

Allocate2D(double**& matrix...)

In Bezug auf, was los ist - auch Sie einen Zeiger haben, die NULL ist, übergeben Sie die Kopie dieser Zeiger auf die Funktion, die mamory zugewiesen und initialisiert die Kopie des Zeigers mit der Adresse des neu zugewiesenen Speichers, aber Ihre ursprünglichen Zeiger bleibt NULL. Wie kostenlos müssen Sie nicht durch Verweis übergeben, da nur der Wert des Zeigers relevant ist. HTH

Da es keine Hinweise in C sind, können Sie durch den Zeiger passieren kann, das heißt

Allocate2D(double*** pMatrix...)
{
   *pMatrix = malloc(...)
}

und später Aufruf wie

Allocate2D(&matrix ...)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top