Verkette Liste-Das zu löschende Element eingeben

Sevenfold

Grünschnabel
Hallo erstmal!
Ich stehe vor dem Problem, dass ich in meiner verketteten Liste ein Element, welches ich vorher eingegeben habe, wieder löschen kann. Und zwar steht in der Aufgabenstellung, dass das zu löschende Element von dem Benutzer abgefragt werden soll. Ich schaffe es nicht, dass ich den Namen des zu löschenden Elements eingeben kann. Das Programm löscht mir immmer nur das erste Element der Liste.

Würde mich über jede Hilfe freuen.

Code:
//------------------------------------------------------------------------
//
// Datei:		 programmname.cpp
//
// Name:		 
// Matr.-Nr.:    123456
// Datum:		 xx.xx.2009 V1.0
// geaendert:	 xx.xx.2009
//
/*Schreiben Sie ein Programm, das eine Wörterliste verwaltet. Die Wörter, die z. B. Namen, 
Orte oder Gegenstände bezeichnen, werden in einer verketteten Liste gespeichert. Mit Hilfe 
eines Menüs sollen folgende Funktionen gewählt werden können: 
a)   Liste erstellen
der Speicherplatz für einen neues Wort wird erstellt und das Wort eingegeben. Die 
Eingabe wird so lange wiederholt, bis "ENDE" eingegeben wird.
b)   Element hinzufügen
der Speicherplatz für ein neues Wort wird erstellt und das Wort eingegeben. Es wird 
gefragt, vor welchem Element das neue Wort eingefügt werden soll.
c)   Element löschen
Das zu löschende Wort wird abgefragt. Es wird gelöscht und sein Speicherplatz 
wieder freigegeben.
Nach jeder Bearbeitung wird die aktuelle Wortliste vor dem Hauptmenue wieder auf dem 
Bildschirm angezeigt. */   
// Eingabe:      Angabe der erforderlichen Eingaben (Benutzer / Datei)
//               
// Ausgabe:      Angabe der vom Programm generierten Ausgaben
//
//------------------------------------------------------------------------
#include <stdio.h>           // Bibliothek fuer printf, scanf, ...
#include <conio.h>           // Bibliothek fuer getch, gets, ...
#include <string.h>
#include <stdlib.h>


struct eintrag { // Deklaration eines Listenelements
char wort[20];
struct eintrag *next;
};
typedef struct eintrag element; // Typedef -> typedef ist eine Deklaration, wird zunächst kein Programmcode vom Compiler erzeugt
struct eintrag *liste;   //Zeiger auf den Anfang der Liste


//Die Funktion "erstellen" wird zunächst mit dem Zeiger auf den Listenanfang aufgerufen, 
//dann rekursiv jeweils mit dem Zeiger auf das nächste Element.

void erstellen (element* ptr){
printf ("Wort eingeben 'ENDE' fuer Ende der Liste: ");
scanf("%s", ptr->wort);
if (strcmp(ptr->wort,"ENDE")==0) ptr->next=NULL;
else {
ptr->next = (element*) malloc(sizeof(element));
erstellen (ptr->next);
}
return;
}

void hinzufügen (element* ptr) {
}


//Das letzte Element der Liste enthält so das Wort "ende" und den Zeiger next = NULL. Die 
//Funktion "anzeigen" wird auch mit dem Zeiger auf das erste Element aufgerufen, dann 
//rekursiv mit dem next-Zeiger auf das jeweils nächste Element.
void anzeigen (element* ptr){
if (ptr->next != NULL) {
printf ("%s\n",ptr->wort);
anzeigen (ptr->next);
}
return;
}

/*void loeschen (element*ptr, char *loeschen) {
	// Dazu muss man den next-Zeiger der Liste auf das neue Element setzen, und den next-Zeiger des neuen Element
	// auf den alten Wert des next-Zeigers der Liste
	liste=ptr->next;
	//printf ("Geben Sie das zu loeschende Wort ein: ");
	//scanf("%s", ptr->wort);
	//ptr = liste ->next;
	//liste->next =liste->next->next;
	
	free(ptr);
	system("cls");
}

*/
void loeschen(element *ptr) {

		
		printf("%s wurde geloescht", ptr->wort);
		liste->next = liste->next->next;
		free(ptr);
		getch();
		system ("cls");
}
int main () {
int z;

do {
	char eingabe[20];

		printf("HAUPTMENUE:\n1 - Liste erstellen\n2 - Element hinzufuegen\n3 - Element loeschen\n4 - Liste anzeigen\n5 - Programm beenden\n\nBitte waehlen Sie: ");
		z=getche();
		printf ("\n\n");

if (z=='1') {
//Beim Erstellen einer neuen Liste muss im Hauptprogramm zunächst der Speicherplatz für 
//das Anfangselement mit der Adresse  "liste" reserviert werden. Die Speicherreservierung 
//für die folgenden Elemente erfolgt in der Funktion erstellen.
	liste = (element*)malloc(sizeof(element));
	erstellen(liste);
}
	system("cls");

	if (z=='2') {	
}
	if (z=='3') {

		printf("Zu loeschendes Wort eingeben: ");
		scanf("%s", eingabe);
		loeschen(liste);
				

}
	if (z=='4') {
		printf("Der Inhalt ihrer gespeicherten Liste:\n");
		anzeigen(liste);
		getch();
		system ("cls");
}



} while (z!='5');


}
 
Hi.

Wo ist denn jetzt genau dein Problem?

Weißt du nicht wie man die Liste durchläuft? (=> Schleife?)

Oder wie du den zu löschenden Eintrag findest (=> strcmp?)

Gruß
 
Hi,
als erstes wäre nicht schlecht der "loeschen"-Fkt das zu löschende Wort zu übergeben, denn die Funktion weiß ja garnicht, was sie löschen soll. (Siehe hinzufügen)
Desweiteren musst du dir überlegen, wie die Funktion intern aufgebaut sein muss. Wie deepthroat schon sagte, solltest du eine Schleife haben und alle Elemente durchgehen.

Grüße
 
Danke schonmal für die Beiträge die haben mir schon weitergeholfen.
Ich habe die Eingabe einfach in die löschen Funktion eingefügt somit muss ich nichts übergeben.
Wie vergleiche ich nun das wort in der liste mit der eingabe? if (strcmp ....
 
Ich versteh nicht wo hier der Fehler ist:

Code:
void loeschen(element *ptr) {
	char eingabe[20];
		printf("Zu loeschendes Wort eingeben: ");
		scanf("%s", eingabe);

		do {
		if(strcmp(ptr->wort, eingabe)==NULL) { // Eintrag gefunden

		if(ptr->wort==NULL) { // erster Eintrag
			liste=ptr->next;
		} else {
			liste->next=ptr;
		}

		} else if(strcmp(ptr->wort, "ENDE")==0) {
			printf("'%s' wurde nicht gefunden!", eingabe);

		} else {
			loeschen(ptr->next);
		}
		
		} while (strcmp != NULL);
			printf("%s wurde geloescht", ptr->wort);
			free(ptr);

	 }
 
Zuletzt bearbeitet:
Du übergibst der Funktion den globalen Zeiger, das ist unnötig, da er sowieso global ist. Dann in der Zeile, in der du prüfst ob es der erste Eintrag ist: Das ist ja egal, ob es nun der erste Eintrag ist, oder nicht, du willst ja nur das eingegebene Element löschen oder?
Nun ja, auf jeden Fall, wenn es so ist, dann schreibst du liste = ptr->next; Da ptr ja liste ist, bedeutet das liste = liste -> next; Ich glaube kaum, dass das deine Absicht ist.
Den weiteren Code habe ich mir bis jetzt noch nicht angesehen, nur while (strcmp != NULL); ist auch nicht korrekt. strcmp ist eine Funktion, die 2 Parameter übergeben bekommt. Du übergibst hier nur den Namen der Funktion und das bewirkt eine Endlosschleife (Der Name einer Funktion ohne () ist die Adresse der Funktion).

Lg
 
Das Endergebnis sieht jetzt so aus (Vielleicht helf ich damit ja dem einen oder anderen)
Code:
/*Schreiben Sie ein Programm, das eine Wörterliste verwaltet. Die Wörter, die z. B. Namen, 
Orte oder Gegenstände bezeichnen, werden in einer verketteten Liste gespeichert. Mit Hilfe 
eines Menüs sollen folgende Funktionen gewählt werden können: 
a)   Liste erstellen
der Speicherplatz für einen neues Wort wird erstellt und das Wort eingegeben. Die 
Eingabe wird so lange wiederholt, bis "ENDE" eingegeben wird.
b)   Element hinzufügen
der Speicherplatz für ein neues Wort wird erstellt und das Wort eingegeben. Es wird 
gefragt, vor welchem Element das neue Wort eingefügt werden soll.
c)   Element löschen
Das zu löschende Wort wird abgefragt. Es wird gelöscht und sein Speicherplatz 
wieder freigegeben.
Nach jeder Bearbeitung wird die aktuelle Wortliste vor dem Hauptmenue wieder auf dem 
Bildschirm angezeigt. */   
// Eingabe:      Angabe der erforderlichen Eingaben (Benutzer / Datei)
//               
// Ausgabe:      Angabe der vom Programm generierten Ausgaben
//
//------------------------------------------------------------------------
#include <stdio.h>           // Bibliothek fuer printf, scanf, ...
#include <conio.h>           // Bibliothek fuer getch, gets, ...
#include <string.h>
#include <stdlib.h>


struct eintrag { // Deklaration eines Listenelements
char wort[20];
struct eintrag *next;
};
typedef struct eintrag element; // Typedef -> typedef ist eine Deklaration, wird zunächst kein Programmcode vom Compiler erzeugt
struct eintrag *liste;   // Zeiger auf den Anfang der Liste


void erstellen (element* ptr){
printf ("Wort eingeben 'ENDE' fuer Ende der Liste: ");
scanf("%s", ptr->wort);
if (strcmp(ptr->wort,"ENDE")==0){ 
	ptr->next=NULL;
	printf("\nListe erfolgreich erstellt!\n\n");
	system("Pause");
}
else {
ptr->next = (element*) malloc(sizeof(element));
erstellen (ptr->next); // Rekursion
}
return;
}

void hinzufügen (element* ptr, char*eingabeübergabe, char* posübergabe, element*vorptr) { 
		// Es wird ein Zeiger auf der vorherige Element und auf das nachfolgende Element benötigt
		if(strcmp(posübergabe, ptr->wort)==0) { // Posübergabe gefunden
			element *nachptr=(element *)malloc(sizeof(element)); // Speicher reservieren
			strcpy(nachptr->wort, eingabeübergabe); // in nachptr->wort wird eingabeübergabe eingefügt
			nachptr->next=ptr; 
		if(vorptr==NULL) { // erste Eintrag
			liste=nachptr;
		} else {
			vorptr->next=nachptr;
		}
			printf("\n'%s' wurde vor '%s' hinzugefuegt\n", eingabeübergabe, posübergabe);
			getch();
			system("cls");
		} else if(strcmp(ptr->wort, "ENDE")==0) {
			printf("\n'%s' wurde nicht gefunden!", posübergabe);
			getch();
			system("cls");
	} else {
		hinzufügen(ptr->next, eingabeübergabe, posübergabe,ptr); // Rekursion
	}
}


//Das letzte Element der Liste enthält so das Wort "ende" und den Zeiger next = NULL. Die 
//Funktion "anzeigen" wird auch mit dem Zeiger auf das erste Element aufgerufen, dann 
//rekursiv mit dem next-Zeiger auf das jeweils nächste Element.
void anzeigen (element* ptr){
if (ptr->next != NULL) {
printf ("%s\n",ptr->wort);
anzeigen (ptr->next);
}
return;
}

void loeschen(element *ptr, char* eingabeübergabe, element *vorptr) {
		if(strcmp(ptr->wort, eingabeübergabe)==0){ //strcmp vergleicht zwei Strings miteinander 
			if(vorptr==NULL){ // Erster Eintrag
			liste=ptr->next; // Liste ist der Anfang der Liste
			}
			else {
				vorptr->next=ptr->next; // Nächstes element
			}		
			printf("\n'%s' wurde geloescht\n", ptr->wort);
			free(ptr);
			getch();
			system("cls");
			}
			else if(strcmp(ptr->wort, "ENDE")==0) {
				printf("\n'%s' konnte nicht gefunden werden!\n", eingabeübergabe);
				getch();
				system("cls");
		} 
		else {
		loeschen(ptr->next,eingabeübergabe, ptr); // Rekursion
		}
		
	 }


int main () {
int z;

do {

	printf("HAUPTMENUE:\n1 - Liste erstellen\n2 - Element hinzufuegen\n3 - Element loeschen\n4 - Liste anzeigen\n5 - Programm beenden ");
	printf ("\n\n");
	if (liste!=NULL){
		printf("Es befinden sich folgende Elemente in der Liste:\n");
		anzeigen(liste);
		}
	printf("\nBitte waehlen Sie: ");
	z=getche();
		

if (z=='1') {
//Beim Erstellen einer neuen Liste muss im Hauptprogramm zunächst der Speicherplatz für 
//das Anfangselement mit der Adresse  "liste" reserviert werden. Die Speicherreservierung 
//für die folgenden Elemente erfolgt in der Funktion erstellen.
	system("cls");
	liste = (element*)malloc(sizeof(element));
	erstellen(liste);
}
	system("cls");

	if (z=='2') {		
	char eingabe [20];
	char neueswort [20];
		printf ("Folgende Strings befinden sich in der Liste:\n");
		anzeigen(liste);
		printf("\nNeues Wort eingeben: ");
		scanf("%s", neueswort);
		printf("\nVor welchem Element wollen Sie '%s' einfuegen: ",neueswort);
		scanf("%s", eingabe);
		hinzufügen(liste,neueswort,eingabe,NULL);
}
	if (z=='3') {
		char eingabe [20];
		printf ("Folgende Strings befinden sich in der Liste:\n");
		anzeigen(liste);
		printf("\nZu loeschendes Wort eingeben: ");
		scanf("%s", eingabe);
		loeschen(liste,eingabe, NULL);
}
	if (z=='4') {
		printf("Der Inhalt ihrer gespeicherten Liste:\n");
		anzeigen(liste);
		getch();
		system ("cls");
}

} while (z!='5');

}
 
Das Endergebnis sieht jetzt so aus (Vielleicht helf ich damit ja dem einen oder anderen)
Wirklich schön ist das eigentlich nicht. Wozu übergibst du da noch diesen vorptr? Das ist unnötig.

Ebenso wenig ist ein besonderes Wort notwendig um das Ende der Liste zu markieren. Jetzt kann man ja das Wort "ENDE" nicht in der Liste speichern ohne das die Liste dort plötzlich zuende ist...

Auch die Verwendung der Rekursion ist problematisch, da der Aufrufstack ziemlich begrenzt ist und das bei größeren Listen schnell zum Absturz führt.

Außerdem ist es unschön, dass du eine globale Variable verwendest, so kannst du die Funktion nicht für mehrere Listen verwenden.

Es gibt sicherlich verschiedene Möglichkeiten zur Implementierung. Vorschlag:
C:
void loeschen(element** list, const char* str) {
  element* e = *list;
  while (e != NULL) {
    if (strcmp(e->wort, str) == 0) { /* OK, gefunden. Löschen. */
       *list = e->next;
       free(e);
       return; // nur das erste gefundene Element löschen
    }
    list = &(e->next);
    e = e->next;
  }
}

loeschen(&list, "abc");
Gruß
 
Zurück