2015-11-11 5 views
5

Ich bin derzeit mit c herumspielen Ich habe ein paar Schluckauf in der Zeigerverwendung und Syntaxbereich.Malloc'ing Arrays und dann Free'ing sie?

Unten (ich versuche) ein Array von Zeigern zu Integer-Arrays zu erstellen, dann jeden Zeiger auf ein Array zu richten, das über malloc() erstellt wurde.

Nachdem die Arrays erstellt wurden, gehe ich dann für jede Zelle durch und lege einen Wert fest.

Jetzt scheint das alles zu funktionieren, aber wenn es darum geht, free() zu verwenden, um den Speicher zurückzunehmen, stürzt das Programm ab.

Ich habe festgestellt, dass, wenn ich malloc() den Array-Speicher und dann sofort kostenlos() auf sie aufrufen, das Programm ohne Problem ausgeführt wird. Wenn ich jedoch malloc() Werte vergebe und DANN frei rufe() wird der Absturz auftreten. (Segmentierungsfehler)

Unten ist der Code, danach frei, malloc() dann sofort frei() ing

int (*ptrArr[5])[5]; 

for(int i=0; i<5; i++) 
    ptrArr[i] = malloc(sizeof(int) * 5); 

for(int i=0; i<5; i++) 
    printf("ptrArr[%d][%x]->[%x]\n", i, &ptrArr[i], &*ptrArr[i]); 
printf("\n"); 

for(int i=0; i<5; i++){ 
    for(int j=0; j<5; j++){ 
     printf("[%x](%2d) | ", &*ptrArr[i][j], *ptrArr[i][j]); 
    } 
    printf("\n"); 
} 

for(int i=4; i>=0; i--) 
    free(ptrArr[i]); 

die oben ausführt, wie ich es erwartet, aber wenn ich Werte zuweisen Zellen und dann versuchen, und rufen Sie arbeitet ein Segmentierungsfehler generiert:

int (*ptrArr[5])[5]; 

for(int i=0; i<5; i++) 
    ptrArr[i] = malloc(sizeof(int) * 5); 

for(int i=0; i<5; i++) 
    printf("ptrArr[%d][%x]->[%x]\n", i, &ptrArr[i], &*ptrArr[i]); 
printf("\n"); 

for(int i=0; i<5; i++){ 
    for(int j=0; j<5; j++){ 
     printf("[%x](%2d) | ", &*ptrArr[i][j], *ptrArr[i][j]); 
    } 
    printf("\n"); 
} 

int loop = 5; 
for(int i=0; i<5; i++){ 
    for(int j=0; j<5; j++){ 
     *ptrArr[i][j] = (loop + (i*j)); 
     ++loop; 
    } 
} 

printf("\n"); 
for(int i=0; i<5; i++){ 
    for(int j=0; j<5; j++){ 
     printf("[%x](%2d) | ", &*ptrArr[i][j], *ptrArr[i][j]); 
    } 
    printf("\n"); 
} 

for(int i=4; i>=0; i--) 
{ 
    printf("Freeing ptrArr[%x]\n", i); 
    free(ptrArr[i]); 
} 

ich glaube, ich bin entweder die

int (*ptrArr[5])[5]; 
Mißverständnis

Deklaration, die ich beabsichtigte, war ein Array von 5 Zeigern, von denen jeder auf ein Integer-Array zeigt, oder ich werfe Zellen nicht korrekt Werte zu, sondern verdirbt Speicher, der verursacht, dass das free() fehlschlägt.

Jede Hilfe wäre willkommen, ich hoffe, die Frage ist klar und prägnant.

Danke.

+3

'int * ptrArr [5] 'deklariert ein Array von 5 Zeigern. –

+0

Ich glaube nicht, dass der erste Code funktioniert. Versuchen Sie es mit einer Größe größer als 5, vielleicht 10000 –

Antwort

2

So wie ich diese Art von Problem nähern ist aus den sizeof den verschieden Verdächtigen zu drucken, wie diese

int (*test[5])[5]; 

printf("%zu ", sizeof(test)); 
printf("%zu ", sizeof(test[0])); 
printf("%zu\n", sizeof(test[0][0])); 

Das Ergebnis ist 40 8 20. (Beachten Sie, dass auf meiner Maschine ein int 4 Bytes und ein Zeiger 8 Bytes ist.)
Also sagt mir, dass test ist ein Array von 5 Zeigern. Es folgt logisch, dass test[0] ein einzelner Zeiger ist. Interessant ist aber, dass test[0][0] ein Array von 5 Ints ist.

Wenn ich die folgende Zeile des Codes

printf("%zu\n", sizeof(test[0][0][0])); 

der Ausgang 4 ist, d.h. test[0][0][0] ist eine einzelne int. Daraus schließen wir, dass die Deklaration int (*test[5])[5] ein dreidimensionales Array deklariert, was nicht beabsichtigt ist.


Also lassen Sie uns eine einfachere Erklärung versuchen, wie diese

int (*test)[5]; 

printf("%zu ", sizeof(test)); 
printf("%zu ", sizeof(test[0])); 
printf("%zu\n", sizeof(test[0][0])); 

Der Ausgang 8 20 4 ist, was zu sagen ist, dass test ein einziger Zeiger ist, test[0] ist ein Array von 5 ints und test[0][0] ist eine einzige int. Wir schließen, dass int (*test)[5] ein zweidimensionales Array deklariert.


Die nächste Frage ist, wie wir Speicher für das Array reservieren.Wenn wir diese

test = malloc(5 * sizeof(int)); 

dann tun haben wir eine Reihe, die mit 1 Zeile und 5 Spalten hat, im wesentlichen eine eindimensionale Anordnung.

Um ein zweidimensionales Array mit N Reihen zu bekommen, wir

test = malloc(N * 5 * sizeof(int)); 

Dann müssen wir füllen können, drucken und frei das Array wie diese

int N = 5; 
for (int row = 0; row < N; row++) 
    for (int col = 0; col < 5; col++) 
     test[row][col] = (row+5)*10 + col; 

for (int row = 0; row < N; row++) 
{ 
    for (int col = 0; col < 5; col++) 
     printf("%2d ", test[row][col]); 
    printf("\n"); 
} 

free(test); 
0

Nun, das war ein Kopfschmerz zu entschlüsseln, aber wie ein gutes kryptisches Kreuzworträtsel gibt es eine Lösung. Ich habe die Dinge ein bisschen aufgeräumt. Das grundlegende Problem war die Dereferenzierung.

See: Order of operations for dereference and bracket-ref in C

Ich habe die Linie in einem gewissen Arbeits Code unten markiert. Ich habe Klammern um das (* ptrArr [i]) hinzugefügt, um das Array zu erhalten, das dann korrekt indiziert werden kann als (* ptrArr [i]) [j].

Ich habe auch eine alternative Möglichkeit vorgeschlagen, das Array an erster Stelle zu deklarieren. Eine, die einfacher zu überprüfen ist!

#include <stdlib.h> 
#include <stdio.h> 

#define SIZE 5 

int main() 
{ 
    // This makes things clearer :- 
    typedef int ArrayType[SIZE]; 
    typedef ArrayType * ArrayPtr; 
    ArrayPtr ptrArr[SIZE]; 

    for (int i = 0; i < SIZE; i++) 
     ptrArr[i] = malloc (sizeof (int) * SIZE); 

    int loop = SIZE; 

    for (int i = 0; i < SIZE; i++) 
    { 
     for (int j = 0; j < SIZE; j++) 
     { 
      // THIS NEXT LINE HAD THE WRONG BRACKETS IN 
      // *(ptrArr[i])[j] = (loop + (i * j)); 
      (*ptrArr[i])[j] = (loop + (i * j)); 
      printf("array has base address: %lx\n", ptrArr[i]); 
      printf("writing to: %lx\n", &(*ptrArr[i])[j]); 
      ++loop; 
     } 
    } 

    for (int i = SIZE-1; i >= 0; i--) 
    { 
     printf ("Freeing ptrArr[%x] with address %lx\n", i, ptrArr[i]); 
     free (ptrArr[i]); 
    } 
} 
0
for(int i=0; i<5; i++) 
    ptrArr[i] = malloc(sizeof(int) * 5); 

Dieses besagt, dass ptrArr[i] einige ganzen Zahlen ein Zeiger ist.

Dies besagt, dass ptrArr[i][j] ein Zeiger auf eine ganze Zahl ist.

Was ist das? Diese beiden Codeteile unterscheiden sich in der Anzahl der indirekten Ebenen.

0

Ihr erstes Beispiel ist nicht korrekt, weil Sie die falschen Array-Indizes drucken.

Die for-Schleife nested nennt dies:

printf("[%x](%2d) | ", &*ptrArr[i][j], *ptrArr[i][j]); 

Der dritte Parameter ist ptrArr[i][j][0] identisch.

Aber das ist falsch. Es sollte ptrArr[i][0][j] sein, da Sie nur eine innere Dimension Ihres 2d-Arrays mit dem Malloc-Aufruf zugewiesen haben: ptrArr[i] = malloc(sizeof(int) * 5);.

Sie sehen int (*ptrArr[5])[5]; ist wirklich ein Array von Zeigern zu einem Array von 5 Zoll. Und ptrArr[i] ist ein Zeiger auf ein Array von 5 Zoll.

Das bedeutet auch, dass der zweite Parameter &*ptrArr[i][j], der mit ptrArr[i][j] identisch ist, eigentlich ptrArr[i][0] sein sollte, weil wir wiederum nur eine Dimension zugewiesen haben.

...

Wir sind fast fertig. Ersetzen Sie zuerst den Malloc-Aufruf durch Calloc, so dass wir keine Garbage-Werte ausgeben. Ersetzen Sie dann% x printf-Spezifizierer durch% p und setzen Sie ihre jeweiligen Parameter auf (void *).

Mit diesen Korrekturen an Ort und Stelle, druckt das erste Beispiel die richtigen Adressen und korrekte Werte aus, und kein undefiniertes Verhalten. (Sie können auch redundante &* Paare entfernen)

(Dies war nur ein Update für Ihr erstes Beispiel, ich habe adressierte nicht einmal die zweiten. Aber die Lösung ist meist die gleiche.)

Verwandte Themen