Gast demo88 Geschrieben 13. April 2011 Geschrieben 13. April 2011 Hallo, Ich bekomme bei einem C Programm an einer bestimmten Stelle in einer Funktion immer einen Speicherzugriffsfehler. Das Problem an der Sache ist, wenn ich die Funktion mehrmals hintereinander aufrufe dann klappt sie ohne Probleme. Habe da aber ein Menü zu "programmiert" und jetzt kommt an einer Stelle eben immer der Fehler... Das C Programm ist ein Krawattenhalter, die Funktion fügt eine neue Krawatte immer an der letzten Position ein und setzt den Zeiger der aktuellen Krawatte *k auf diese. Das ganze ist eine einfach verkettete Liste und war schon unglaublich stolz auf mich das es Funktioniert hat, nur nachdem ich die Funktion jetzt aus dem Menü aufrufe eben nicht mehr! main.c int main() { Krawatte *k = 0; char menuInput = '\0'; char insColor; char insPattern; ////////// Wenn ich die nächsten Zeile auskommentiere, dafür das Menü kommentiere läuft alles wie es soll /* Daten d1, d2; d1.color = ROT; d1.pattern = KARIERT; d2.color = BLAU; d2.pattern = GESTREIFT; einfuegen(&k, d1); einfuegen(&k, d2); einfuegen(&k, d1); einfuegen(&k, d2); ausgabe(&k); printf("Fertig");*/ ////////// while (menuInput != 'q') { printf("Menu\n"); printf("----\n"); printf("Press [i] to insert\n"); printf("Press [q] to quit\n"); printf("Press [p] to print\n"); printf("Eingabe: "); scanf("%1s", &menuInput); switch(menuInput) { case 'i': //Krawatte einfügen printf("Krawatte einfuegen:\n"); Daten *insData = (Daten *) malloc(sizeof(Daten)); //Farbe printf("Farbe:\n"); printf("Rot [r]\n"); printf("Gelb [g]\n"); printf("Blau [b]\n"); printf("Eingabe: "); scanf("%1s", &insColor); switch(insColor) { case 'r': insData->color = ROT; break; case 'g': insData->color = GELB; break; case 'b': insData->color = BLAU; break; default: insData->color = ROT; } //Muster printf("\nMuster:\n"); printf("Kariert [k]\n"); printf("Gestreift [s]\n"); printf("Gepunktet [p]\n"); printf("Eingabe: "); scanf("%1s", &insPattern); switch(insPattern) { case 'k': insData->pattern = KARIERT; break; case 's': insData->pattern = GESTREIFT; break; case 'p': insData->pattern = GEPUNKTET; break; default: insData->pattern = KARIERT; } printf("\n"); einfuegen(&k, *insData); free(insData); break; case 'p': ausgabe(&k); break; } } return 0; } listType.h typedef enum farbe {ROT, GELB, BLAU} Farbe; typedef enum muster {KARIERT, GESTREIFT, GEPUNKTET} Muster; typedef struct Daten { Farbe color; Muster pattern; } Daten; typedef struct Krawatte { Daten data; struct Krawatte *nextTie; } Krawatte; listType.c void einfuegen(Krawatte **k, Daten d) { //Neue Krawatte erstellen Krawatte *newTie = (Krawatte *) malloc(sizeof(Krawatte)); if (newTie == NULL) { printf("Fehler: Kein Speicher mehr vorhanden!\n"); exit(1); } //Überprüfen ob schon eine Krawatte im Halter exisitiert if (*k == NULL) { newTie->data = d; //Erste und letzte Krawatte im Halter newTie->nextTie = newTie; *k = newTie; } else { Krawatte *lastTie = (Krawatte *) malloc(sizeof(Krawatte)); lastTie = *k; printf("lastTie: %p\n", lastTie); printf("lastTie->nextTie: %p\n", lastTie->nextTie); printf("*k: %p\n", *k); //Suche letzte Krawatte im Halter while (lastTie->nextTie != *k) { [COLOR="red"]//IN DER NÄCHSTEN ZEILE LIEGT DER SPEICHERZUGRIFFSFEHLER!! lastTie = lastTie->nextTie;[/COLOR] } newTie->data = d; //Füge Krawatte an letzter Position ein und setze Zeiger auf neu eingefügte Krawatte newTie->nextTie = *k; lastTie->nextTie = newTie; *k = newTie; //Speicher freigeben free(lastTie); } /* printf("\n\n----\n"); printf("newTie: %p\n", newTie); printf("newTie->nextTie: %p\n", newTie->nextTie); printf("*k: %p\n", *k); printf("----\n\n"); */ printf("Krawatte wurde eingefuegt:\n"); ausgabeKrawatte(newTie->data.color, newTie->data.pattern); } Ein paar Sachen waren vorgegeben: Die Structs inkl Aufbau und Namen und die Signatur von einfuegen. Der Rest ist verhandelbar... Zitieren
Klotzkopp Geschrieben 13. April 2011 Geschrieben 13. April 2011 Das malloc/free-Paar im else-Block der einfuegen-Funktion ist falsch. Krawatte *lastTie = (Krawatte *) malloc(sizeof(Krawatte)); Hier holst du nochmal Speicher für eine Krawatte. Warum überhaupt? lastTie = *k; Hier verbiegst du den Zeiger lastTie auf den Listenanfang. Damit hast du keinen Zeiger mehr, der auf den gerade reservierten Speicher zeigt -> Speicherleck. free(lastTie); Da lastTie auf deinen alten Listenanfang zeigt, löschst du hier eine Krawatte aus deiner Liste. Der Vorgänger verweist allerdings noch darauf, darum fliegt es dir um die Ohren, wenn du das nächste Mal die Liste durchgehst. Zitieren
Gast demo88 Geschrieben 13. April 2011 Geschrieben 13. April 2011 Ja das kann schon sein, aber habe nur vergessen das wieder rauszunehmen, habe es Testweise eingefügt, den Fehler gab es schon vorher, bzw gibt es jetzt wieder. So sieht der else Block eigentlich aus: else { Krawatte *lastTie = *k; printf("lastTie: %p\n", lastTie); printf("lastTie->nextTie: %p\n", lastTie->nextTie); printf("*k: %p\n", *k); //Suche letzte Krawatte im Halter while (lastTie->nextTie != *k) { printf("Suche nachechste Krawatte...\n"); lastTie = lastTie->nextTie; } newTie->data = d; //Füge Krawatte an letzter Position ein und setze Zeiger auf neu eingefügte Krawatte newTie->nextTie = *k; lastTie->nextTie = newTie; *k = newTie; } Vielen Dank schon mal:) Zitieren
Klotzkopp Geschrieben 13. April 2011 Geschrieben 13. April 2011 Mit diesem Code tritt das Problem bei mir nicht mehr auf. Allerdings hast du noch einen Fehler beim Einlesen der Benutzereingaben: Wenn du mit %1s einliest, brauchst du ein char-Array mit mindestens zwei Elementen, weil automatisch eine Nullterminierung angehängt wird. Alternativ kannst du auch mit %c einlesen. Zitieren
Gast demo88 Geschrieben 13. April 2011 Geschrieben 13. April 2011 Ja das Problem daran war das dadurch manchmal scanf übersprungen wurde. (Hab auch dazu was in dem MSDN nachgelesen - programmiere zwar mit Linux aber durch %1s war das Problem dann trotzdem gelöst). Aber mit dem Code oben klappts bei dir? Theoretisch sollte es bei mir ja auch. Wie man in der main.c sieht, wenn ich den oberen auskommentierten Code benutze, also einfach ein paar mal hintereinander einfuegen(x, y) aufrufe, funktioniert es. Durch das Menü kommt in der Funktion der Speicherzugriffsfehler... Zitieren
Klotzkopp Geschrieben 13. April 2011 Geschrieben 13. April 2011 Wenn du bei %1s bleibst, musst du aus deinen Eingabevariablen char-Arrays mit 2 Elementen machen, sonst erzeugt der Code undefiniertes Verhalten. Zitieren
Gast demo88 Geschrieben 13. April 2011 Geschrieben 13. April 2011 Ok gesagt getan. Menü funktioniert immer noch, Fehler leider immer noch da:( Aber woran kann es denn bitte liegen das es ohne Menü funktioniert, mit aber nicht? Da muss das Menü doch irgendwo am Speicher rumwurschteln oder? int main() { Krawatte *k = 0; char menuInput[1]; menuInput[0] = '\0'; char insColor[1]; char insPattern[1]; while (menuInput[0] != 'q') { printf("Menu\n"); printf("----\n"); printf("Press [i] to insert\n"); printf("Press [q] to quit\n"); printf("Press [p] to print\n"); printf("Eingabe: "); scanf("%1s", menuInput); switch(menuInput[0]) { case 'i': //Krawatte einfügen printf("Krawatte einfuegen:\n"); Daten *insData = (Daten *) malloc(sizeof(Daten)); //Farbe printf("Farbe:\n"); printf("Rot [r]\n"); printf("Gelb [g]\n"); printf("Blau [b]\n"); printf("Eingabe: "); scanf("%1s", insColor); switch(insColor[0]) { case 'r': insData->color = ROT; break; case 'g': insData->color = GELB; break; case 'b': insData->color = BLAU; break; default: insData->color = ROT; } //Muster printf("\nMuster:\n"); printf("Kariert [k]\n"); printf("Gestreift [s]\n"); printf("Gepunktet [p]\n"); printf("Eingabe: "); scanf("%1s", insPattern); switch(insPattern[0]) { case 'k': insData->pattern = KARIERT; break; case 's': insData->pattern = GESTREIFT; break; case 'p': insData->pattern = GEPUNKTET; break; default: insData->pattern = KARIERT; } printf("\n"); einfuegen(&k, *insData); free(insData); break; case 'p': ausgabe(&k); break; } } return 0; } Zitieren
Klotzkopp Geschrieben 13. April 2011 Geschrieben 13. April 2011 Ich sagte zwei Elemente. Arrays mit einem Element lösen das Problem nicht. Zitieren
Gast demo88 Geschrieben 13. April 2011 Geschrieben 13. April 2011 (bearbeitet) Oh mein Gott das war echt doof von mir:D Dachte wenn ich ein Array erstelle mit [1] Elementen erzeugt der 0 und 1...Kurz drüber nachgedacht, korrigiert und jetzt funktioniert es;) Gibt wahrscheinlich einen guten Grund warum der Speicherfehler erst später auftritt aber ist ja schrecklich wenn man nach Fehlern suchen will. Vielen vielen Dank! Edit: Weil ich nicht der Typ bin der sich alles vorkauen lässt und gerne selber die Fehler findet (Höhö): Wie kann ich Speicherzugriffsfehler debuggen? Benutze Eclipse oder die Konsole unter Debian 6 Bearbeitet 13. April 2011 von demo88 Zitieren
Empfohlene Beiträge
Dein Kommentar
Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.