Speicherzugriffsfehler (Speicherabzug geschrieben), was ist falsch...


  • Gesperrt

    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct Node
    {
        struct TNode *next;
        char *content;
        int len;
    } TNode;
    
    TNode *root = 0;
    int len = 0;
    
    TNode *get_nth(int n)
    {
        TNode *tn = root;
        int i = 0;
        for (; i < len && i < n; i++)
        {
            root = (TNode *)root->next;
        }
        return tn;
    }
    
    void insert(int n, char *content, int l)
    {
        TNode *tn0 = get_nth(n - 1);
        TNode *tn1 = get_nth(n);
        TNode *tn2 = 0;
        if (tn0 == 0)
        {
            tn2 = malloc(sizeof(TNode));
            tn2->content = content;
            tn2->len = l;
            if (tn1 != 0)
                tn2->next = (struct TNode *)tn1;
            else
                tn2->next = 0;
            root = tn2;
        }
        else
        {
            tn2 = malloc(sizeof(TNode));
            tn2->content = content;
            tn2->len = l;
            if (tn1 != 0)
                tn2->next = (struct TNode *)tn1;
            else
                tn2->next = 0;
            tn0->next = (struct TNode *)tn2;
        }
        len++;
    }
    
    int main(int argc, char **argv)
    {
        int i = 0;
        TNode *tn = 0;
        insert(0, "hallo 1", 7);
        insert(1, "hallo 2", 7);
        insert(0, "hallo 3", 7);
        for (; i < len; i++)
        {
            tn = get_nth(i);
            printf("%s\n", tn->content);
        }
        return 0;
    }
    

    Ich erhalte folgende Ausgabe:

    $ ./LinkedList.out 
    hallo 3
    hallo 3
    Speicherzugriffsfehler (Speicherabzug geschrieben)
    

    Sieht ein geübtes Auge evtl schnell den Fehler?


  • Gesperrt

    Hab den Fehler gerade in der Funktion get_nth(int n) gefunden:

    TNode *get_nth(int n)
    {
        TNode *tn = root;
        int i = 0;
        if (n < 0)
            return 0;
        for (; i < len && i < n; i++)
        {
            tn = (TNode *)tn->next;
        }
        return tn;
    }
    


  • @EinNutzer0
    Jup, sehe den Fehler. Variable root ist anfangs 0.


  • Gesperrt

    @Quiche-Lorraine Also das Problem war... get_nth sollte mit -1 nicht root zurückgeben, sondern 0



  • @EinNutzer0
    Aber der zweite get_nth() Aufruf wird beim ersten insert() mit 0 aufgerufen.



  • @EinNutzer0
    Sorry stimmt nicht was ich gesagt habe.



  • @EinNutzer0 sagte in Speicherzugriffsfehler (Speicherabzug geschrieben), was ist falsch...:

    insert(0, "hallo 1", 7);
    insert(1, "hallo 2", 7);
    insert(0, "hallo 3", 7);
    

    Warum nutzt der letzte insert Befehl den Index 0?


  • Gesperrt

    @Quiche-Lorraine Hier ist das nochmal "geglättet":

    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct Node
    {
        struct TNode *next;
        char *content;
        int len;
    } TNode;
    
    TNode *root = 0;
    int len = 0;
    
    TNode *get_nth(int n)
    {
        TNode *tn = root;
        int i = 0;
        if (n < 0)
        {
            return 0;
        }
        for (; i < len && i < n; i++)
        {
            tn = (TNode *)tn->next;
        }
        return tn;
    }
    
    void insert(int n, char *content, int l)
    {
        TNode *tn0 = get_nth(n - 1);
        TNode *tn1 = get_nth(n);
        TNode *tn2 = 0;
        if (tn0 == 0)
        {
            tn2 = malloc(sizeof(TNode));
            tn2->content = content;
            tn2->len = l;
            tn2->next = (struct TNode *)tn1;
            root = tn2;
        }
        else
        {
            tn2 = malloc(sizeof(TNode));
            tn2->content = content;
            tn2->len = l;
            tn2->next = (struct TNode *)tn1;
            tn0->next = (struct TNode *)tn2;
        }
        len++;
    }
    
    int main(int argc, char **argv)
    {
        int i = 0;
        TNode *tn = 0;
        insert(0, "hallo 1", 7);
        insert(1, "hallo 2", 7);
        insert(2, "hallo 3", 7);
        insert(0, "hallo 0", 7);
        for (; i < len; i++)
        {
            tn = get_nth(i);
            printf("%s\n", tn->content);
        }
        return 0;
    }
    

    Nu funktioniert es, insert() soll den content an Stelle n einfügen...



  • @EinNutzer0 sagte in Speicherzugriffsfehler (Speicherabzug geschrieben), was ist falsch...:

    root = (TNode *)root->next;
    

    Jetzt sehe ich den Fehler. 🙂



  • @EinNutzer0 sagte in Speicherzugriffsfehler (Speicherabzug geschrieben), was ist falsch...:

        struct TNode *next;
    

    Das ist doch Quatsch oder? struct Node!

    In Zeile 39 machst Du den selben Blödsinn nochmal ähnlich.
    Allgemein schaut das alles viel zu komplifiziert aus.


  • Gesperrt

    @Swordfish Du hast recht... Aber wieso funktioniert das dennoch?!

    Ist mir beim pasten auch nicht aufgefallen... o.O



  • Weil das einfach eine struct deklariert die nichts mit der definierten Node zu tun haben. Pointer sizes werden wohl die selben sein, deshalb "funktioniert" es.
    Aber allgemein: Du vermischt da komplett die Zuständigkeiten. Ein String ist keine Node. Eine Node ist keine List. Modelliere jedes einzelteil für sich.


  • Gesperrt

    @Swordfish sagte in Speicherzugriffsfehler (Speicherabzug geschrieben), was ist falsch...:

    Eine Node ist keine List

    doch...

    Ich hab jetzt die Zuständigkeiten getrennt... Aber jetzt bekomme ich immer eine Gleitkomma-Ausnahme (Speicherabzug geschrieben) zwischen Zeile 94 und 98. Ich vermute es liegt am sprintf aber sicher bin ich mir nicht. Kann noch mal jemand schauen?

    #include <stdio.h>
    #include <stdlib.h>
    
    struct ByteContent
    {
        char *content;
        int len;
    };
    
    struct Node
    {
        struct Node *next;
        struct ByteContent *byte_content;
    };
    
    struct Node *root = 0;
    int len = 0;
    
    struct Node *get_nth(int n)
    {
        struct Node *tn = root;
        int i = 0;
        if (n < 0)
        {
            return 0;
        }
        for (; i < len && i < n; i++)
        {
            tn = tn->next;
        }
        return tn;
    }
    
    struct ByteContent *get_byte_content(int n)
    {
        return get_nth(n)->byte_content;
    }
    
    void insert(int n, struct ByteContent *bc)
    {
        struct Node *tn0 = get_nth(n - 1);
        struct Node *tn1 = get_nth(n);
        struct Node *tn2 = 0;
        if (tn0 == 0)
        {
            tn2 = malloc(sizeof(struct Node));
            tn2->byte_content = bc;
            tn2->next = tn1;
            root = tn2;
        }
        else
        {
            tn2 = malloc(sizeof(struct Node));
            tn2->byte_content = bc;
            tn2->next = tn1;
            tn0->next = tn2;
        }
        len++;
    }
    
    struct ByteContent *delete (int n)
    {
        struct Node *tn0 = 0;
        struct Node *tn1 = 0;
        struct ByteContent *a = 0;
        if (n < 0 || n >= len)
        {
            return 0;
        }
        tn0 = get_nth(n - 1);
        tn1 = get_nth(n);
        a = tn1->byte_content;
        if (tn0 == 0)
        {
            root = root->next;
        }
        else
        {
            tn0->next = tn1->next;
        }
        free(tn1);
        len--;
        return a;
    }
    
    int main(int argc, char **argv)
    {
        int i = 0;
        struct ByteContent *temp = 0;
        struct ByteContent **bc = malloc(sizeof(struct ByteContent *) * 10);
        char *ca = 0;
        for (i = 0; i < 10; i++)
        {
            bc[i] = malloc(sizeof(struct ByteContent));
            ca = (char *)malloc(sizeof(char) * 9);
            sprintf(ca, "hallo %d!", i);
            bc[i]->content = ca;
            bc[i]->len = 9;
        }
        for (i = 0; i < 10; i++)
        {
            insert(rand() % len, bc[i]);
        }
        for (i = 0; i < 10; i++)
        {
            delete (rand() % len);
        }
        for (i = 0; i < 10; i++)
        {
            insert(rand() % len, bc[i]);
        }
        for (i = 0; i < len; i++)
        {
            temp = get_byte_content(i);
            printf("%s\n", temp->content);
        }
        return 0;
    }
    


  • Welchen wert hat len in Zeile 102?


  • Gesperrt

    @Swordfish sagte in Speicherzugriffsfehler (Speicherabzug geschrieben), was ist falsch...:

    Welchen wert hat len in Zeile 102?

    0, ist ja noch leer...



  • Dann brauchst du dich auch nicht über den Fehler bei rand() % len wundern (intern wird bei Modulo ja auch eine Division durchgeführt)...


  • Gesperrt

    Danke, jetzt funktioniert es:

    #include <stdio.h>
    #include <stdlib.h>
    
    struct ByteContent
    {
        char *content;
        int len;
    };
    
    struct Node
    {
        struct Node *next;
        struct ByteContent *byte_content;
    };
    
    struct Node *root = 0;
    int len = 0;
    
    struct Node *get_nth(int n)
    {
        struct Node *tn = root;
        int i = 0;
        if (n < 0)
        {
            return 0;
        }
        for (; i < len && i < n; i++)
        {
            tn = tn->next;
        }
        return tn;
    }
    
    struct ByteContent *get_byte_content(int n)
    {
        return get_nth(n)->byte_content;
    }
    
    void insert(int n, struct ByteContent *bc)
    {
        struct Node *tn0 = get_nth(n - 1);
        struct Node *tn1 = get_nth(n);
        struct Node *tn2 = 0;
        if (tn0 == 0)
        {
            tn2 = (struct Node *)malloc(sizeof(struct Node));
            tn2->byte_content = bc;
            tn2->next = tn1;
            root = tn2;
        }
        else
        {
            tn2 = (struct Node *)malloc(sizeof(struct Node));
            tn2->byte_content = bc;
            tn2->next = tn1;
            tn0->next = tn2;
        }
        len++;
    }
    
    struct ByteContent *delete (int n)
    {
        struct Node *tn0 = 0;
        struct Node *tn1 = 0;
        struct ByteContent *a = 0;
        if (n < 0 || n >= len)
        {
            return 0;
        }
        tn0 = get_nth(n - 1);
        tn1 = get_nth(n);
        a = tn1->byte_content;
        if (tn0 == 0)
        {
            root = root->next;
        }
        else
        {
            tn0->next = tn1->next;
        }
        free(tn1);
        len--;
        return a;
    }
    
    int main(int argc, char **argv)
    {
        int i = 0;
        struct ByteContent *bc[10];
        char *ca = 0;
        struct ByteContent *temp = 0;
        for (i = 0; i < 10; i++)
        {
            bc[i] = (struct ByteContent *)malloc(sizeof(struct ByteContent));
            ca = (char *)malloc(sizeof(char) * 9);
            sprintf(ca, "hallo %d!", i);
            bc[i]->content = ca;
            bc[i]->len = 9;
        }
        for (i = 0; i < 10; i++)
        {
            insert(rand() % (len + 1), bc[i]);
        }
        for (i = 0; i < 10; i++)
        {
            delete (rand() % len);
        }
        for (i = 0; i < 10; i++)
        {
            insert(rand() % (len + 1), bc[i]);
        }
        for (i = 0; len > 0; i++)
        {
            temp = delete (0);
            printf("%s\n", temp->content);
            free(temp->content);
            free(temp);
            temp = 0;
        }
        /*
         * Überprüfe, ob Heap leer ist...?
         */
        return 0;
    }
    

    Kann ich am Ende irgendwie feststellen, ob der Heap leer ist?



  • @EinNutzer0 sagte in Speicherzugriffsfehler (Speicherabzug geschrieben), was ist falsch...:

    Kann ich am Ende irgendwie feststellen, ob der Heap leer ist?

    Valgrind?


  • Gesperrt

    @Swordfish sagte in Speicherzugriffsfehler (Speicherabzug geschrieben), was ist falsch...:

    Valgrind?

    Geil!

    #include <stdio.h>
    #include <stdlib.h>
    
    struct ByteContent
    {
        char *content;
        int len;
    };
    
    struct Node
    {
        struct Node *next;
        struct ByteContent *byte_content;
    };
    
    struct Node *root = 0;
    int len = 0;
    
    struct Node *get_node(int n)
    {
        struct Node *tn = root;
        int i = 0;
        if (n < 0)
        {
            return 0;
        }
        for (; i < len && i < n; i++)
        {
            tn = tn->next;
        }
        return tn;
    }
    
    struct ByteContent *get_byte_content(int n)
    {
        if (n < 0 || n >= len)
        {
            return 0;
        }
        return get_node(n)->byte_content;
    }
    
    void insert(int n, struct ByteContent *bc)
    {
        struct Node *tn0 = get_node(n - 1);
        struct Node *tn1 = get_node(n);
        struct Node *tn2 = 0;
        if (n < 0 || n > len || bc == 0)
        {
            return;
        }
        tn2 = (struct Node *)malloc(sizeof(struct Node));
        tn2->byte_content = bc;
        tn2->next = tn1;
        if (tn0 == 0)
        {
            root = tn2;
        }
        else
        {
            tn0->next = tn2;
        }
        len++;
    }
    
    struct ByteContent *delete (int n)
    {
        struct Node *tn0 = 0;
        struct Node *tn1 = 0;
        struct ByteContent *temp = 0;
        if (n < 0 || n >= len)
        {
            return 0;
        }
        tn0 = get_node(n - 1);
        tn1 = get_node(n);
        temp = tn1->byte_content;
        if (tn0 == 0)
        {
            root = root->next;
        }
        else
        {
            tn0->next = tn1->next;
        }
        free(tn1);
        len--;
        return temp;
    }
    
    int main(int argc, char **argv)
    {
        int i = 0;
        struct ByteContent *byte_array[10];
        char *content = 0;
        struct ByteContent *temp = 0;
        for (i = 0; i < 10; i++)
        {
            byte_array[i] = (struct ByteContent *)malloc(sizeof(struct ByteContent));
            content = (char *)malloc(sizeof(char) * 9);
            sprintf(content, "hallo %d!", i);
            byte_array[i]->content = content;
            byte_array[i]->len = 9;
        }
        for (i = 0; i < 10; i++)
        {
            insert(rand() % (len + 1), byte_array[i]);
        }
        for (i = 0; i < 10; i++)
        {
            delete (rand() % len);
        }
        for (i = 0; i < 10; i++)
        {
            insert(rand() % (len + 1), byte_array[i]);
        }
        for (i = 0; len > 0; i++)
        {
            temp = delete (0);
            printf("%s\n", temp->content);
            free(temp->content);
            free(temp);
            temp = 0;
        }
        /*
         * Let Valgrind do it's work...
         */
        return 0;
    }
    
    $ valgrind --leak-check=yes ./LinkedList.out 
    ==6482== Memcheck, a memory error detector
    ==6482== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
    ==6482== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
    ==6482== Command: ./LinkedList.out
    ==6482== 
    hallo 2!
    hallo 8!
    hallo 3!
    hallo 5!
    hallo 7!
    hallo 9!
    hallo 4!
    hallo 1!
    hallo 6!
    hallo 0!
    ==6482== 
    ==6482== HEAP SUMMARY:
    ==6482==     in use at exit: 0 bytes in 0 blocks
    ==6482==   total heap usage: 41 allocs, 41 frees, 1,594 bytes allocated
    ==6482== 
    ==6482== All heap blocks were freed -- no leaks are possible
    ==6482== 
    ==6482== For lists of detected and suppressed errors, rerun with: -s
    ==6482== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
    

    Jetzt hab ich eine bombensichere Liste. 😉



  • @EinNutzer0 sagte in Speicherzugriffsfehler (Speicherabzug geschrieben), was ist falsch...:

    Jetzt hab ich eine bombensichere Liste.

    Werd' mal die gobalen Variablen los, typedefs für die Structs, Variablen so lokal wie möglich deklarieren, sizeof(*ptr) statt sizeof(explicit_type), ...


  • Gesperrt

    @Swordfish sagte in Speicherzugriffsfehler (Speicherabzug geschrieben), was ist falsch...:

    typedefs für die Structs,

    Dafür bräuchte ich ein Header file... (wegen Vorwärtsdeklaration)

    @Swordfish sagte in Speicherzugriffsfehler (Speicherabzug geschrieben), was ist falsch...:

    Variablen so lokal wie möglich deklarieren,

    Wäre nicht mehr Ansi-C!

    @Swordfish sagte in Speicherzugriffsfehler (Speicherabzug geschrieben), was ist falsch...:

    sizeof(*ptr) statt sizeof(explicit_type),

    Stimmt!

    @Swordfish sagte in Speicherzugriffsfehler (Speicherabzug geschrieben), was ist falsch...:

    Werd' mal die gobalen Variablen los,

    Aber wie?


Anmelden zum Antworten