PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Einfach verkette Listen in C - Was mache ich falsch?



milchmann
31-03-2006, 15:25
Hi, wir mussten jetzt als "Klausur" eine dynamische Bücherverwaltung in C umsetzen und dazu einfach verkettete Listen verwenden.

Ich habe leider nur eine 2.0 (83%) bekommen (:-.

Was ist denn an meinem Code schlecht?


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct buecher {
char autor[16];
char titel[16];
char isbn[11];
struct buecher *naechstes;
};

void eingabe(struct buecher *ein_buch);
void ausgabe(struct buecher *momentanes_buch);
void ausgabeAlle(struct buecher *erstes_buch);
void suche(struct buecher *erstes_buch);
struct buecher *loeschen(struct buecher *erstes_buch);

int main() {
int wahl;
struct buecher *neues_buch = NULL, *vorheriges_buch = NULL, *erstes_buch = NULL;
do {
printf("1 - Buch hinzufuegen \n");
printf("2 - Buch suchen\n");
printf("3 - Alle Buecher ausgeben\n");
printf("4 - Buch entfernen\n");
//Das Programmende funktionniert zwar auch mit
//anderen Zahlen, jedoch passt diese Ausgabe
//besser in meine Ausgabestruktur
printf("5 - Pogrammende\n");
scanf("%d", &wahl);
switch (wahl) {
case 1: {
//Speicher fuer einen neuen Datensatz anfordern
neues_buch = malloc(sizeof(struct buecher));
//Naechstes Buch auf NULL setzen
neues_buch->naechstes = NULL;
//Liste verketten
if (vorheriges_buch != NULL) {
vorheriges_buch->naechstes = neues_buch;
}
//Erstes Buch initialisieren
if(erstes_buch == NULL) {
erstes_buch = neues_buch;
}
//Datensatz einlesen
eingabe(neues_buch);
//Liste verketten
vorheriges_buch = neues_buch; break;
}
//Suche aufrufen
case 2: suche(erstes_buch); break;
//Alle Buecher ausgeben
case 3: ausgabeAlle(erstes_buch); break;
//Ein Buch loeschen
case 4: erstes_buch = loeschen(erstes_buch);
}
} while (wahl != 5);
return 0;
}

//Datensatz fuer ein Buch von der Tastatur einlesen
void eingabe(struct buecher *ein_buch) {
printf("Buchtitel ");
scanf("%s", ein_buch->titel);
printf("Autor ");
scanf("%s", ein_buch->autor);
printf("ISBN ");
scanf("%s", ein_buch->isbn);
}

//Einen Datensatz ausgeben
void ausgabe(struct buecher *momentanes_buch) {
printf("Titel %s\n", momentanes_buch->titel);
printf("Autor %s\n", momentanes_buch->autor);
printf("ISBN %s\n\n", momentanes_buch->isbn);
}

//Alle Buecher ausgeben
void ausgabeAlle(struct buecher *erstes_buch) {
struct buecher *momentanes_buch = erstes_buch;
int i = 1;
//Von 1 bis n alle Datensaetze durchlaufen
while (momentanes_buch != NULL) {
printf("Buch Nr. %d:\n", i);
i++;
ausgabe(momentanes_buch);
//Jede Iteration einen Datensatz weiter
momentanes_buch = momentanes_buch->naechstes;
}
}

void suche(struct buecher *erstes_buch) {
struct buecher *momentanes_buch = erstes_buch;
char suchbegriff[16];
int wahl = 0;
printf("Suche\n");
printf("1 - Titel\n");
printf("2 - Autor\n");
printf("3 - ISBN\n");
scanf("%d", &wahl);
printf("Bitte Suchebgriff eingeben\n");
scanf("%s", suchbegriff);
//Benutzerwahl auswerten und nach den Elementen
//Titel, Autor oder ISBN suchen
//Schleifen laufen von 1 bis N durch und geben einer
//Uebereinstimmung und rufen die Funktion ausgabe() auf
switch (wahl) {
case 1: {
while (momentanes_buch != NULL) {
if (strcmp(momentanes_buch->titel, suchbegriff) == 0) {
ausgabe(momentanes_buch);
}
momentanes_buch = momentanes_buch->naechstes;
} break;
}
case 2: {
while (momentanes_buch != NULL) {
if (strcmp(momentanes_buch->autor, suchbegriff) == 0) {
ausgabe(momentanes_buch);
}
momentanes_buch = momentanes_buch->naechstes;
} break;
}
case 3: {
while (momentanes_buch != NULL) {
if (strcmp(momentanes_buch->isbn, suchbegriff) == 0) {
ausgabe(momentanes_buch);
}
momentanes_buch = momentanes_buch->naechstes;
} break;
}
default: printf("Falsche Eingabe\n");
}
}

//Da wir einfach verkettete Listen verwenden sollten ist diese
//Funktion umfangreicher geworden
struct buecher *loeschen(struct buecher *erstes_buch) {
//Benutzer kann Buecher nach ihrem Titel loeschen
char titel[16];
struct buecher *ein_buch_weiter, *vorheriges_buch;
printf("Titel eingeben\n");
scanf("%s", titel);
int wahl = 0;
//Falls das erste Buch der Liste geloescht werden soll
//So lange der erste Datensatz Aequivalent mit $titel ist
//oder der Benutzer diesen Datensatz nicht loeschen moechte
while (wahl != 2 && strcmp(erstes_buch->titel, titel) == 0) {
ausgabe(erstes_buch);
printf("\nDieses Buch loeschen?\n");
printf("1 - Ja --- 2 - Nein\n");
scanf("%d", &wahl);
if (wahl == 1) {
struct buecher *tempptr;
tempptr = erstes_buch;
//Falls noch weitere Buecher in der Liste existieren
if (erstes_buch->naechstes != NULL) {
erstes_buch = erstes_buch->naechstes;
free(tempptr);
}
//Falls das einzigste Buch geloescht wird
else {
free(tempptr);
return NULL;
}
}
}
ein_buch_weiter = erstes_buch->naechstes;
vorheriges_buch = erstes_buch;
//Datensatz 2 bis n auf Aequivalenz mit $titel
//pruefen und den Nutzer nach einer Loeschung
//fragen
while (ein_buch_weiter != NULL) {
wahl = 2;
if (strcmp(ein_buch_weiter->titel, titel) == 0) {
ausgabe(ein_buch_weiter);
printf("\nDieses Buch loeschen?\n");
printf("1 - Ja --- 2 - Nein\n");
scanf("%d", &wahl);
if (wahl == 1) {
//Falls ein Datensatz n geloescht wird
//n-1->naeschstes auf n+1 zeigen lassen
//und n loeschen (free())
vorheriges_buch->naechstes = ein_buch_weiter->naechstes;
free(ein_buch_weiter);
}
}
//Liste durchlaufen
ein_buch_weiter = ein_buch_weiter->naechstes;
//Vorheriges Buch auch in der Liste weiterlaufen lassen
//falls Buch n nicht geloescht wurde
if (wahl != 1) { vorheriges_buch = vorheriges_buch->naechstes; }
}
return erstes_buch;
}

Joghurt
31-03-2006, 15:54
Warum fragst du uns das und nicht den Lehrer? Noten sind sehr subjektiv. Ich habe mal von einem Experiment gehört. Ein Aufsatz zu einem bestimmten Thema wurde verschiedenen Lehrern zum benoten vorgelegt. Von einer 1 bis zu einer 5 war alles dabei.

Abgesehen davon, ist das "manuelle" Anlegen eines Buches in der case-Anweisung sub-optimal.

Besser wären da zwei Funktionen
void Buch_einfuegen(Buchliste* bl, Buch* b);
void Buch_loeschen(Buchliste* bl, Buch* b);gewesen.

locus vivendi
31-03-2006, 16:01
Hi, wir mussten jetzt als "Klausur" eine dynamische Bücherverwaltung in C umsetzen und dazu einfach verkettete Listen verwenden.

Ich habe leider nur eine 2.0 (83%) bekommen (:-.

Was ist denn an meinem Code schlecht?
Eklatante Defizite bei der Fehlerbehandlung - zum Beispiel vergisst du zu Überprüfen ob scanf fehlgeschlagen ist. Dein Programm lässt sich sehr einfach in eine Endlosschleife schicken. Außerdem benutzt du Arrays fester Größe um vom Benutzer eingegebene Variablen wie Buchtitel und Namen zu Speichern. Das ist Anno 1980, und übrigens ein Grund nicht C, sondern C++ zu verwenden, weil es dort viel leichter ist, Felder fester größe zu Vermeiden.