malloc und Umfang

Ich kämpfe, um meinen Kopf um malloc in c zu wickeln - besonders wenn es frei sein muss() 'd. Ich bekomme komische Fehler in gcc, wie:

... free (): ungültig nächste Größe (fast): ...

wenn ich versuche, einen Char-Zeiger freizugeben. Wenn Sie beispielsweise aus einer Eingabedatei lesen, stürzt sie bei bestimmten Zeilen ab:

FILE *f = fopen(file,"r");
char x[256];
while(1) {
    if(fgets(x,sizeof x,f)==NULL) break;
    char *tmp = some_function_return_char_pointer(x); //OR malloc(nbytes);
   //do some stuff
    free(tmp);//this is where I get the error, but only sometimes
}

Ich habe nach offensichtlichen Dingen gesucht, z. B. dass x NULL ist, aber das ist es nicht; es stürzt nur auf zufälligen Zeilen ab.

Aber meine wahre Frage ist - Wann brauche ich free() ? Oder, richtiger, wann sollte ich NICHT kostenlos nutzen? Was ist, wenn malloc in einer Funktion ist, und ich die Variable zurückgeben, die malloc() verwendet hat? Was ist mit einer For- oder While-Schleife? Hat malloc-ing für ein Array von struct dieselben Regeln wie für einen string/char-Pointer?

Ich erfahre von den Fehlern, die ich in gcc auf Programmabsturz bekomme, dass ich gerade malloc nicht verstehe und frei bin. Ich habe meine wertvolle Zeit mit Google verbracht und stoße immer noch auf Mauern. Gibt es irgendwelche guten Ressourcen, die du gefunden hast? Alles, was ich sehe, sagt, dass wenn ich malloc benutze, ich kostenlos verwenden muss. Aber dann versuche ich das und mein Programm stürzt ab. Vielleicht ist es anders, basierend auf dem Umfang einer Variablen? Gibt C den Speicher am Ende einer Schleife frei, wenn darin eine Variable deklariert wird? Am Ende einer Funktion?

Damit:

for(i=0;i<100;i++) char *x=malloc(n);//no need to use free(x)?

aber:

char *x;
for(i=0;i<100;i++) {
    x=malloc(n);
    free(x); //must do this, since scope of x greater than loop?
}

Ist das richtig?

Hoffentlich mache ich Sinn ...

1
alles, was Sie malloc (), Sie frei (einmal), wenn Sie es nicht mehr benötigen.
hinzugefügt der Autor Mitch Wheat, Quelle
Bist du malloc'ing null Bytes ...? bytes.com/topic/c/answers/578467- was-wäre-malloc-0-sollte-Return & zwnj; s EDIT: , um diese Gewohnheit Sache einfach realisiert werden, wie Sie können nach wie vor kostenlos (... ) der Zeiger, unabhängig.
hinzugefügt der Autor cwharris, Quelle

7 Antworten

malloc() is C's dynamic allocator. You have to understand the difference between automatic (scoped) and dynamic (manual) variables.

Automatic variables live for the duration of their scope. They're the ones you declare without any decoration: int x;

Most variables in a C program should be automatic, since they are local to some piece of code (e.g. a function, or a loop), and they communicate via function calls and return values.

Die only Zeit, die Sie für die dynamische Zuweisung benötigen, liegt vor, wenn Sie einige Daten haben, die einen bestimmten Bereich überstehen müssen. Solche Daten müssen dynamisch zugewiesen und schließlich freigegeben werden, wenn sie nicht mehr benötigt werden.

Das Hauptanwendungsbeispiel hierfür ist Ihre typische verknüpfte Liste . Die Listenknoten können möglicherweise nicht für jeden Bereich lokal sein, wenn Sie generische Funktionen zum Einfügen/Löschen/Suchen von Listen bearbeiten möchten. Daher muss jeder Knoten dynamisch zugewiesen werden, und die Listenmanipulationsfunktionen müssen sicherstellen, dass sie diejenigen Knoten freigeben, die nicht länger Teil der Liste sind.

Zusammenfassend ist die Variablenzuweisung grundsätzlich und vor allem eine Frage von scope . Wenn möglich, halte alles automatisch und du musst nichts tun. Verwenden Sie bei Bedarf die dynamische Zuordnung und achten Sie darauf, dass die Zuordnung manuell aufgehoben wird.

( Bearbeiten: Wie @Oli sagt, möchten Sie vielleicht auch die dynamische Zuweisung in einem streng lokalen Kontext verwenden, da die meisten Plattformen die Größe von automatischen Variablen auf eine viel kleinere Grenze begrenzen als die Größe von dynamic Denken Sie an "riesige Arrays". Das Überschreiten des verfügbaren Platzes für automatische Variablen hat normalerweise einen farbigen Namen wie "Stapelüberlauf" oder etwas Ähnliches.)

5
hinzugefügt
+1 für den Hinweis, die dynamische Zuordnung möglichst zu vermeiden.
hinzugefügt der Autor R.., Quelle
@OliCharlesworth: Ah, ja, ein weiterer guter Punkt! Bearbeitet.
hinzugefügt der Autor Kerrek SB, Quelle
Ehrfürchtige Erklärung, wann es (nicht) passend zu malloc ist
hinzugefügt der Autor g33kz0r, Quelle
Die Art, wie du es erklärt hast, hat definitiv geholfen. Von PHP kommend, wo $ x = "eine Zeichenfolge"; , habe ich versucht, malloc zu verwenden hat den Ersatz für die Zuweisung; es ist viel sinnvoller, es als dynamische und nicht automatische Zuweisung zu beschreiben
hinzugefügt der Autor cegfault, Quelle
Eine Instanz der dynamischen Zuweisung, die nicht auf den überlebenden Bereich hinausläuft, ist, wenn Sie ein riesiges Array (z. B. eine Million Elemente) benötigen, das den Stack zerstören würde.
hinzugefügt der Autor Oliver Charlesworth, Quelle

Im Allgemeinen muss jeder Aufruf von malloc einen entsprechenden Aufruf free haben. * Das hat nichts damit zu tun Umfang (dh nichts mit Funktionen oder Schleifen zu tun).


* Ausnahmen von dieser Regel beinhalten Funktionen wie strdup , aber das Prinzip ist das gleiche.
3
hinzugefügt
@xixonia: Ein Absturz ist das Best-Case-Szenario und nicht das, was Sie erwarten sollten. Der schlimmste Fall ist, einem Angreifer Root zu geben.
hinzugefügt der Autor R.., Quelle
@xixonia: Fertig!
hinzugefügt der Autor Oliver Charlesworth, Quelle
@R .., das alles bringt mich nur dazu, wieder in C zu kommen :)
hinzugefügt der Autor cwharris, Quelle
Es ist wichtig zu beachten, dass das zweimalige Aufrufen von free (...) zu einem Absturz führen kann.
hinzugefügt der Autor cwharris, Quelle

Grob gesagt muss jeder Zeiger, der jemals von malloc() zurückgegeben wird, schließlich an free() übergeben werden. Der Gültigkeitsbereich der Variablen, in der Sie den Zeiger in speichern, wirkt sich nicht darauf aus, da der Speicher, auf den der Zeiger verweist, auch nach dem Aufrufen von free() darauf.

2
hinzugefügt

Nun, der Umfang des Malloc'd-Speichers liegt zwischen den Aufrufen von malloc und free oder anders, bis der Prozess gestoppt wird (dh wenn OS für den Prozess aufräumt). Wenn Sie nie free aufrufen, erhalten Sie ein Speicherleck. Das kann passieren, wenn die Adresse, die Sie an free weitergeben können, vor der eigentlichen Nutzung nicht mehr gültig ist - das ist, als würden Sie Ihre Schlüssel für das Auto verlieren, das Auto ist noch da, aber Sie können es nicht wirklich fahren . Der Fehler, den Sie erhalten, ist höchstwahrscheinlich entweder, weil die Funktion einen Zeiger auf Speicher zurückgibt, der nicht mit malloc zugewiesen wurde, oder einen Nullzeiger zurückgibt, den Sie an free übergeben du kannst nicht tun.

1
hinzugefügt
Streng genommen ist das Wort in C "Speicherdauer", nicht "Lebensdauer". :-)
hinzugefügt der Autor R.., Quelle
@OliverCharlesworth, oh snap kämpft Wörter :: Pops popcorn ::
hinzugefügt der Autor user1717828, Quelle
Du meinst "Lebenszeit", nicht "Geltungsbereich". Gültigkeitsbereich gilt für Bezeichner, nicht für Objekte.
hinzugefügt der Autor Oliver Charlesworth, Quelle
@R ..: Nein, ich meine wirklich "Lebenszeit"; siehe 6.2.4 Satz 2.
hinzugefügt der Autor Oliver Charlesworth, Quelle

Sie sollten Speicher freigeben, wenn Sie nicht mehr darauf zugreifen. Sie sollten keinen Speicher freigeben, wenn Sie darauf zugreifen. Dies wird dir viel Schmerz bereiten.

0
hinzugefügt

malloc (n) ordnet n Bytes des Speichers von einem Speicherort namens heap zu und gibt dann einen Zeiger void * zurück. Der Speicher wird zur Laufzeit zugeordnet. Sobald Sie einen Speicher dynamisch zugewiesen haben, spielt der Gültigkeitsbereich keine Rolle, solange Sie einen Zeiger auf ihn (oder die Adresse davon) haben. Beispielsweise:

int* allocate_an_integer_array(int n)
{
    int* p = (int*) (malloc(sizeof(int)*n));
    return p;
}

Diese Funktion teilt einfach Speicher von Heap gleich n Ganzzahlen zu und gibt einen Zeiger auf den ersten Speicherort zurück. Der Zeiger kann in der aufrufenden Funktion wie gewünscht verwendet werden. Das SCOPE spielt keine Rolle, solange der Zeiger bei dir ist.

free (p) gibt den Speicher an Heap zurück.

Das Einzige, an das Sie sich erinnern müssen, ist, es freizugeben, als ob Sie es nicht freigeben und den Wert seiner Adresse verlieren, da es zu einem Speicherleck kommt. Es ist so, weil Sie nach OS immer noch den Speicher verwenden, da Sie ihn nicht freigegeben haben und ein Speicherverlust auftritt.

Setzen Sie den Wert des Zeigers auch nach dem Freigeben auf null, damit Sie ihn nicht erneut verwenden, da der gleiche Speicher möglicherweise zu einem anderen Zeitpunkt für einen anderen Zweck erneut zugewiesen wird.

Also, alles, was Sie tun müssen, ist vorsichtig zu sein ...

Ich hoffe es hilft!

0
hinzugefügt

Wenn Sie Speicherverlust nicht möchten, müssen Sie den Speicher von malloc befreien.

Es kann sehr schwierig sein. Zum Beispiel, wenn der //einige Sachen einen continue hat, wird der freie Code übersprungen und führt zu einem Speicherleck. Es ist schwierig, also haben wir shared_ptr in C ++; und Gerücht hat es Gehalt von C-Programmierer ist höher als C ++ - Programmierer.

Manchmal kümmern wir uns nicht um Speicherlecks. Wenn der Speicher etwas enthält, das während der gesamten Ausführungsdauer benötigt wird, können Sie wählen, dass es nicht freigegeben wird. Beispiel: Eine Zeichenfolge für die Umgebungsvariable.

PS: Valgrind ist ein Tool zur Erkennung von Speicherfehlern. Besonders nützlich für Speicherlecks.

0
hinzugefügt
Wenn meine Kollegen einen Speicherverlust im Bibliothekscode hinterlassen, hebe ich ein Ticket an und bringe sie dazu, es zu reparieren ...
hinzugefügt der Autor Oliver Charlesworth, Quelle
Nein, tun wir nicht, wir können einfach unser Gedächtnis richtig aufräumen.
hinzugefügt der Autor Oliver Charlesworth, Quelle
Vernachlässigung, etwas zu befreien, nur weil es lebenslang ist, ist die ganze Ausführung sehr schlechte Praxis. Für einen Anfang überschwemmt es Ihre Valgrind-Ausgabe mit Fehlern.
hinzugefügt der Autor Oliver Charlesworth, Quelle
Ich stimme zu. Aber damit müssen wir leben.
hinzugefügt der Autor Cha Cha, Quelle
Sie tun dies nicht nur, wenn Sie als einziger Code schreiben und keine Bibliothek verwenden. Realität ist der Code deiner Kollegen so; und die Bibliotheken, auf die Sie angewiesen sind, können den Speicher nicht freigeben.
hinzugefügt der Autor Cha Cha, Quelle
Okay, Sie haben einen Punkt. Ich werde meine Kollegen davon überzeugen, die Erinnerung an putenv (strdup (...)) zu befreien. Ich werde versuchen, sie zur Arbeit zu bringen. Vielen Dank.
hinzugefügt der Autor Cha Cha, Quelle