Ich verwende malloc, um ein 2d char-Array dynamisch zuzuweisen. Wenn ich nicht jeden Array-Index vor free() auf NULL setze, wird beim Versuch von free() ein Segmentierungsfehler angezeigt. Warum erhalte ich einen Segmentierungsfehler?

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

int main(void) {

    int nrows = 20; int ncolumns = 10;
    char ** arr = malloc(nrows * sizeof(char *));
    for(int i = 0; i < nrows; i++)
        arr[i] = malloc(ncolumns * sizeof(char));

    arr[0] = "string1";
    arr[1] = "string2";

    // does not work without the following code:
    // for(int i = 0; i < 20; i++)
    //     arr[i] = NULL;

    for(int i = 0; i < 20; i++)
        free(arr[i]);
    free(arr);

    return 0;
}
c
5
Joe K 18 Jän. 2019 im 00:20

5 Antworten

Beste Antwort

Wenn Sie dies tun:

arr[0] = "string1";
arr[1] = "string2";

Sie überschreiben den Inhalt von arr[0] und arr[1], die die von malloc zurückgegebenen Speicheradressen enthalten, mit der Adresse von zwei Zeichenfolgenkonstanten. Dies führt zu einem Speicherverlust, da auf diesen Speicher nicht mehr zugegriffen werden kann. Dies ist auch der Grund, warum Sie beim Aufrufen von free abstürzen, da diese Variablen nicht mehr die Adressen des zugewiesenen Speichers enthalten.

Was Sie hier wahrscheinlich stattdessen tun möchten, ist die Verwendung von strcpy, wodurch der Inhalt des Zeichenfolgenliteral in den von Ihnen zugewiesenen Speicher kopiert wird.

strcpy(arr[0], "string1");
strcpy(arr[1], "string2");

Jetzt können Sie den Speicher ordnungsgemäß free.

3
dbush 17 Jän. 2019 im 21:25

Ihr Code ist in Ordnung. Das Problem ergibt sich aus der Tatsache, dass Sie Ihrem Array hier Zeichenfolge Literale zuweisen: arr[0] = "string1";.

Sie ersetzen also den Zeiger auf arr[0], der auf Ihren zugewiesenen Speicher zeigt, durch den Zeiger auf ein Zeichenfolgenliteral.

Zeiger auf Literale sind geschützt, Sie können sie nicht freigeben (oder ihnen schreiben), weil Sie sie nicht zugewiesen haben.

Um dieses Problem zu lösen, kopieren Sie mit strcpy den Wert Ihres Literal in den zugewiesenen Speicher:

strcpy(arr[0], "string1");
strcpy(arr[1], "string2");
3
SystemGlitch 17 Jän. 2019 im 21:27

Der Operator = kopiert nicht die Zeichenfolge, sondern weist nur den Zeiger zu. Daher ist Ihr malloced-Speicher für diese Array-Elemente nicht mehr zugänglich, und der Versuch, ihn freizugeben, ist ein undefiniertes Verhalten, das zum Segfault führen kann.

Sie müssen es mit strcpy kopieren.

1
P__J__ 17 Jän. 2019 im 21:25

Ein Absturz bei einem Aufruf von free ist ein Zeichen für eine falsche Speicherverwaltung an einer anderen Stelle in Ihrem Code. Wenn Sie einen Zeiger auf NULL und dann auf free setzen, stürzen Sie nicht ab, da free(NULL) nach dem C-Standard § 7.22.3.3 garantiert harmlos ist:

7.22.3.3 Die freie Funktion

... Wenn ptr ein Nullzeiger ist, wird keine Aktion ausgeführt . Ansonsten wenn Das Argument stimmt nicht mit einem Zeiger überein, der zuvor von einer Speicherverwaltung zurückgegeben wurde Funktion , oder wenn der Speicherplatz durch einen Aufruf zur Freigabe oder Neuzuweisung freigegeben wurde, wird die Verhalten ist undefiniert.

Hervorhebung von mir.

Wie andere Antworten festgestellt haben, versuchen Sie, free im Speicher aufzurufen, den Sie nicht explizit mit malloc -Familienfunktionen zugewiesen haben (da Sie arr[i] Zeiger mit Zeigern auf Zeichenfolgenliterale überschrieben haben).

1
Govind Parmar 17 Jän. 2019 im 21:46

Zwei Dinge zu wissen:

  • Sie haben zwei Bereiche in Ihrem Speicher (um das Verständnis zu erleichtern), Heap und Stack
  • malloc, realloc, calloc ordnen Ressourcen aus dem Heap zu. Ich werde nur malloc sagen (aber es ist das gleiche)
    • free kann nur Ressourcen vom Heap befreien. Der Stapel ist für den Compiler reserviert (er speichert Funktionsaufruf und andere Daten)

Die Regel für jede Ressource, die Sie von malloc erhalten, müssen Sie freigeben. Um zu befreien, rufen Sie einfach die freie Funktion auf (aber wir können optional einen Nullzeiger zuweisen, um sicherzugehen, dass er freigegeben ist).

char * a = malloc(255);

Befreien

free(a);/* this is mandatory */
a = NULL;/* we can add this to the first line */

Tatsächlich haben Sie die Gewohnheit, einen NULL-Wert zuzuweisen, und wenn Sie einmal auf den Wert zugreifen, tritt ein NULL-Deference-Fehler auf, sodass Sie wissen, wo Sie einen Fehler finden

Was Sie versuchen zu tun: Ordnen Sie ein Array char ** arr = malloc(nrows * sizeof(char *)); zu und Sie geben es frei free(arr);

Sie weisen jedoch 20 Arrays von char arr[i] = malloc(ncolumns * sizeof(char)); zu Sie ignorieren den Wert arr[0] = "string1"; (Sie verlieren den von malloc zurückgegebenen Wert, sodass Sie ihn jetzt nicht freigeben können arr [0]). Wir befinden uns nicht in C ++. "String1" befindet sich also auf dem Stapel (Malloc kann es also nicht freigeben) und du rufst kostenlos drauf an.

Was du tun kannst

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

int main(void) {

    int nrows = 20; int ncolumns = 10;
    char ** arr = malloc(nrows * sizeof(char *));
    for(int i = 0; i < nrows; i++)
        arr[i] = malloc(ncolumns * sizeof(char));
    free(arr[0]);//know we can loose it value because it is freed
    arr[0] = NULL;// in fact we assign a value just after so this line is useless but is educationnal purpose
    free(arr[1]);//know we can loose it value because it is freed
    arr[1] = NULL;// in fact we assign a value just after so this line is useless but is educationnal purpose
    arr[0] = "string1";
    arr[1] = "string2";

    // does not work without the following code:
    // for(int i = 0; i < 20; i++)
    //     arr[i] = NULL;

    for(int i = 2; i < 20; i++)//we start at 2 because the first two value are on the stack
    {
        free(arr[i]);
        arr[i] = NULL;//this is useless because we will free arr just after the loop)
    }
    free(arr);
    arr = NULL;// this is useless because we exit the end of program

    return 0;
}
1
Et7f3XIV 17 Jän. 2019 im 21:52