ein Kapitel zurück                                           ein Kapitel weiter

Die Funktion loesche_alles() stellt sich auch als relativ einfach heraus. Wir laufen lediglich die ganze Liste durch und löschen alles außer das 1. und letzte Element...

void loesche_alles()
{
 struct angestellt *zeiger, *zeiger1;

/*Ist überhaupt eine Liste zum löschen vorhanden*/
 if(anfang != NULL)
  {
/*Es ist eine vorhanden....*/
   zeiger=anfang->next;
   while(zeiger != NULL)
     {
       zeiger1=anfang->next->next;
       if(zeiger1 == NULL)
           break;
       anfang->next=zeiger1;
       zeiger1->previous=anfang;
       free(zeiger);
       zeiger=zeiger1;
     }



doppelt verkettete Listen


Die if - Abrage ob unser Zeiger zeiger1 auf NULL zeigt benutzen wir als Abbruchbedienung, da falls das wahr sein sollte nur noch 2 Elemente in der Liste vorhanden sind. Genauso gut hätten wir das mit der while - Abfrage machen können : while(zeiger->next != NULL)<7i> - aber ich wollte das Programm nicht allzu sehr umschreiben, damit es leichter fällt sich wieder hinein zu versetzten. Und Außerdem gibt es keine Regel die schreibt wie sie Ihr Programm schreiben!!! Jetzt hängen wir das Element auf das zeiger zeigt wieder aus (anfang->next=zeiger1; zeiger1->previous=anfang;) ....


doppelt verkettete Listen


Jetzt können wir das Element auf das zeiger zeigt mit free(...) freigeben. Somit ergibt sich folgendes Bild...


doppelt verkettete Listen


Hier endet nun unsere while - Schleife da - zeiger1=anfang->next->next auf NULL zeigt oder wenn sie die Funktion umschreiben wollen - while(zeiger->next != NULL).........

Jetzt wollen wir unsere letzten beiden Elemente löschen...

free(anfang);
free(ende);
anfang=NULL;
ende=NULL;

Sie brauchen lediglich den Speicherplatz für auf den anfang und ende zeigen freizugeben. Anschließend bekommen die Zeiger anfang und ende den NULL - Zeiger. Dazu bedarf es wohl keinerlei weiteren Kommentare. Hier noch einmal die Funktion loesche_alles() komplett...

void loesche_alles()
{
 struct angestellt *zeiger, *zeiger1;

/*Ist überhaupt eine Liste zum löschen vorhanden*/
 if(anfang != NULL)
  {
/*Es ist eine vorhanden....*/
   zeiger=anfang->next;
   while(zeiger != NULL)
     {
       zeiger1=anfang->next->next;
       if(zeiger1 == NULL)
           break;
       anfang->next=zeiger1;
       zeiger1->previous=anfang;
       free(zeiger);
       zeiger=zeiger1;
     }
/*Jetzt löschen wir erst den Anfang der Liste und das Ende der Liste*/
   free(anfang);
   free(ende);
   anfang=NULL;
   ende=NULL;
   printf("Liste erfolgreich gelöscht!!\n");
  }
 else
   fprintf(stderr,"Keine Liste zum löschen vorhanden!!\n");
}
Kommen wir nun zur Funktion sortiert_eingeben(..) .....
void sortiert_eingeben(char n[],char v[],int at,int am,int aj,
int et,int em,int ej,long geh)
{
 struct angestellt *zeiger, *zeiger1;

/*Ist es das 1.Element der Liste ? */
 if(anfang==NULL)
    anhaengen(n,v,at,am,aj,et,em,ej,geh);
/*Es ist nicht das 1.Element. Wir suchen nun so lange bis das
gesuchte Element gefunden wird oder wir auf NULL stoßen*/
 else
  {
   zeiger=anfang;
   while(zeiger != NULL && (strcmp(zeiger->name,n)<0))
      zeiger=zeiger->next;
/*Falls der Zeiger auf NULL zeigt können wir unser Element hinten
anhängen da unser neues Element das "grösste" zu sein scheint */
   if(zeiger==NULL)
       anhaengen(n,v,at,am,aj,et,em,ej,geh);
/*Ist unser neues Element das kleinste und somit kleiner als das
1.Element so müssen wir es an den Anfang hängen */
 else if(zeiger==anfang)
  {
   anfang=(struct angestellt *)malloc(sizeof(struct angestellt));
   strcpy(anfang->name,n);
   strcpy(anfang->vorname,v);
   anfang->alter.tag=at;
   anfang->alter.monat=am;
   anfang->alter.jahr=aj;
   anfang->eingest.tag=et;
   anfang->eingest.monat=em;
   anfang->eingest.jahr=ej;
   anfang->gehalt=geh;

   anfang->next=zeiger;
   anfang->previous=NULL;
  }

Die Erklärungen ob es nun das einzige, das erste oder das letzte Element der Liste ist erspare ich mir hier. Hierzu können sie mehr in einem Kapitel zuvor lesen, der Funktion anhaengen(). Uns soll jetzt vielmehr interessieren wie wir unser Element irgendwo dazwischen reinschieben können.....

else
{
 zeiger1=anfang;
/*Wir suchen das Element das vor dem Zeiger zeiger steht*/
 while(zeiger1->next != zeiger)
     zeiger1=zeiger1->next;
 zeiger=(struct angestellt *)malloc(sizeof(struct angestellt));
 strcpy(zeiger->name,n);
 strcpy(zeiger->vorname,v);
 zeiger->alter.tag=at;
 zeiger->alter.monat=am;
 zeiger->alter.jahr=aj;
 zeiger->eingest.tag=et;
 zeiger->eingest.monat=em;
 zeiger->eingest.jahr=ej;
 zeiger->gehalt=geh;

/*Wir fügen das neue Element ein*/
 zeiger->next=zeiger1->next;
 zeiger->previous=zeiger1;
 zeiger1->next=zeiger;
 zeiger1->next->previous=zeiger;
}/*Ende else*/

Gehen wir schon mal soweit voraus wir haben denn Platz für das Element gefunden und unser zeiger1 zeigt auch schon auf die Adresse vor dem Element, das der Nachfolger von unserem neuen Element werden soll....


doppelt verkettete Listen


Wir wollen unser neues Element nun zwischen dem 2. und 3. Element einfügen...

zeiger->next=zeiger1->next;



doppelt verkettete Listen




zeiger->previous=zeiger1;



doppelt verkettete Listen




zeiger1->next=zeiger; 



doppelt verkettete Listen




zeiger1->next->previous=zeiger; 



doppelt verkettete Listen


Somit hätten wir unser neues Element eingefügt. Hiermit möchte ich mit dem Kapitel "Doppelt verkettete Listen" langsam abschließen. Ich habe mich bei den Kapiteln für Grafiken als Erklärung entschieden die ,wie ich finde, das Thema etwas einfacher darstellen. Vielleicht noch ein paar Tipps zu diesem Thema...

  1. Denken sie immer daran wenn sie Zeiger benutzen das diese auf einen Speicherbereich (Adresse) zeigen. Denn das Problem was viele immer mit den Zeigern haben ist das z.B. mit: zeiger1=zeiger kein Wert an zeiger1 übergeben wird, sondern die Adresse auf die zeiger zeigt.
  2. Benutzen sie Aussagekräftig Namen für die Zeigern. Wie in unserem Fall : next, previous, anfang, ende. Dies ist eine enorme Erleichterung wenn das Programm Fehler (und sie werden immer Fehler machen) hat und sie danach suchen. Denn mit anfang->next=ende kann man sich mehr vorstellen als mit a->n=e. Und wenn sie im Team arbeiten gibt es noch andere Leute die den Code auch noch lesen wollen.
  3. Einer der häufigsten Fehler ist das ein Zeiger auf einem unerlaubten Speicherplatz zeigt. Nehmen sie sich daher die Zeit das ganze auf ein Blatt Papier zu zeichnen damit sie den Ablauf nachvollziehen können. So wie ich es bei den Kapiteln gemacht habe. Gerade bei doppelt verketteten Listen kann man ziemlich schnell mal ein Glied der Kette vergessen. Meist wird dieser Fehler am Anfang gar nicht bemerkt, den der Compiler kann bei Übersetzung des Programms nicht wissen ob ein Zeiger ins Nirwana zeigt. Programmabstürze sind dabei garantiert.
  4. And last but not least. Überprüfen sie immer den Rückgabewert, wenn sie Speicher für eine neue Struktur reservieren. Denn alles was schiefgehen kann wird irgendwann einmal schiefgehen.


Ich habe bei unserem Programm noch ein paar zusätzlich Funktionen geschrieben die ich auch im Programm ausführlich dokumentiert habe. Besonders habe ich Funktionen geschrieben mit denen es möglich ist das ganze auch abzuspeichern und wieder auszulesen (laden). Ich habe das Programm aus Zeitgründen nicht sehr intensiv getestet. Sollten euch ein paar Bugs auffallen schickt mir bitte eine Mail damit ich das beheben kann.

strudop.c (WIN/DOS)       xstrudop.c (Linux)

ein Kapitel zurück          nach oben           ein Kapitel weiter


© 2001,2002 Jürgen Wolf