Problem mit malloc und realloc



  • Hallo Leute,

    ich bin gerade dabei ein Programm zu schreiben mit dem in strings von der Konsole einlesen kann, wobei ich mein Array am Anfang ne fixe Größe habe und wenn diese überschreitet wird mit realloc neuen Speicher reserviere. Strings sollen mit \n gesplittet sein. Als Abbruchbedingung nehme ich den Leerstring.

    #include <stdio.h>
    #include <stdlib.h>
    
    int main() {
        char** arr;
        int j = 0;
    
        arr = malloc(sizeof(char*) * 2);
    
        for (int i = 0; i < 2; i++) {
            arr[i] = malloc(sizeof(char) * 10);
        }
    
        while (scanf("%9[^\n]%*c", arr[j]) == 1) {
            if (arr[j] == '\0') {
                break;
            }
    
            ++j;
    
            if (j >= 1) {
                arr = realloc(arr, sizeof(char*) * 1);
                arr[j] = malloc(sizeof(char) * 10);
            }
        }
    
        for (int i = 0; i < j; i++) {
            puts(arr[i]);
        }
    
        for (int i = 0; i < j; i++) {
            free(arr[i]);
        }
        free(arr);
    
        return 0;
    }
    

    Leider ist die Ausgabe immer falsch, die ersten beiden Strings werden nicht ausgegeben etc. Kann mir jemand sagen was ich falsch mache?

    MfG



  • 1. Kompiliert nicht ohne -std=c99-Option. Oder vorher i zusammen mit j deklarieren und die Deklaration in den Schleifen unterlassen.

    1. int main(void) soll es sein.

    3. Habe vier Strings angegeben, beim letzten hat meine Lautzeitumgebung verkündet, ich solle doch bitte mal mein Programm prüfen:

    *** Error in `./bla': realloc(): invalid next size: 0x0000000000602010 ***
    

    Wenn ich zwei Strings angebe und danach einen leeren, geht noch alles. Ja, das Programm beendet sich ordentlich.
    Wenn ich drei Strings angebe und danach einen leeren, bricht das Programm ab, und die Memory Map wird mir ausgeben.
    Wenn ich vier Strings angebe, kommt die obige Fehlermeldung, und danach nimmt das Programm keine Eingaben mehr an.

    4. Lässt also auf ein Problem mit deiner Speicherverwaltung schließen. Beim drüberlinsen habe ich diesen Code gefunden:

    if(j>=1)
    {
        arr     =realloc(arr, sizeof(char*) * 1);
        arr[j]  =malloc(sizeof(char) * 10);
    }
    

    Also zurück auf ein Element? Und da bist du dir sicher? Wo prüfst du eigentlich, ob realloc eventuell 0 zurückgibt? So würde der Code im Fehlerfall den Zeiger komplett verlieren.

    Vielleicht solltest du auch mal darüber nachdenken, das ganze als eindimensionales Array zu verwenden, und ein bisschen mehr Speicher, als du eigentlich brauchst, zu reservieren. Fixe Stringgrößen hast du ja schon, und dynamische Speicherverwaltung ist halt teuer.

    Übrigens: für diese Formatierungsunart gehört K&R exhumiert und an einen Laternenpfahl gehängt.



  • Du benutzt realloc falsch, dort musst du die neue Gesamtgröße vorgeben, und nicht die Differenz der neuen zur bisherigen Größe.



  • Vielen Dank, nun funktioniert alles wie gewollt. Nun möchte ich aber noch die Stringlänge dynamisch machen, also ich reservier am Anfang 10, wenn diese überschritten wird dann nochmal 10, nur wie kann ich dann die Bedingung in meiner while Schleife ausdrücken?



  • Das geht so nicht, du musst vor dem Einlesen ausreichend Speicher für die Strings bereitstellen.



  • Nein, Wutz, das ist so auch nicht korrekt. Aber man muss auf scanf verzichten.
    Man kann mit getchar() oder getline() einzelne Zeichen bzw. Teile des Strings von der Eingabe holen, und wenn man merkt, dass man nicht genug Speicher hat, kann man diesen vor dem nächsten Holen erweitern.



  • Man kann auch mehrmals mit fgets einlesen.
    Ob die Zeile schon ganz eingelesen wurde, kann man daran erkennen, dass das '\n' enthalten ist.


Anmelden zum Antworten