mehrfaches Freigeben von allokiertem Speicher verhindern
-
Hallo c-Community,
ich habe mal wieder eine Frage. Diesmal eher eine stilistische zum allokieren und freigeben von Speicher.
Also folgende Situation. Ich habe einen Buffer, den ich an mehreren Stellen benötige. Dieser wird in der Regel freigegeben und neu allociert. Dies habe ich folgender MAßen gemacht:
if (Buffer != NULL) free(Buffer); Buffer = malloc(sizeof(char) * BUFFER));
Bei einer solchen Verwendung kommt es jetzt aber regelmäßig vor, dass Buffer nicht NULL aber freigegeben ist (Ich weiß da ist ein Fehler also in meiner Logik).
Welche Wege gibt es ohne den genauen Zustand von Buffer zu kennen, sicher zu stellen, dass der Buffer "frei und leer" ist?
Ich habe mir schonmal die Funktion CLEAR:
#define CLEAR(x) memset(&(x), 0, sizeof(x))
aber diese kopiert ja auch nur Nullen in den Puffer (so wie ich das verstehe) und gibt ihn nicht frei.
Um die Frage nach dem ständigen neuallokieren vorweg zu nehmen: Ich benötige den Buffer in unterschiedlichen Längen zwischen 1024 und ca 360000, jenachdem wie ich das im Programm errechne. Deswegen freigeben und neuallocieren. An einen statischen Buffer mit der Größe 360000 finde ich aber nicht so toll. Falls das aber die "beste" Möglichkeit ist, werde ich sie aber in Erwägung ziehen. Hoffe aber es gibt andere Methoden.
MfG
mirrowwinger
-
Für Anfänger gibt es da noch das gute alte realloc. Wollte ich nur mal erwähnen, da du es offensichtlich nicht kennst. Es behebt aber an sich nicht die Probleme, die du durch schludrigen Stil hast.
Die richtige Vorgehensweise wäre, es so zu machen wie in C++ und ähnlichen Sprachen (falls du das kennst), bloß eben in C. Das heißt, jede Ressource (hier Speicher) wird in einem ressourcenhaltenden "Objekt" gespeichert, welches ganz genau weiß, wie es mit dieser Ressource umzugehen hat (C++-Stichwort: RAII). In C musst du dabei eine gehörige Portion Selbstdisziplin aufbringen, da du alles das, was in C++ der Compiler für dich macht (automatisches Allokieren und Freigeben, Schutz der privaten Daten) von Hand an den Stellen machen musst, an denen es in C++ für dich erledigt würde. was aber zum Glück immer noch wesentlich weniger Aufwand und auch viel einfacher ist, als jede Ressource manuell zu verfolgen. In C++ kann mit dieser Technik, abgesehen von absichtlichem Missbrauch, gar kein Fehler mehr entstehen, in C hast du eine ähnliche Sicherheit, solange du die Aufrufe des "Konstruktors" und "Destruktors" nicht vergisst. Falls du trotzdem einen Fehler hast, dann weiß du wenigstens, wonach du gucken musst.
Konkret für dein Problem dynamischer Arrays: Du musst std::vector aus C++ nachprogrammieren. Insbesondere Konstruktor (auch Kopierkonstruktor!), Destruktor und Zuweisungsoperator. Hier natürlich auch noch resize. Dann benutzt du den Konstruktor am Anfang des Gültigkeitsbereiches, in dem das Objekt lebt, und den Destruktor am Ende. Bei Zuweisungen und Kopien unbedingt die passende Funktion benutzen!
Diese Technik betont ganz stark die Idee, dass das ressourcenhaltende Objekt und mit ihr die Ressource in einem Gültigkeitsbereich lebt. Dies macht ganz sauber klar, wo die Verantwortung für die Ressource liegt. Die bei Anfängern beliebte Frickeltechnik, Speicher wild in irgendwelchen Funktionen zu allokieren und später ganz woanders (oder gerne auch mal gar nicht) wieder frei zu geben, wird dadurch verhindert. Das ist auch gut so, denn letzteres führt immer nur zu Fehlern und schwer verfolgbarem Programmablauf. Ich habe den Eindruck, dass du aber genau so etwas tust.Der GCC kennt übrigens eine C-Erweiterung, die die automatischen Konstruktoren und Destruktoren aus C++ nach C bringt:
http://en.wikipedia.org/wiki/RAII#GCC_extensions_for_CReicht dir das als Erklärung oder brauchst du ein Beispiel. Ein Beispiel wäre ziemlich lang, da selbst ein minimales Programm mit dieser Technik ziemlich viel drumherum benötigt. Das gute ist aber, dass man dann bereits alles hat. Es wird nicht mehr, egal wie komplex das Programm sonst noch wird. Es sit sogar ziemlich universell einsetzbar, so dass man es bloß ein einziges Mal im Leben schreiben braucht. Bloß gibt es eben keine halbe Ressourcenverwaltung, ganz oder gar nicht. Daher würde ich ungern ein komplettes Beispiel geben müssen.
-
also ein kleines Beispiel wäre vieleicht nicht schlecht.
-
mirrowwinger schrieb:
einen statischen Buffer mit der Größe 360000 finde ich aber nicht so toll. Falls das aber die "beste" Möglichkeit ist, werde ich sie aber in Erwägung ziehen. Hoffe aber es gibt andere Methoden.
Es wäre mit Sicherheit die schnellste Variante.
Möglicherweise würde aber dein System einen Stackoverflow melden.Nun hast du relativ wenig Infos darüber rausgerückt, was dein Programm machen soll. Falls du mehr Infos postest kann man dir gezielt Tipps geben, wie du die Sache angehen musst.
Was ich überhaupt nicht verstehen kann, dass dir ein erfahrener Moderator verklickern will, dass du std::vector nachprogrammieren müsstest, ohne zu wissen, was dein Programm leisten soll. Was für ein Quatsch!!!
-
Ein einfaches
if (Buffer != NULL) { free(Buffer); Buffer = NULL; } ... Buffer = malloc(sizeof(char) * BUFFER));
Versteckt ja nur dein Problem.
Denn es kann ja auch jederzeit ein
Buffer2 = Buffer;
davor stehen. Und dann zeigt Buffer2 ins Nirvana.Und dein CLEAR löscht nicht den Buffer sondern setzt den Zeiger auf NULL. (Also genau so wie
Buffer = NULL;
)
-
furious goose schrieb:
Was ich überhaupt nicht verstehen kann, dass dir ein erfahrener Moderator verklickern will, dass du std::vector nachprogrammieren müsstest, ohne zu wissen, was dein Programm leisten soll. Was für ein Quatsch!!!
Das ist die Antwort auf die sehr allgemeine Frage
Welche Wege gibt es ohne den genauen Zustand von Buffer zu kennen, sicher zu stellen, dass der Buffer "frei und leer" ist?
Die letztendliche, allgemeine Lösung ist eben gerade solch ein Konstrukt.
-
...
-
wozu?
-
...
-
okay, mal sehen wer noch außer dir lust hat, ins blaue zu schießen.
-
mirrowwinger schrieb:
Ich habe mir schonmal die Funktion CLEAR:
#define CLEAR(x) memset(&(x), 0, sizeof(x))
Das macht für Zeiger nicht das was du erwartest und für Arrays UB.