2008-09-19 7 views
6

Ich habe einige Probleme mit der Erstellung einer int-Matrix, ohne Speicherlecks zu erstellen. Ich möchte in der Lage sein, eine gegebene (globale) Matrix über read_matrix() dynamisch in eine beliebige Größe zu bringen. Aber dann möchte ich die Erinnerung später freigeben können. In meiner Hauptmethode sollte der zweite printf zu einem Busfehler führen, da ihm kein Speicher zugewiesen werden sollte. Wie würde ich das schaffen?int Matrix mit Zeigern in C - Speicherzuordnung Verwirrung

int**  first_matrix; 
int**  second_matrix; 
int**  result_matrix; 

int** read_matrix(int size_x, int size_y) 
{ 
    int** matrix; 
    matrix = calloc(size_x, sizeof(int*)); 
    for(int i = 0;i<size_x;i++) { 
     matrix[i] = calloc(size_y, sizeof(int)); 
    } 
    for(int i = 0;i<size_x;i++) { 
     for(int j = 0;j<size_y;j++) { 
      matrix[i][j] = i*10+j; 
     } 
    } 
    return matrix; 
} 

int main(int stackc, char** stack) 
{ 
    first_matrix = read_matrix(10,10); 
    printf("9:3 %d - 4:6 %d \n", first_matrix[9][3], first_matrix[4][6]); 
    free(*first_matrix); 
    free(first_matrix); 
    printf("9:3 %d - 4:6 %d \n", first_matrix[9][3], first_matrix[4][6]); 
} 

Antwort

9

Nur weil der Speicher frei ist bedeutet nicht, dass Sie nicht darauf zugreifen können! Natürlich ist es eine sehr schlechte Idee, darauf zuzugreifen, nachdem es frei ist, aber das ist, warum es in Ihrem Beispiel funktioniert.

Beachten Sie, dass free(*first_matrix) nur frei first_matrix[0], nicht die anderen Arrays. Sie möchten wahrscheinlich eine Art Marker, um das letzte Array zu kennzeichnen (es sei denn, Sie werden immer wissen, wann Sie das äußere Array freigeben, wie viele innere Arrays Sie zugewiesen haben).Etwas wie:

int** read_matrix(int size_x, int size_y) 
{ 
    int** matrix; 
    matrix = calloc(size_x, 1+sizeof(int*)); // alloc one extra ptr 
    for(int i = 0;i<size_x;i++) { 
     matrix[i] = calloc(size_y, sizeof(int)); 
    } 
    matrix[size_x] = NULL; // set the extra ptr to NULL 
    for(int i = 0;i<size_x;i++) { 
     for(int j = 0;j<size_y;j++) { 
      matrix[i][j] = i*10+j; 
     } 
    } 
    return matrix; 
} 

Dann, wenn man sie sind befreit:

// keep looping until you find the NULL one 
for(int i=0; first_matrix[i] != NULL; i++) { 
    free(first_matrix[i]); 
} 
free(first_matrix); 
+0

es scheint, dass die Schleife bis Matrix [i]! = NULL funktioniert, auch wenn ich nicht den letzten Zeiger auf NULL setzen, ist diese Koinzidenz/etwas anderes schlecht? – Fredrik

+0

Wenn Sie einen zusätzlichen Zeiger zuweisen und ihn nicht setzen, wird * * standardmäßig auf NULL gesetzt, abhängig vom Betriebssystem (Windows setzt den zugewiesenen Speicher auf Null, Unix nicht). Wenn dies nicht der Fall ist, werden Sie das Ende des zugewiesenen Arrays verlassen und die Dinge freigeben, bis Sie einen NULL-Zeiger oder (wahrscheinlich) einen Absturz erleiden. –

+1

Calloc setzt den Speicher immer auf null. – quinmars

2

Sie müssen individuell jede Zeile befreien:


void free_matrix(int **matrix, int size_x) 
{ 
    for(int i = 0; i < size_x; i++) 
     free(matrix[i]); 
    free(matrix); 
} 
+0

Sie können keine Variable im For-Zyklus in C deklarieren. – terminus

+2

Sie können in C99, aber Ihr Code ist nicht portabel. –

0

Sie befreit nur die erste Zeile (oder Spalte) von first_matrix. Schreiben Sie eine andere Funktion wie folgt aus:

void free_matrix(int **matrix, int rows) 
{ 
    int i; 
    for(i=0; i<rows; i++) 
    { 
     free(matrix[i]); 
    } 
    free(matrix); 
} 

Vielleicht möchten Sie die Matrix in einer Struktur, um zu speichern, es ist Zeilen- und Spaltenzahl.

1

Das Freigeben des Speichers macht es nicht weg, es bedeutet nur, dass eine andere Zuordnung denselben Speicherbereich abrufen kann. Was immer du hineinlegst, wird immer noch da sein, bis etwas anderes es überschreibt.

Sie befreien auch nicht alles, was Sie zugewiesen haben. Sie befreien nur das Array von Zeigern und die erste Zeile. Aber selbst wenn Sie alles richtig freigeben, würden Sie immer noch den gleichen Effekt haben.

Wenn Sie einen "Busfehler" erstellen möchten, müssen Sie auf Speicher verweisen, der nicht zu Ihrem Prozess gehört. Warum willst du das überhaupt machen?

+0

Ich wollte das nur tun, um zu zeigen, dass die Erinnerung frei war, aber jetzt gelernt habe, dass der Fehler in meinem Denken lag, kann Valgrind nicht ausführen, da ich onOS X bin und einen Weg sehen wollte, ob ich es wirklich befreit hätte – Fredrik

0

Ich empfehle die Verwendung von Valgrind, um unfrei Speicher zu finden, im Gegensatz zu versuchen, einen Busfehler auftreten zu lassen. Es rockt auch für viele andere Sachen.

Sam

+0

Ich bin auf OS X, so kann ich Valgrind nicht ausführen, sonst würde ich:/ Sie wissen, jede Alternative, die auf Mac funktioniert? – Fredrik

0

Sie Speicherlecks bekommen, weil Sie die erste Zeile der Matrix und die Liste der Zeilen sind zu befreien, aber keiner der 1 bis n-ten Reihen. Sie müssen in einer Schleife frei anrufen.

Es gibt ein paar Alternativen, aber: - Weisen Sie sizeof (int *) Zeilen + Reihen cols * sizeof (int) Bytes und die ersten Bytes für die Zeilenzeiger verwenden. Auf diese Weise haben Sie nur einen einzigen Speicherbereich frei (und es ist auch einfacher für den Zuordner) - Verwenden Sie eine Struktur, die die Anzahl der Zeilen enthält. Dann können Sie die Zeilenliste ganz vermeiden (Speicher sparen). Der einzige Nachteil ist, dass Sie eine Funktion, ein Makro oder eine unordentliche Notation verwenden müssen, um die Matrix zu adressieren.

Wenn Sie mit der zweiten Option gehen, können Sie eine Struktur wie diese in jedem C99-Compiler verwenden und wiederum nur einen einzigen Speicherblock zuweisen (der Größe numints * sizeof (int) + sizeof (int)) :

0

Das Konzept Sie hier fehlt, ist, dass für jeden calloc, muss es eine frei sein. und dass free muss auf den vom Calloc übergebenen Zeiger angewendet werden.

Ich empfehle Ihnen, eine Funktion (genannt delete_matrix) erstellen , die eine Schleife verwendet alle Zeiger zu befreien, die Sie in hier zuteilen

for (int i = 0; i < size_x; i ++) { Matrix [i] = Calloc (Größe_y, Größevon (Int)); }

Dann, sobald das erledigt ist, geben Sie den zugewiesenen Zeiger frei.

matrix = Aufruf (size_x, sizeof (int *));

So wie du es jetzt,

kostenlos (* first_matrix) tun werden; frei (erste_matrix);

wird nicht tun, was Sie tun wollen.