Speicherreservierung malloc()



  • Hi ich hab ein Frage zu einer dyn. Speicherreservierung mit malloc() für Mehrfach-pointer.

    Bei meinem Versuch funktioniert eigentlich alles und genau das verwirrt mich.
    Ich habe versucht eine dyn. Bereich für eine beliebig große Matrix zu reservieren:

    int m, n, b, c;
    float a, **j;

    printf ("\nBitte Anzahl der Zeilen angeben:");
    scanf ("%d", &m);
    printf ("Zeilen: %d",m);
    printf ("\nBitte Anzahl der Spalten angeben:");
    scanf ("%d", &n);
    printf ("Spalten: %d\n\n", n);

    *j= (float*)malloc(msizeof(float));
    j= (float**)malloc(m*n*sizeof(float
    ));

    In meinem Vorlesungsskript steht allerdings ein Beispiel:

    .
    .
    .
    a = (double**)malloc(m*sizeof(double*)); /* Reserviere Zeigerfeld /
    a[0]=(double
    )malloc(m*n*sizeof(double)); /*Speicher für Gesamtfeld */
    .
    .
    .

    Normlareweise gibt es keinen Anlass an dem Skript zu zweifeln. Allerdings funktioniert meine Lösung, und bei der des Skripts stürtzt das Prog. ab (oder andere Fehler wie Datenüberschreibungen treten auf).

    Mir sind auch schon kleiner Sachen aufgefallen. Zum Bsp. muss ich meinen Zeiger als *j definieren. Aber wäre j[0] nicht das gleiche (so wie eben auch in dem bsp.)? Bei dieser Lösung stürtzt das Prog. allerdings auch ab.

    Wie ihr seht habe ich einfach noch nicht so das Verständnis von dieser Anwendung. Und was ich suche ist eigentlich keine Lösung für ein Problem sondern eine kurze Erläuterung. Ich wäre auch schon dankbar über einen Verweis auf ANSCHAULICHE Beispiele und Erklärungen zu diesem Thema.

    Im voraus schon mal vielen Dank für die Hilfe.

    Ohje...nu aber ab ins Bett! 😉



  • Ich fürchte, du hast nur sehr viel Glück gehabt, daß dein Programm funktioniert - *j ist nämlich undefiniert, solange du nicht j mit einer korrekten Adresse initialisiert hast. (und die Größenwerte sind außerdem falsch herum angegeben)
    Und bei dem Beispiel aus dem Skript sollten hinterher noch die Werte a[1] bis a[m-1] so umgebogen werden, daß sie (an der richtigen Stelle) in das Feld von a[0] zeigen.





  • Hi,
    ich habs jetzt schon heraus gefunden was ich falsch gemacht (oder viel mehr falsch gedacht habe). Und beim abkupfern von meinem Skript hab ich lediglich die Zeile

    for (i=1;i<m;i++) a[i] = a[0] + i*n; (ich denke das hast du gemeint CStoll)

    übersehn. 🤡 War wohl gestern etwas zu spät für dieses Zeug.

    Trotzdem fände ich es gut, wenn jemand zu diesem Thema noch einen Link oder sowas, mit guten Erläuterungen oder Bsp. postet. Diese Mehrfachzeiger-Speicherreservierungsgeschichte ist nämlich nicht gerade die Einfachste, für Anfänger wie mich.

    Nochmals Danke für die Hilfe. 🙂



  • ich erlaeuter dir den code gerne. sag du dann nur, ob ich etwas zu wenig erklaert hab.

    sinn dieser art der matrixerstellung ist, dass die eigentlichen werte alle in einem zusammenhaengenden stueck speicher liegen. man koennte auch fuer jede zeile einen block erstellen, wobei das unerwuenscht ist, weil man so eventuell zu sehr durch den speicher springt und der cache des prozessors nicht greifen kann.
    die anatomie der erstellten matrix stellt sich so dar, dass man einen type** zeiger bekommt (type soll fuer einen beliebigen typen stehen). type** liest sich als "zeiger auf eine reihe von zeilenzeigern", wobei ein "zeilenzeiger" in den vorher angelegten grossen speicherblock fuer die eigentlichen werte hineinzeigt.
    hat man also z.b. ein "double meinematrix", dann hat man mit meinematrix[0] bis meinematrix[zeilenzahl-1] jeweils einen pointer auf den anfang der angegebenen zeile.
    mit dem zeilenpointer wiederum kann man den gleichen spass machen und so auf einen bestimmten wert zugreifen: meinematrix[12][5] greift auf die dreizehnte zeile (zeile 12) zu und dort auf das sechste element (element 5), denn alle indices fangen bei 0 an.
    meinematrix ist double

    meinematrix[12] ist double*
    meinematrix[12][5] ist double

    insgesamt hat man zwei bloecke an speicher zu alloziieren: den speicher fuer die werte und den speicher fuer die zeilenpointer. das array von zeilenpointern wird so initialisiert, dass ein zeilenzeiger an die stelle in den wertespeicher zeigt, an der der streifen fuer die jeweilige zeile beginnt.
    beispiel: meinematrix[0] muss auf den ersten streifen (streifen 0) zeigen. das sei ganz am anfang des wertespeichers und deswegen wird meinematrix[0] mit (wertespeicher + 0spaltenzahl) initialisiert. spaltenzahl ist gleichbedeutend mit "anzahl der speicherzellen in einer zeile".
    der naechste streifen beginnt unmittelbar nach dem ersten streifen (klingt logisch *g*). damit berechnet sich sein anfangspunkt so: (wertespeicher + 1
    spaltenzahl)
    der faktor bei "spaltenzahl" laeuft mit dem zeilenindex mit.
    diese methode hat die eigenschaft, dass der zeiger matrix[0] nicht nur der zeiger auf die erste zeile ist, sondern auch der zeiger auf den gesamten wertespeicher. deswegen muss man beim free()n auch zu erst free(matrix[0]) fuer den wertespeicher und erst dann free(matrix) fuer den speicher der zeilenpointer ausfuehren. andersrum geht es nicht, weil man sonst den pointer auf den wertespeicher verlieren wuerde.

    ich weiss nicht, wie selbsterklaerend dieser code ist. wenn was unklar ist, bescheid sagen und ich ergaenze.

    double **initmatrix(unsigned int zeilen, unsigned int spalten)
    {
        double **matrix, *p;
        int i;
    
        // speicher fuer die zeilenpointer
        matrix = malloc(sizeof(double*) * zeilen); // ein zeilenpointer ist sizeof(double*) breit
    
        // speicher fuer die werte der eigentlichen matrix
        p = malloc(sizeof(double) * zeilen * spalten);
    
        for(i = 0; i < zeilen; ++i)
            matrix[i] = p + i*spalten; // laesst jeden zeilenpointer auf seinen bereich in der matrix zeigen
    
        return matrix;
    }
    
    void freematrix( double **matrix)
    {
        free(*matrix); // eigentliche matrix; *matrix ist equivalent zu matrix[0], suggeriert aber nicht, dass ich "eine zeile free()n" wuerde
        free(matrix); // zeilenpointer
    }
    


  • Mein Denkfehler war ursprünlich, dass ich dachte der **Zeiger zeigt direkt auf meine Werte. Daher auch der falsch definierte Bereich:

    *j= (float*)malloc(m*sizeof(float)); 
    j= (float**)malloc(m*[b]n*[/b]sizeof(float*));
    

    Warum das Programm trotzdem lief weiß ich nicht. 😕

    Und bei der Lösung meines Skriptes hab ich lediglich die Zeile

    for (i=1;i<m;i++) a[i] = a[0] + i*n;
    

    vergesssen. Somit war ja nur das erste Zeilenfeld definiert und das Programm ist nach Eingabe der 1. Zahl in der 2. Zeile abgestürtzt.
    Wie du siehst ich hab meine Hausaufgaben gemacht 😉 und aus meinen Fehlern gelernt.
    Was ich an deinem Bsp. gut finde ist, dass du noch einen zusätzlichen Zeiger *p benutzt. Der macht den Vorgang doch noch um einiges anschaulicher.

    Danke für die Mühe. 🙂



  • Noch ne kleine Frage:

    free(*matrix); // eigentliche matrix; *matrix ist equivalent zu matrix[0], suggeriert aber nicht, dass ich "eine zeile free()n" wuerde
    

    Also steht hier das matrix[0] für meine Startadresse des reservierten Bereichs und nicht nur für die 1. Zeile?

    Rein theoretisch; wie könnte ich dann lediglich die 1. Zeile löschen?
    Kann man das über die Variable machen:

    i=0;
    free(matrix[i]);
    

    oder macht das keinen Unterschied?



  • sourz schrieb:

    Noch ne kleine Frage: 🙂

    free(*matrix); // eigentliche matrix; *matrix ist equivalent zu matrix[0], suggeriert aber nicht, dass ich "eine zeile free()n" wuerde
    

    Also steht hier das matrix[0] für meine Startadresse des reservierten Bereichs und nicht nur für die 1. Zeile?

    Ja, in matrix[0] steht die Startadresse des gesamten Datenbereiches.

    wie könnte ich dann lediglich die 1. Zeile löschen?

    Gar nicht - wozu benötigst du das überhaupt?

    Kann man das über die Variable machen:

    i=0;
    free(matrix[i]);
    

    oder macht das keinen Unterschied?

    Das hätte den selben Effekt wie "free(*matrix);" (löscht die komplette Matrix)
    (btw, free(matrix[1]); dürfte übrigens zu undefiniertem Verhalten führen)


Anmelden zum Antworten