Segmentattion fault bei verketteten Listen
-
Hallo
ich sitze gerade an einer Aufgabe, in der es darum geht verkette Listen zu handhaben.
Das Programm soll in bei der Eingabeaufforderung einen Stream übergeben bekommen, daraus eine verkettete Liste machen und anschließend nach einem Namen suchen, der beliebig oft vorkommen kann.
Das mit dem Liste erstellen habe ich nach langem hin und her auch geschafft, allerdings beim Suchen habe ich ein Problem. Obwohl der Compiler nicht meckert bekomme ich immer ein segmentation fault.
Das passiert immer dann, wenn meine Suchfunktion (alle_spieler) mit den Zeigern arbeiten soll. Ich habe nun schon vieles versucht, aber bin zu keinem Ergebnis gekommen.Kann mir bitte jemand auf die Sprünge helfen?! Die vermeidlichen Fehlerstellen sind in der Funktion
int alle_spieler(char *ges_name)
in der while-Schleife bei den Zeigern
le->s->name
.
Hier der koplette Code:
// Präprozessor ///////////////////////////////////////////////////////////////////////// #include <stdio.h> #include <stdlib.h> #include <string.h> // Datentypen /////////////////////////////////////////////////////////////////////////// // Aufgabe 10.21 // IO typedef struct spieler{ char land[4]; // [Länderkürzel] char name[26]; // [Spielername] int tore; // [Tore] int vorlagen; // [Vorlagen] int torschuss; // [Torschüsse] int nieten; // [Schüsse neben das Tor] } SPIELER; // Aufgabe 10.03 // IO typedef struct listenelement{ SPIELER *s; struct listenelement *naechste; } LISTENELEMENT; // global //////////////////////////////////////////////////////////////////////////////// static LISTENELEMENT *liste; int ENDE = 0; // Funktionen /////////////////////////////////////////////////////////////////////////// // Aufgabe 10.22 // gibt einen Spielerdatensatz aus // IO void spieler_ausgeben(SPIELER *s){ printf("\nDie Statistik für %s ausgeben:\n\tLand: %s\n\tTore: %d\n\tVorlagen: %d\n\tTorschüsse: %d\n\tFehlschüsse: %d\n", s->name, s->land, s->tore, s->vorlagen, s->torschuss, s->nieten); } // Ende spieler_ausgeben // Aufgabe 10.24 // Einlesen einer Zeile und Konvertierung zu einem Spielerdatensatz // IO void einlesen_spieler(SPIELER *s){ char zahl[4]; int a; a = scanf("%29s", zahl); if(a <= 0){ // prüft den Eingansstrom ENDE = 1; printf("\nStream einlesen abgeschlossen"); return ; } // Ende if s = (SPIELER*) malloc(sizeof(SPIELER)); strcpy(s->land, zahl); scanf("%29s", s->name); scanf("%29s", zahl); s->tore = atoi(zahl); scanf("%29s", zahl); s->vorlagen = atoi(zahl); scanf("%29s", zahl); s->torschuss = atoi(zahl); scanf("%29s", zahl); s->nieten = atoi(zahl); // spieler_ausgeben(s); } // Ende einlesen_spieler // Aufgabe 10.24 // Ein listenelement erstellen und deren Zeiger zurückgeben // IO void listenelement_erstellen(LISTENELEMENT *lie){ einlesen_spieler(lie->s); if(ENDE == 1){return;} // Ende if lie->naechste = NULL; } // Ende listenelement_erstellen // Aufgabe 10.24 // Ein Listenelement anhängen // IO void listenelement_anhaengen(LISTENELEMENT *lie){ if(liste == NULL){ liste = lie; } // Ende if else{ LISTENELEMENT *p; p = liste; while(p->naechste != NULL){ p = p->naechste; } // Ende while p->naechste = lie; } // Ende else*/ } // Ende listenelement_anhaengen // Aufgabe 10.24 // Ein Datenstrom wird ausgelesen // IO void einlesen_stream(){ int n = 0; while(ENDE == 0){ LISTENELEMENT *lie; lie = (LISTENELEMENT *) malloc(sizeof(LISTENELEMENT)); listenelement_erstellen(lie); if(ENDE == 0){ listenelement_anhaengen(lie); n++; } // Ende if } // Ende while printf("\nerfolgrich eingelesene Spieler: %d\n",n); } // Ende einlesen_stream // Aufgabe 10.25 // findet einen Spieler in der Liste // in Bearbeitung int alle_spieler(char *ges_name){ printf("\nGesucht wird: %s", ges_name); int a = 0; LISTENELEMENT*le; le = liste; while(le->naechste != NULL){ printf("%s\t",le->s->name); if(strcmp(le->s->name, ges_name)){ spieler_ausgeben(le->s); a++; } // Ende if le = le->naechste; } // Ende while return a; } // Ende alle_spieler // main ////////////////////////////////////////////////////////////////////////////////// int main(int argc, char **argv){ printf("\n Aufgabe 10.2 - Verkettete Listen implementieren und anwenden \n\n"); einlesen_stream(); printf("\n10 - stream_einlesen -- erledigt"); if(liste == NULL){ printf("\n10 - stream_einlesen -- Fehler"); } // Ende if alle_spieler(argv[1]); printf("\n\n"); return 0; }
Vielen Dank
-
Entweder benutze einen Debugger der das für dich macht (mein GDB ist leider kaputt), oder benutze printf-Debugging:
#define DEBUG printf("Aktuell: %s %d\n", __FUNCTION__, __LINE__);
Und dann pflasterst du deinen Code mit DEBUG bis du die Zeile findest die falsch ist.
Wenn das nicht hilft schreibe dir eine printListe-Funktion die die Liste ausgibst und du genau sehen kannst an welcher Stelle was nicht funktioniert.void printListe(struct listenelement *le){ while (le){ printf("Listenadresse: %p, ", le); printf("Spieler: %p, naechste: %p\n", le->s, le->naechste); le = le->naechste; } }
Damit kannst du dann schrittweise durchgehen bis du die fehlerhafte Funktion findest.
Aber ich glaube ich habe es auch so gefunden. Tausche mal Zeile 71 und 72 miteinander.
-
Wenn das Ding segfaultet, wird's wohl an einem Speicherfehler liegen. Ich hatte Glück:
$ ./main Aufgabe 10.2 - Verkettete Listen implementieren und anwenden eins zwei eins drei eins vier ^D Stream einlesen abgeschlossen erfolgrich eingelesene Spieler: 1 10 - stream_einlesen -- erledigt Gesucht wird: (null) $
Das war der gcc. Der gibt gerne
(null)
aus, wenn man einen Nullzeiger als String ausgeben lassen will. Vielleicht hilft dir das ja weiter.Wenn nicht, kannst du mir die Arbeit sehr erleichtern, indem du den Fehler auf weniger Zeilen eingrenzt, und das erwartete Format der Eingabe genauer spezifizierst.
-
Hallo,
ich habe mal die Ausgabe eingefügt und habe das erhalten:
Listenadresse: 0x8220060, Spieler: (nil), naechste: 0x82200a8
Er hat scheibar keinen einzigen Spieler gespeichert
Wie kann das sein??
-
Zeile 70: einlesen_spieler(lie->s);
Damit willst du in lie->s einen Spieler speichern.
Zeile 52: s = (SPIELER*) malloc(sizeof(SPIELER));
Du überschreibst den Pointer auf die Zieladresse mit einem neuen Pointer, damit verlierst du die Adresse an die du eigentlich den Spieler speichern wolltest.Wenn du einen Parameter an eine Funktion übergibst kriegst du nur eine Kopie des Wertes, s zu überschreiben ändert nicht lie->s. Du musst entweder den Wert auf den lie->s bzw den Wert auf den s zeigt ändern, oder du übergibst eine Referenz auf den Pointer und änderst den Pointer.
Letzteres würde so aussehen:
Zeile 70: einlesen_spieler(&lie->s);
Zeile 40: void einlesen_spieler(SPIELER **s){
Zeile 52: *s = (SPIELER*) malloc(sizeof(SPIELER));Es sind sicher noch ein paar mehr Änderungen nötig.
-
Cool das mit dem DEBUG
Habe mir mal beides ausgedruckt und ein paar kleine Veränderungen gemacht...
// Präprozessor ///////////////////////////////////////////////////////////////////////// #include <stdio.h> #include <stdlib.h> #include <string.h> #define DEBUG printf("Aktuell: %s %d\n", __FUNCTION__, __LINE__); // Datentypen /////////////////////////////////////////////////////////////////////////// // Aufgabe 10.21 // IO typedef struct spieler{ char land[4]; // [Länderkürzel] char name[26]; // [Spielername] int tore; // [Tore] int vorlagen; // [Vorlagen] int torschuss; // [Torschüsse] int nieten; // [Schüsse neben das Tor] } SPIELER; // Aufgabe 10.03 // IO typedef struct listenelement{ SPIELER *s; struct listenelement *naechste; } LISTENELEMENT; // global //////////////////////////////////////////////////////////////////////////////// static LISTENELEMENT *liste; int ENDE = 0; // Funktionen /////////////////////////////////////////////////////////////////////////// // Aufgabe 10.22 // gibt einen Spielerdatensatz aus // IO void spieler_ausgeben(SPIELER *s){ printf("\n\tDie Statistik für %s ausgeben:\n\tLand: %s\tTore: %d\tVorlagen: %d\tTorschüsse: %d\tFehlschüsse: %d\n\n", s->name, s->land, s->tore, s->vorlagen, s->torschuss, s->nieten); } // Ende spieler_ausgeben // Aufgabe 10.24 // Einlesen einer Zeile und Konvertierung zu einem Spielerdatensatz // IO void einlesen_spieler(LISTENELEMENT *t){DEBUG SPIELER *s; s = (SPIELER*)malloc(sizeof(SPIELER)); char zahl[4]; int a; a = scanf("%29s", zahl); if(a <= 0){ /* prüft den Eingansstrom*/DEBUG ENDE = 1; printf("Stream einlesen abgeschlossen\n"); free(s); return ; } // Ende if strcpy(s->land, zahl); scanf("%29s", s->name); scanf("%29s", zahl); s->tore = atoi(zahl); scanf("%29s", zahl); s->vorlagen = atoi(zahl); scanf("%29s", zahl); s->torschuss = atoi(zahl); scanf("%29s", zahl); s->nieten = atoi(zahl); t->s = s; spieler_ausgeben(s);DEBUG } // Ende einlesen_spieler // Aufgabe 10.24 // Ein listenelement erstellen und deren Zeiger zurückgeben // IO void listenelement_erstellen(LISTENELEMENT *lie){DEBUG einlesen_spieler(lie);DEBUG if(ENDE == 1){return;}DEBUG // Ende if lie->naechste = NULL;DEBUG } // Ende listenelement_erstellen // Aufgabe 10.24 // Ein Listenelement anhängen // IO void listenelement_anhaengen(LISTENELEMENT *lie){DEBUG if(liste == NULL){DEBUG liste = lie; } // Ende if else{DEBUG LISTENELEMENT *p; p = liste; while(p->naechste != NULL){ p = p->naechste; } // Ende while p->naechste = lie; } DEBUG// Ende else*/ } // Ende listenelement_anhaengen // Aufgabe 10.24 // Ein Datenstrom wird ausgelesen // IO void einlesen_stream(){DEBUG int n = 0; while(ENDE == 0){ LISTENELEMENT *lie; lie = (LISTENELEMENT *) malloc(sizeof(LISTENELEMENT));DEBUG listenelement_erstellen(lie); DEBUG if(ENDE == 0){DEBUG listenelement_anhaengen(lie); n++; } // Ende if }DEBUG // Ende while printf("erfolgrich eingelesene Spieler: %d\n",n); } // Ende einlesen_stream // Aufgabe 10.25 // findet einen Spieler in der Liste // in Bearbeitung int alle_spieler(char *ges_name){DEBUG printf("Gesucht wird: %s\n", ges_name); int a = 0; LISTENELEMENT*le; le = liste;DEBUG while(le->naechste != NULL){DEBUG if(!strcmp(le->s->name, ges_name)){DEBUG spieler_ausgeben(le->s); a++; } // Ende if le = le->naechste;DEBUG }DEBUG // Ende while return a; } // Ende alle_spieler // main ////////////////////////////////////////////////////////////////////////////////// int main(int argc, char **argv){ printf("\n Hausaufgabe 10.2 - Verkettete Listen implementieren und anwenden \n\n"); einlesen_stream(); printf("10 - stream_einlesen -- erledigt\n"); if(liste == NULL){ printf("10 - stream_einlesen -- Fehler\n");} // Ende if alle_spieler(argv[1]); printf("\n\n"); return 0; }
Jetzt sind nur noch zwei kleine Fehlerchen beim Suchen drin, aber das wird gehen