Dreimal Speicher anfordern im selben Unterprogramm?


  • Mod

    Normalerweise regelt man das so, dass derjenige, der den Speicher anfordert, diesen auch wieder frei gibt. Eine Funktion gibt dann nie etwas zurück, was man hinterher freigeben muss, sondern ist eine in sich möglichst geschlossene Einheit. Wenn eine Funktion Speicher zum Befüllen braucht, dann reserviert der aufrufende diesen Speicher und gibt der Funktion einen Zeiger da drauf, damit diese da hinein schreiben kann.



  • SeppJ schrieb:

    Normalerweise regelt man das so, dass derjenige, der den Speicher anfordert, diesen auch wieder frei gibt. Eine Funktion gibt dann nie etwas zurück, was man hinterher freigeben muss, sondern ist eine in sich möglichst geschlossene Einheit. Wenn eine Funktion Speicher zum Befüllen braucht, dann reserviert der aufrufende diesen Speicher und gibt der Funktion einen Zeiger da drauf, damit diese da hinein schreiben kann.

    "Eine Funktion gibt dann nie etwas zurück, was man hinterher freigeben muss"

    Also heißt das das, wenn ich nichts zurückgeben muss "void" verwenden kann.

    Aber wo soll ich nun die 3 Speicher wieder freigeben?


  • Mod

    Nein, da hast du mich falsch verstanden. Beschäftige dich bitte erst einmal mit den Grundlagen, wie man Sachen aus einer Funktion zurückgeben kann und was die Unterschiede zwischen den verschiedenen Techniken sind. Sonst machen die Antworten keinen Sinn, weil du sie nicht verstehst.



  • c_anfaenger_C schrieb:

    Nur kann ich nicht 3 Werte(da es 3 Pointer sind) zusammen zurückgeben, da man ja nur einen Wert vom Unterprogramm ins Hauptprogramm zurückgeben kann.

    Doch. Als normalen Rückgabewert kann man zwar nur einen Wert zurückgeben, aber darüber hinaus kann man beliebig mehr Werte zurückgeben, indem man einfach Pointer auf Variablen als Parameter übergibt, in die das Unterprogramm dann die Werte speichert. Wenn du auf diese Weise Pointer zurückgeben willst, musst du als Parameter also Pointer auf Pointer übergeben:

    #include <stdlib.h>
    
    void unterprogramm(char **pointer1, char **pointer2, char **pointer3)
    {
        *pointer1 = malloc(42);
        *pointer2 = malloc(108);
        *pointer3 = malloc(1337);
    }
    
    int main()
    {
        char *pointer1, *pointer2, *pointer3;
        unterprogramm(&pointer1, &pointer2, &pointer3);
        free(pointer1);
        free(pointer2);
        free(pointer3);
        return 0;
    }
    


  • @namespace invader: Da postet SeppJ so eine schöne Erklärung:

    SeppJ schrieb:

    Normalerweise regelt man das so, dass derjenige, der den Speicher anfordert, diesen auch wieder frei gibt.

    Und dann kommst Du daher und postest so einen Scheiss. Ja, das kann man so machen - aber das ist ja *würg*.



  • SeppJ hat doch schon selbst gesagt, dass seine Antwort für den Fragesteller nicht hilfreich ist 😉

    Wenn erst in einer Funktion klar wird, wie viel Speicher reserviert werden muss (etwa wenn nicht vorher bekannt ist, wie viele Spulen usw. in der Datei aufgelistet sind), ist es oft die beste Lösung, die Funktion selbst den Speicher reservieren zu lassen und vom Aufrufer zu verlangen, das zurückgegebene Objekt wieder freizugeben.


  • Mod

    namespace invader schrieb:

    SeppJ hat doch schon selbst gesagt, dass seine Antwort für den Fragesteller nicht hilfreich ist 😉

    Nein, ich habe gesagt, dass er es nicht verstanden hat, weil er noch zuwenig weiß und dass er deshalb erst einmal Lernen soll.

    Wenn erst in einer Funktion klar wird, wie viel Speicher reserviert werden muss (etwa wenn nicht vorher bekannt ist, wie viele Spulen usw. in der Datei aufgelistet sind), ist es oft die beste Lösung, die Funktion selbst den Speicher reservieren zu lassen und vom Aufrufer zu verlangen, das zurückgegebene Objekt wieder freizugeben.

    Und dann bringst du ihm so einen Quatsch bei der ihn für die nächsten Monate total verdirbt.



  • SeppJ schrieb:

    Nein, ich habe gesagt, dass er es nicht verstanden hat, weil er noch zuwenig weiß und dass er deshalb erst einmal Lernen soll.

    Und das ist ja wohl kaum hilfreich.

    Eine Sache die er nicht wusste war, wie man in C aus einer Funktion mehr als einen Wert zurückgeben kann, und das habe ich ihm gezeigt.

    Und dann bringst du ihm so einen Quatsch bei der ihn für die nächsten Monate total verdirbt.

    Inwieweit? Was war denn an meiner Antwort zu beanstanden?

    Es mag sein, dass es je nach Problemstellung (die wir hier ja nicht kennen) bessere Möglichkeiten gibt, seine Funktionen und Datenstrukturen zu organisieren.

    Aber wenn die Lösung so aussehen soll, dass eine Funktionen auf einmal drei voneinander unabhängige Objekte erzeugt, deren Größe der Aufrufer nicht weiß, welche bessere Möglichkeiten gäbe es denn dazu?

    Ich will mich ja hier nicht groß streiten, ohne die genaue Problemstellung zu kennen würde dabei wohl ohnehin nichts für den Fragesteller hilfreiches herauskommen, ich finde es nur niveaulos dass mein Beitrag hier gleich mit Scheiß, würg, Quatsch beantwortet wird.


  • Mod

    Kennst du eine einzige (gute) Bibliothek bei der man das jemals so machen würde? Was meinst du, warum das nirgendwo gemacht wird? Die Verantwortung für Freigabe von Speicher überträgst du in sauberem Design nie.

    Als Alternativen guck dir an, wie das anderswo gehandhabt wird, ebenso meinen ersten Beitrag. Du musst gar nicht weit gehen, ein Blick in die Standardbibliothek reicht.

    Und wenn du das hier anders zeigst, dann kannst du ihm auch eine Lösung mit globalen Variablen und longjmp zeigen. Klar funktioniert das und mag sein Problem lösen, aber wenn man was daraus lernt und das Schema selber nachmacht kommt man in höchstwahrscheinlich bald in große Schwierigkeiten.



  • Ich würde die Funktion so schreiben, dass man am Programmende
    einen bestimmten Wert der Funktion übergibt - und der sagt dann
    der Funktion - mach nix ausser Speicher freigeben.
    Dann am Programmende mit diesem Wert einmal aufrufen - und gut is...
    so alla
    funktion (int meyer) {
    if (meyer = 7777) {
    free..
    free..
    }
    return;
    }



  • SeppJ schrieb:

    Kennst du eine einzige (gute) Bibliothek bei der man das jemals so machen würde? Was meinst du, warum das nirgendwo gemacht wird? Die Verantwortung für Freigabe von Speicher überträgst du in sauberem Design nie.

    In nahezu jeder API gibt es create_irgendwas-Funktionen, die dynamischen Speicher reservieren und dem Aufrufer abverlangen, eine entsprechende delete_irgendwas-Funktion aufzurufen, da er sonst ein Memory Leak baut.

    fopen/fclose und diverse neue Funktionen aus threads.h sind letztendlich auch ein Beispiele dafür.

    Wenn man über Modulgrenzen hinweg Speicher hin- und herreicht, wird man natürlich nicht einfach verlangen, ein rohes free() aufzurufen, sondern eine API-Funktion darum wrappen, insbesondere weil der Aufrufer gar nicht wissen soll was und wie dort für Speicher reserviert wird. Aber innerhalb eines kleinen Programms oder Moduls, zwischen Funktionen die zusammengehören, spricht nichts dagegen.

    Als Alternativen guck dir an, wie das anderswo gehandhabt wird, ebenso meinen ersten Beitrag.

    Du hast geschrieben dass Speicher immer in genau der selben Funktion wieder freigegeben werden soll, aber das ist im Allgemeinen nicht immer machbar und sinnvoll - dann bräuchte man ja beinahe gar kein malloc, sondern könnte einfach alles auf den Stack packen 😉

    Und wenn du das hier anders zeigst, dann kannst du ihm auch eine Lösung mit globalen Variablen und longjmp zeigen. Klar funktioniert das und mag sein Problem lösen, aber wenn man was daraus lernt und das Schema selber nachmacht kommt man in höchstwahrscheinlich bald in große Schwierigkeiten.

    Ich halte es für verfehlt, jemandem, der erst dabei ist C zu lernen, gleich zu versuchen alle möglichen stilistischen Erwägungen einzutrichtern, denn den Sinn dahinter wird er ohnehin noch nicht verstehen können. Guck was pferdefreund aus deinem Tipp gemacht hat m(

    Umgekehrt kommt man auf die meisten dieser Dinge von selbst, sobald man die Sprache kann und anfängt größere Programme damit zu schreiben; wer bei einem großen Programm merkt, dass er den Überblick über seinen dynamischen Speicher verliert, wird sich schon selbst Gedanken machen wie er ihn besser organisiert.

    Und natürlich sollte man einem Anfänger erklären, wie globale Variablen und longjmp funktionieren. Wie sonst soll er beurteilen können, wann und wann nicht es sinnvoll ist sie einzusetzen?


  • Mod

    namespace invader schrieb:

    SeppJ schrieb:

    Kennst du eine einzige (gute) Bibliothek bei der man das jemals so machen würde? Was meinst du, warum das nirgendwo gemacht wird? Die Verantwortung für Freigabe von Speicher überträgst du in sauberem Design nie.

    In nahezu jeder API gibt es create_irgendwas-Funktionen, die dynamischen Speicher reservieren und dem Aufrufer abverlangen, eine entsprechende delete_irgendwas-Funktion aufzurufen, da er sonst ein Memory Leak baut.

    Merkste was? Die rufen das create nicht selbstständig in einer Funktion auf und verlangen, dass der Benutzer das was aus der Funktion zurück kommt, einem delete_X vorwirft. Derjenige der das create_X benutzt hat, macht auch das delete.

    fopen/fclose und diverse neue Funktionen aus threads.h sind letztendlich auch ein Beispiele dafür.

    Gerade nicht. Siehe erklärung oben. Das fclose wird von dem gemacht, der fopen gemacht hat. Ebenso bei den Threads.

    Wenn man über Modulgrenzen hinweg Speicher hin- und herreicht, wird man natürlich nicht einfach verlangen, ein rohes free() aufzurufen, sondern eine API-Funktion darum wrappen, insbesondere weil der Aufrufer gar nicht wissen soll was und wie dort für Speicher reserviert wird. Aber innerhalb eines kleinen Programms oder Moduls, zwischen Funktionen die zusammengehören, spricht nichts dagegen.

    Also im Kleinen und bei Übungsbeispielen darf man schlampen? Damit erreicht man bloß, dass man. wenn es ernst wird, keine Ahnung hat, wie es richtig geht.

    Als Alternativen guck dir an, wie das anderswo gehandhabt wird, ebenso meinen ersten Beitrag.

    Du hast geschrieben dass Speicher immer in genau der selben Funktion wieder freigegeben werden soll, aber das ist im Allgemeinen nicht immer machbar und sinnvoll - dann bräuchte man ja beinahe gar kein malloc, sondern könnte einfach alles auf den Stack packen 😉

    Nein, ich schrieb, dass der Speicherreservierende den Speicher wieder freigibt. Das ist immer sinnvoll zu machen. Oben beschreibst du viele gute Beispiele, wie man das macht.

    Ich halte es für verfehlt, jemandem, der erst dabei ist C zu lernen, gleich zu versuchen alle möglichen stilistischen Erwägungen einzutrichtern, denn den Sinn dahinter wird er ohnehin noch nicht verstehen können. Guck was pferdefreund aus deinem Tipp gemacht hat m(

    Super. Da siehst mal, wo das hinführt, wenn man es nicht gleich von Anfang an richtig macht. Willst du, dass jeder endet wie die JW-Opfer?

    Umgekehrt kommt man auf die meisten dieser Dinge von selbst, sobald man die Sprache kann und anfängt größere Programme damit zu schreiben; wer bei einem großen Programm merkt, dass er den Überblick über seinen dynamischen Speicher verliert, wird sich schon selbst Gedanken machen wie er ihn besser organisiert.

    Da kommt man eben nicht so leicht von alleine drauf. Guck dir an, was der Threadersteller, du und pferdefreund getan haben. Und der Threadersteller hat eben gerade gefragt, weil er damit ein Problem hat.

    Und natürlich sollte man einem Anfänger erklären, wie globale Variablen und longjmp funktionieren. Wie sonst soll er beurteilen können, wann und wann nicht es sinnvoll ist sie einzusetzen?

    Zu der Erklärung was es tut gehört auch eine Erklärung, was da dran und warum gefährlich ist. Sonst ist die Erklärung nicht vollständig. Wenn jeder immer und immer wieder die gleichen Designfehler wiederholen soll, dann kann man sich die Lehre auch sparen und ihnen eine C-Referenz geben ganz ohne Erläuterungen.


Anmelden zum Antworten