Pointer Löschproblem



  • Ich habe hier ein Programm erstellt, bei dem man Listen eingeben kann. Es funktioniert tadellos, aber wie kann ich einzelne Teile der Liste Löschen?
    Ich habe bis jetzt nur eine Funktion geschrieben bei der man alles löschen kann.

    #include <stdio.h> // printf,gets
    #include <string.h> // strcmp, strcpy
    #include <conio.h> // getch(), clrscr()

    typedef char string[80];
    enum bool {FALSE,TRUE};

    struct listenelement // DEFINITION einer
    { string s_name; // verketteten Liste
    string s_ort;
    struct listenelement *p_next; // Zeiger auf n„chstes Listenelement
    } ;

    listenelement *p_wurzel,*p; // Zeiger auf die Struktur

    void listeneingabe();
    void listenausgabe();
    void liste_loeschen();

    void main()
    { clrscr();
    listeneingabe();
    printf("\n\nEingabe beendet - Ausgabe mit ENTER"); getch();
    listenausgabe();
    liste_loeschen();
    getch();
    }

    void listeneingabe() // EINGABE der Liste, Ablegen im HEAP
    { string eingabe;
    bool fertig=FALSE;
    p=p_wurzel=NULL; // mit "nichts" initialisieren
    do
    {
    printf("\nName : ");
    gets(eingabe);
    if (strcmp(eingabe,"")!=0) // Es wurde etwas eingegeben
    { if (p==NULL) // Liste noch leer??
    { p = new listenelement;
    p_wurzel = p; // Erdung der Liste
    }
    else
    { p->p_next=new listenelement; // Liste fortsetzen
    p=p->p_next; // Pointer weiterbewegen
    }
    strcpy(p->s_name,eingabe); // eingabe-String hineinkopieren
    printf("\nWohnort : ");
    gets(p->s_ort); // gets = getstring
    }
    else // ENTER - Ende der Liste
    { p->p_next=NULL; // Ende der Liste definieren
    fertig=TRUE;
    }
    }
    while (!fertig);
    }

    void listenausgabe()
    {
    for (p=p_wurzel ; p != NULL ; p = p->p_next)
    printf("\n%s %s",p->s_name,p->s_ort);

    /******* dieselbe Schleife in ausfhrlicher Schreibweise:
    p=p_wurzel;
    while (p != NULL)
    { printf("%s\n",p->s_name);....
    p = p->p_next ;
    } ****************/
    }

    void liste_loeschen()
    {
    for (p=p_wurzel ; p != NULL ; p = p->p_next)
    delete p; // oder: free(p);
    }

    Ich hätte mit der Funktion so angefangen.

    int del(string person)
    {
    (p->p_last)->p_next=p->p_next;

    }

    Ich bitte um Hilfe!! 😕



  • Um einen Listenknoten zu löschen, müssen 2 Dinge passieren:

    1. aus der Liste ausklinken
    2. Element löschen

    Du hast eine einfach verkettete Liste, das heißt, du kannst, wenn du einen Zeiger auf einen Listenknoten hast, immer nur den nachfolgenden Knoten entfernen, da du zum ausklinken den next-Zeiger des vorhergehenden Knoten verändern mußt.

    Das heißt, du brauchst eine Fallunterscheidung, ob der erste Knoten der Liste gelöscht werden soll. In dem Fall wird nicht der next-Zeiger des vorhergehenden Knotens verändert, sondern der Listenkopf.

    Da du eine Funktion zu suchen scheinst, die erst einen String sucht, und dann den entsprechenden Knoten entfernt, bietet sich eine Aufteilung der Aufgaben in 4 Funktionen an:

    delete(string)
    delete_first() // löscht erstes Element
    delete_next(struct listelement*) // löscht nachfolgendes Element
    struct listelement * find(string) // gibt Listenknoten zurück, der den String enthält

    Das ganze läßt sich simpler gestalten, wenn man als Listenkopf einen Pseudoknoten verwendet, dh einen Listenknoten wie alle anderen, den man bei Suchoperationen usw. übergeht. Man kann den sogar gleichzeitig als Listenkopf und -ende verwenden, so dass sich eine zyklische Liste ergibt. Die Algorithmen zum entfernen und einfügen vereinfachen sich dadurch insbesondere bei einer doppelt verketteten Liste.

    Noch was zum Stil:
    Globale Variablen sind schlecht, auch wenns der Listenkopf ist (was spricht gegen Argumentübergabe, zb void listenausgabe(struct listelement * wurzel) ...)
    gets ist schlecht, da du keine Kontrolle über die Länge der Eingabe hast. Wenn jemand zuviel eingibt, werden die Grenzen deiner Arrays überschritten und es kommt zum buffer overflow (nimm fgets stattdessen)
    die Funktion zum Löschen der ganzen Liste hat undefiniertes Verhalten: Du löschst erst einen Knoten p, und verwendest danach nochmal p, um an p->next zu kommen. Du hast keine Garantie, dass free (ich seh an der Stelle mal über delete hinweg, eigentlich ist das ein C++-Programm was du da hast ;)) den Bereich, den es freigibt, nicht überschreibt. Der Speicher gehört dir einfach nicht mehr, nachdem du ihn freigegeben hast. Also speichere zuerst p->next in einen anderen temporären Zeiger, und lösche dann p.


Anmelden zum Antworten