TDM Geschrieben 6. Juli 2005 Geschrieben 6. Juli 2005 hi, Ich hab hier ein kleines Problem mit meinem C Programm. Es soll eine Art Warteschlange (FIFO) simulieren. Soweit geht auch alles, nur wenn ich das Programm beenden will, dann bekomm ich immer einen Speicherfehler O.o Weis jemand woran es liegt ? Ist bestimmt nur eine Kleinigkeit und ich seh den Wald vor lauter Bäumen nicht... //Einsprungspunkt für FIFO.cpp #include <iostream> using namespace std; #if !defined(CASE) || !defined(DEFAULT) #define CASE break;case #define DEFAULT break;default #endif #if !defined(CLS) #include <stdlib.h> #define CLS system("CLS") #endif #define MAX_ATTEMPT 3 /* Anzahl der Fehlversuche */ //Struct Deklaration struct sNode; //Typedef typedef int Element; typedef sNode Node, *Link; /* Node = Elemente */ /* Link = Verweise */ //Funktion void print_menu(unsigned int Orders); void push(Element data); void pop(void); Element show(void); //Struct Definition struct sNode { Element Elem; Link PPrev; Link PNext; }; //Kopf und Schwanz (erste und letzte) Link head; Link tail; int main() { short int Quit = MAX_ATTEMPT, Wahl; unsigned int Orders = 0; Element data; while (Quit) { print_menu(Orders); scanf("%d", &Wahl); switch (Wahl) { case 1: CLS; printf("Zahl eingeben:\t"); scanf("%d", &data); push(data); Orders++; CASE 2: CLS; printf("Aktueller Auftrag:\t%d\n\n",show()); CASE 3: pop(); CLS; Orders--; CASE 4: Quit = 0; DEFAULT: CLS; printf("ungueltige Eingabe\n\n"); Quit--; } } return 0; } void print_menu(unsigned int Orders) { printf("********************************************************************************" "* *" "* 1 = Neuen Auftrag erzeugen *"); if (Orders) printf("* 2 = Aktuellen Auftrag anzeigen *" "* 3 = Aktuellen Auftrag loeschen *"); printf("* 4 = Programm beenden *" "* *" "********************************************************************************"); } void push(Element data) { static bool IsHead = true; Link tmp; tmp = (Link) malloc(sizeof(sNode)); tmp -> Elem = data; /* Daten eintragen */ if (IsHead) { head = tmp; tmp -> PPrev = NULL; /* Anfang auf NULL setzen */ IsHead = false; /* nicht mehr das erste Element */ } else { tmp -> PPrev = tail; /* Verlinkung zum Vorherigen */ tail -> PNext = tmp; /* Verlinkung zum Nächsten */ } tmp -> PNext = NULL; /* Nächste vom Nächsten gibts nicht */ tail = tmp; /* Neues Ende */ } inline Element show(void) { return head -> Elem; } void pop(void) { static bool WasLast = false; if (!WasLast) { Link tmp; tmp = head -> PNext; tmp -> PPrev = NULL; free(head); head = tmp; if (head == tail) /* erste gleich letzte (nur noch 1 Element) */ { WasLast = true; } } else { head -> Elem = tail -> Elem = NULL; free(head); } } Zitieren
Klotzkopp Geschrieben 6. Juli 2005 Geschrieben 6. Juli 2005 Deine Vorgehensweise mit den statischen bool-Variablen funktioniert so nicht. Wenn man z.B. ein Element anlegt und gleich wieder löscht, versuchst du in pop() auf head -> PNext -> PPrev zuzugreifen. head -> PNext ist aber 0. Mit funktionsstatischen Variablen kannst du nicht die Sonderfälle erkennen. Du musst das über die Zeiger selbst prüfen. Zitieren
TDM Geschrieben 6. Juli 2005 Autor Geschrieben 6. Juli 2005 ja, schon... nur das ja ne ausnahme, man wird bestimmt keine verkette Liste benutzen wenn man nur einen Auftrag hatt Notfalls kann ich das über "unsigned int Orders" aber mal abgesehen von dem Problem geht das ja... nur dann halt bei Wahl = 4 bekomm ich den blöden Speicherfehler und ich weis nicht warum kann doch nicht sein dass das mit der static Variable zusammenhängt O.o' Zitieren
Klotzkopp Geschrieben 6. Juli 2005 Geschrieben 6. Juli 2005 aber mal abgesehen von dem Problem geht das ja...Tut mir leid, aber dein Programm geht nur, wenn man zu Beginn mindestens zwei Einträge anlegt, und zwischendurch nicht wieder alle löscht. nur dann halt bei Wahl = 4 bekomm ich den blöden Speicherfehler und ich weis nicht warum Ich bekomme bei Wahl = 4 keinen Speicherfehler. Ich bekomme einen handfesten Absturz wegen Dereferenzierung eines Nullzeigers, wenn ich ein Element hinzufüge und gleich wieder lösche. Geht das bei dir etwa? kann doch nicht sein dass das mit der static Variable zusammenhängt O.o'Warum kann das nicht sein? Du versuchst, mit diesen statischen Variablen die Sonderfälle für push (noch kein Eintrag da) und pop (nur noch ein Eintrag da) zu unterscheiden. Das geht aber nicht, weil sich die Anzahl der Einträge eben in push und pop ändern kann. Wenn ich den letzten Eintrag in pop lösche, müsste IsHead in push ja auf magische Weise wieder true werden, damit das funktioniert. Zitieren
TDM Geschrieben 6. Juli 2005 Autor Geschrieben 6. Juli 2005 Irgentwie ging Edit nicht...: *keine Probleme mag* void pop(void) { if (head -> PNext) { Link tmp; tmp = head -> PNext; tmp -> PPrev = NULL; free(head); head = tmp; } else if (head == tail && head -> Elem) /* erste gleich letzte (nur noch 1 Element) */ { head -> Elem = NULL; } else { head -> Elem = tail -> Elem = NULL; free(head); } } Nun hab ich aber immernoch das Speicherproblem beim beenden :/ Edit: OK... IsHead hab ich vergessen :X Zitieren
TDM Geschrieben 6. Juli 2005 Autor Geschrieben 6. Juli 2005 Link head = (Link) malloc(sizeof(sNode)); Link tail; int main() { short int Quit = MAX_ATTEMPT, Wahl; unsigned int Orders = 0; Element data; head -> Elem = NULL; while (Quit) { print_menu(Orders); scanf("%d", &Wahl); switch (Wahl) { case 1: CLS; printf("Zahl eingeben:\t"); scanf("%d", &data); push(data); Orders++; CASE 2: CLS; printf("Aktueller Auftrag:\t%d\n\n",show()); CASE 3: pop(); CLS; Orders--; CASE 4: Quit = 0; DEFAULT: CLS; printf("ungueltige Eingabe\n\n"); Quit--; } } return 0; } void push(Element data) { Link tmp; tmp = (Link) malloc(sizeof(sNode)); tmp -> Elem = data; /* Daten eintragen */ if (!head -> Elem) { head = tmp; tmp -> PPrev = NULL; /* Anfang auf NULL setzen */ } else { tmp -> PPrev = tail; /* Verlinkung zum Vorherigen */ tail -> PNext = tmp; /* Verlinkung zum Nächsten */ } tmp -> PNext = NULL; /* Nächste vom Nächsten gibts nicht */ tail = tmp; /* Neues Ende */ } ok... jetzt gehts eigentlich auch nachdem alles gelöscht wurde nur der speicherfehler kommt immernoch Zitieren
Klotzkopp Geschrieben 6. Juli 2005 Geschrieben 6. Juli 2005 nur der speicherfehler kommt immernoch Bei mir läuft's jetzt. Wie sieht denn dieser "Speicherfehler" aus? Bekommst du eine Fehlermeldung? Wenn ja, wie lautet die genau? Zitieren
TDM Geschrieben 6. Juli 2005 Autor Geschrieben 6. Juli 2005 Debug Error! Programm: d:\C++\vl_FIFO\FIFO.exe Modul: d:\C++\vl_FIFO\FIFO.exe file: d:\C++\vl_FIFO\FIFO.cpp Line: 78 Run Time Error #2 - Stack around the variable "Wahl" was corrupted dann klick ich auf wiederholen dann kommt das: Zitieren
Klotzkopp Geschrieben 6. Juli 2005 Geschrieben 6. Juli 2005 Deklarier Wahl bitte mal als int, nicht als short int. P.S.: Hättest du diese Meldung früher gebracht, hätte ich dir viel schneller helfen können Zitieren
TDM Geschrieben 6. Juli 2005 Autor Geschrieben 6. Juli 2005 Hättest früher fragen können ne spass Warum meckert der bei short int ? O.o Zitieren
Klotzkopp Geschrieben 6. Juli 2005 Geschrieben 6. Juli 2005 Warum meckert der bei short int ? O.oIch nehme mal an, dass du auf einem 32Bit-Windows mit MSVC unterwegs bist. Da hat ein short int zwei Byte, und ein int vier. scanf mit %d geht von einem int aus, also wird die Adresse, die du mitlieferst, als Zeiger auf einen vier Byte großen Speicherbereich interpretiert, und der eingegebene Wert da rein geschrieben. Von diesen vier beschriebenen Bytes gehören aber nur die ersten beiden zu Wahl, die anderen beiden könnten theoretisch zu einer anderen Variablen gehören. Der Wert, der ihn Wahl landet, ist der gleiche, weil dein Windows Little-Endian ist. Zitieren
TDM Geschrieben 6. Juli 2005 Autor Geschrieben 6. Juli 2005 na ok, danke Morgen dann das ganze mit LIFO ? *g* Zitieren
TDM Geschrieben 7. Juli 2005 Autor Geschrieben 7. Juli 2005 ok... nicht mit Lifo... aber trotzdem wieder ein speicher fehler :/ stdflifo.h: #if !defined(CASE) || !defined(DEFAULT) #define CASE break;case #define DEFAULT break;default #endif #if !defined(CLS) #include <stdlib.h> #define CLS system("CLS") #endif #define MAX_ATTEMPT 3 /* Anzahl der Fehlversuche */ #define FEHLEINGABE CLS; printf("ungueltige Eingabe\n\n");Quit-- #define VL_MODE_DEFAULT 0 #ifndef VL_MODE #define VL_MODE VL_MODE_DEFAULT #endif //Struct Deklaration struct sNode; //Typedef #ifndef Element typedef int Element; #endif typedef sNode *Link; /* Link = Verweise */ //Struct Definition struct sNode { Element ID; Element Elem; Link PPrev; Link PNext; }; #define NEW_ADDRESS (Link) malloc(sizeof(sNode)) #if !VL_MODE //Kopf und Schwanz (erste und letzte) Link head = NEW_ADDRESS; Link tail; #else Link tail = NEW_ADDRESS; #endif //Funktion void print_menu(unsigned int Orders) { printf("********************************************************************************" "* *" "* 1 = Neuen Auftrag erzeugen *"); if (Orders) printf("* 2 = Aktuellen Auftrag anzeigen *" "* 3 = Aktuellen Auftrag loeschen *"); printf("* 4 = Programm beenden *" "* *" "* Noch %d Autraege *" "********************************************************************************",Orders); } /*////////////////////////////////////////////////////////////////// // LIFO Funktionen //////////////////////////////////////////////////////////////////*/ #if !VL_MODE void push(Element data) { Link tmp; tmp = NEW_ADDRESS; tmp -> Elem = data; /* Daten eintragen */ if (!head -> Elem) { head = tmp; [b]//tmp -> ID = 0;[/b] tmp -> PPrev = NULL; /* Anfang auf NULL setzen */ } else { [b]//tmp -> ID = (tmp -> PPrev -> ID + 1);[/b] tmp -> PPrev = tail; /* Verlinkung zum Vorherigen */ tail -> PNext = tmp; /* Verlinkung zum Nächsten */ } tmp -> PNext = NULL; /* Nächste vom Nächsten gibts nicht */ tail = tmp; /* Neues Ende */ } inline Element show(void) { return head -> Elem; } inline void set_default(void) { head -> Elem = NULL; } void pop(void) { if (head -> PNext) /* Wenn es ein nächstes gibt */ { Link tmp; tmp = head -> PNext; tmp -> PPrev = NULL; free(head); head = tmp; } else if (head == tail && head -> Elem) /* erste gleich letzte (nur noch 1 Element) */ { head -> Elem = tail -> Elem = NULL; free(head); /* Addresse freigeben */ } } /*////////////////////////////////////////////////////////////////// // FIFO Funktionen //////////////////////////////////////////////////////////////////*/ #else void push(Element data) { Link tmp; tmp = (Link) malloc(sizeof(sNode)); tmp -> Elem = data; tmp -> PPrev = tail; tail -> PNext = tmp; tmp -> PNext = NULL; tail = tmp; } inline Element show(void) { return tail -> Elem; } inline void set_default(void) { tail -> PPrev = NULL; } void pop(void) { if(tail -> PPrev) /*nicht das Letzte */ { Link tmp; tmp = (Link) malloc(sizeof(sNode)); tmp = tail -> PPrev; tmp -> PNext = NULL; free(tail); tail = tmp; } else { free(tail); /* letzte löschen */ } } #endif wenn ich jetzt die die ID zeilen (die dicken) wieder auskommentiere, dann bekomm ich einen speicherfehler in der art von Die Ausnahme "unknown software exception" (0x80000003) ist in der Anwendung an der Stelle 0x77f65a58 aufgetreten. Klicken sie auf "Ok", um das Programm zu beenden. Klicken sie auf "Abbrechen", um das Programm zu debuggen. Woran kann das liegen ? Nur an den beiden zeilen ? O.o' Zitieren
TDM Geschrieben 7. Juli 2005 Autor Geschrieben 7. Juli 2005 ok habs gefunden... if (!head -> Elem) { head = tmp; tmp -> ID = 0; tmp -> PPrev = NULL; /* Anfang auf NULL setzen */ } else { tmp -> PPrev = tail; /* Verlinkung zum Vorherigen */ tmp -> ID = (tmp -> PPrev -> ID + 1); tail -> PNext = tmp; /* Verlinkung zum Nächsten */ } Zitieren
Klotzkopp Geschrieben 7. Juli 2005 Geschrieben 7. Juli 2005 [b]//tmp -> ID = (tmp -> PPrev -> ID + 1);[/b] tmp -> PPrev = tail;[/code] Hier greifst du auf tmp -> PPrev zu, bevor du es setzt. Das machst du nämlich erst in der nächsten Zeile Übrigens, von Konstrukten wie [code]#define NEW_ADDRESS (Link) malloc(sizeof(sNode)) rate ich dringend ab. Schreib besser eine Funktion dafür. Und warum benutzt du eigentlich malloc und free, wenn du sowieso C++ erzeugst? Zitieren
TDM Geschrieben 7. Juli 2005 Autor Geschrieben 7. Juli 2005 Wieso C++ erzeugen ? der Compiler macht einfach nur Cpp dateien draus (man kann nur C++ Projekte erstellen O.o) sicher... da gibts auch irgentwo ne option aber egal... wollt halt mal nen "reinen" C code schreiben und das mit den PPrev hab ich ja schon mitgekriegt Zitieren
Klotzkopp Geschrieben 7. Juli 2005 Geschrieben 7. Juli 2005 Wieso C++ erzeugen ? der Compiler macht einfach nur Cpp dateien draus (man kann nur C++ Projekte erstellen O.o)MSVC? Der kann auch C. Er richtet sich da nach der Dateiendung. wollt halt mal nen "reinen" C code schreibenDein Code ist aber kein C. Du initialisierst globale Variablen mit nichtkonstanten Werten, du benutzt NULL für integrale Datentypen und an einigen Stellen fehlt "struct". Ein C-Compiler wird dir das um die Ohren hauen. Den cast in deinem NEW_ADDRESS-Makro brauchst du nur, weil das C++ ist. In C wäre der unnötig (und eventuell sogar gefährlich). Zitieren
TDM Geschrieben 7. Juli 2005 Autor Geschrieben 7. Juli 2005 Visual Studion .Net und ich dachte malloc ist da damit man eine neue freie Addresse findet O.o? da NULL so und so in der stdlib.h als #define NULL 0 definiert ist, ist es doch eigentlich egal ob ich nun 0 oder NULL nehme O.o' Wenn globale variablen konstante werte hätten, wären es konstanten und keine variablen Zitieren
Klotzkopp Geschrieben 7. Juli 2005 Geschrieben 7. Juli 2005 und ich dachte malloc ist da damit man eine neue freie Addresse findet O.o?"Frei" ist in dem Sinne keine Adresse. malloc "beschafft" Speicher vom Heap. Aber in C++ nimmt man dafür eigentlich new/delete, das hat den Vorteil, dass man Konstruktoren und Destruktoren verwenden kann. da NULL so und so in der stdlib.h als #define NULL 0 [/Code]definiert ist, ist es doch eigentlich egal ob ich nun 0 oder NULL nehme O.o'So sieht das #define für NULL aber nur in C++ aus. In C ist NULL ein void*-Nullzeiger. Das geht aber in C++ nicht, weil dort im Gegensatz zu C ein void* nicht implizit in jeden anderen Zeigertyp konvertierbar ist. Wenn globale variablen konstante werte hätten, wären es konstanten und keine variablenIn C darfst du globale Variablen nur mit Konstanten [i]initialisieren[/i], d.h. du kannst z.B. nicht mit dem Rückgabewert von malloc initialisieren. Das geht nur in C++. Zitieren
TDM Geschrieben 7. Juli 2005 Autor Geschrieben 7. Juli 2005 also wär dann das define #define NULL void*0x00000000 oder wie ? aber die stdlib ist doch für c programme O.o Zitieren
Klotzkopp Geschrieben 7. Juli 2005 Geschrieben 7. Juli 2005 also wär dann das define #define NULL void*0x00000000 oder wie ?In meiner stdlib.h steht: #ifndef NULL #ifdef __cplusplus #define NULL 0 #else #define NULL ((void *)0) #endif[/code] aber die stdlib ist doch für c programme O.oSie ist aber auch Bestandteil von C++. Der Header heißt zwar im C++-Standard <cstdlib>, aber der C-Header funktioniert unter MSVC auch noch. Zitieren
TDM Geschrieben 7. Juli 2005 Autor Geschrieben 7. Juli 2005 ok, hast mich überzeugt... btw: was ist der unterschied zwischen #ifndef und if !defined() ? Zitieren
Klotzkopp Geschrieben 7. Juli 2005 Geschrieben 7. Juli 2005 was ist der unterschied zwischen #ifndef und if !defined() ?Kein Unterschied, das ist gleichbedeutend. Zitieren
TDM Geschrieben 8. Juli 2005 Autor Geschrieben 8. Juli 2005 erm... mir ist grad wieder eingefallen warum ich NULL genommen hatte... Wenn da steht "Aufträge" und man "nur" Zahlen eingibt ist das bissl doof oder ? hatte mir am anfangen überlegt ob ich vielleicht auf strings umsteig (wollte das halt nur anfangs mit zahlen probieren) Zitieren
GrEnE Geschrieben 8. Juli 2005 Geschrieben 8. Juli 2005 ok, hast mich überzeugt... btw: was ist der Unterschied zwischen #ifndef und if !defined() ? Prinzipiell schon, aber einen kleinen unterschied gibt es, oder? Ich meine, wenn man mehrere 'defines' prüfen will, kenne ich nur if !defined(BLA) && !defined(BLA_2) da geht es doch garnicht mit '#ifndef' oder irre ich mich jetzt total. 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.