Fehler wegen Datei - Programm schließt sich nicht korrekt



  • Hallo,

    Ich habe ein dickes Problem. Es geht um ein Programm, das ich derzeit entwickle,
    der auch in der Lage ist Werte in eine Datei zu speichern. Nun es ist eigentlich
    kein richtiger Fehler; das Programm selbst läuft einwandfrei. Jedoch immer wenn
    ich in meinem Programm "3. Programm beenden" auswähle, stürzt es merkwürdiger
    Weise (!! aber erst beim 2ten Programmaufruf !!) ab und es öffnet sich ein
    Windows-Fenster mit folgendem Inhalt:

    Unbehandelte Ausnahme bei 0x770966ab in Zahlenraten.exe: 0xC0000005: Zugriffsverletzung beim Lesen an Position 0x01683f57.
    

    Ich arbeite mit fstream. Hier ist der ganze "Daten"-Code:

    #include <fstream>
    // Headerdateien
    #include "Datei.hpp"
    // Klassen
    #include "CSpieler.hpp"
    
    using namespace std;
    
    // Datei speichern
    //
    int DateiSpeichern (CSpieler &Spieler)
    {
    	// Datei speichern
    	ofstream Output ("DATA.zrt", ios::binary);
    	Output.write ((char*) &Spieler, sizeof (Spieler));
    	Output.close ();
    
    	return 0;
    
    } // Datei speichern
    
    // Datei laden
    //
    int DateiLaden (CSpieler &Spieler)
    {
    	// Datei laden
    	ifstream Input ("DATA.zrt", ios::binary);
    	Input.read ((char*) &Spieler, sizeof (Spieler));
    	Input.close ();
    
    	return 0;
    
    } // Datei laden
    
    // Datei laden oder erstellen
    //
    int DateiLadenErstellen (CSpieler &Spieler)
    {
    	// Datei öffnen
    	ifstream Input ("DATA.zrt", ios::binary);
    
    	// Überprüfen ob die Datei existiert
    	// Wenn ja, wird die Datei geladen
    	//
    	if (Input.is_open ())
    	{
    		// Datei laden
    		Input.read ((char*) &Spieler, sizeof (Spieler));
    		Input.close ();
    
    		// +1 Programmaufruf
    		Spieler.Plus1Programmaufruf ();
    
    		// Datei speichern
    		DateiSpeichern (Spieler);
    
    	} // Datei wird geladen
    
    	// Ansonsten wird die Datei erstellt
    	//
    	else
    	{
    		// Werte initialisieren
    		Spieler.WerteInitialisieren ();
    		Spieler.TitelInitialisieren ();
    
    		// Spielernamen eingeben
    		Spieler.SpielernamenEingeben ();
    
    		// Datei speichern
    		DateiSpeichern (Spieler);
    
    	} // Datei wird erstellt
    
    	return 0;
    
    } // Datei laden oder erstellen
    

    Ich hoffe, dass mir jemand helfen kann.



  • Dieser Thread wurde von Moderator/in Martin Richter aus dem Forum MFC (Visual C++) in das Forum C++ (auch C++0x) verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • Ich habe euch auch jetzt n Screenshot vom Windows-Fenster:
    Bild
    Ich finds komisch, denn i-wie öffnet sich auch eine andere Datei (xstring).
    Das sieht man auch auf'm Screenshot.

    Wenn euch das nicht weiterbringt kann ich euch noch die main zeigen.
    Aber da ist einfach irgendwie kein Fehler drinne:

    #include <iostream>
    #include <string>
    #include <windows.h>
    #include <cstdio>
    #include <ctime>
    #include <fstream>
    #include <conio.h>
    // Headerdateien
    #include "Time.hpp"
    #include "Weiter.hpp"
    #include "clear_screen.hpp"
    #include "Fehler.hpp"
    #include "Datei.hpp"
    // Klassen
    #include "CSpieler.hpp"
    
    using namespace std;
    #pragma comment (lib, "winmm.lib")
    
    // Optionen
    //
    int Optionen (CSpieler &Spieler);
    int DatenLoeschen (CSpieler &Spieler, short &Auswahl);
    void Credit ();
    
    // Hauptfunktion
    //
    int main (void)
    {
    	// Textfarbe Weiß einstellen
    	SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), 15);
    
    	// clear screen
    	clear ();
    
    	// Variablen und Instanzen
    	//
    	short Auswahl = 0;
    	CSpieler Spieler;
    
    	// Datei laden oder erstellen
    	DateiLadenErstellen (Spieler);
    
    	// Hauptmenü
    	//
    	while (Auswahl != 3)
    	{
    		// Titel
    		//
    		SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), 11);
    		cout << " ZAHLENRATEN " << endl;
    		SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), 15);
    		cout << "~~~~~~~~~~~~~" << endl;
    
    		// Navigation
    		//
    		cout << "1. Zahlenraten" << endl;
    		cout << "2. Optionen" << endl;
    		cout << "3. Programm beenden" << endl;
    		cout << "~~~~" << endl;
    		cout << "Deine Auswahl: ";
    		cin >> Auswahl;
    
    		// clear screen
    		clear ();
    
    		switch (Auswahl)
    		{
    			// Zahlenraten
    			//
    		case 1:
    			{
    				// Zahlenraten spielen
    				Spieler.Zahlenraten ();
    
    				// Datei speichern
    				DateiSpeichern (Spieler);
    
    			} break;
    
    			// Optionen
    			//
    		case 2:
    			{
    				// Optionen aufrufen
    				Optionen (Spieler);
    
    			} break;
    
    			// Programm beenden
    			//
    		case 3:
    			{
    
    			} break;
    
    			// Ansonsten Fehler
    			//
    		default:
    			{
    				Fehler ();
    				Auswahl = 0;
    			}
    
    		} // switch
    
    	} // while - Hauptmenü
    
    	return 0;
    
    } // Hauptfunktion
    
    // Optionen
    //
    int Optionen (CSpieler &Spieler)
    {
    	// Variablen
    	//
    	short Auswahl = 0;
    
    	// Optionen
    	//
    	while (Auswahl != 5)
    	{
    		// Daten laden
    		DateiLaden (Spieler);
    
    		// Titel
    		//
    		SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), 11);
    		cout << "  OPTIONEN  " << endl;
    		SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), 15);
    		cout << "~~~~~~~~~~~~" << endl;
    
    		// Navigation
    		//
    		cout << "1. Titel anzeigen" << endl;
    		cout << "2. Daten anzeigen" << endl;
    		cout << "3. Daten loeschen" << endl;
    		cout << "4. Credit anzeigen" << endl;
    		cout << "5. Zurueck zum Hauptmenue" << endl;
    		cout << "~~~~" << endl;
    		cout << "Deine Auswahl: ";
    		cin >> Auswahl;
    
    		// clear screen
    		clear ();
    
    		switch (Auswahl)
    		{
    			// Titel anzeigen
    			//
    		case 1:
    			{
    				Spieler.TitelAnzeigen ();
    
    			} break;
    
    			// Daten anzeigen
    			//
    		case 2:
    			{
    				Spieler.DatenAnzeigen ();
    
    			} break;
    
    			// Daten löschen
    			//
    		case 3:
    			{
    				DatenLoeschen (Spieler, Auswahl);
    
    			} break;
    
    			// Credit anzeigen
    			//
    		case 4:
    			{
    				Credit ();
    
    			} break;
    
    			// Zurück zum Hauptmenü
    			//
    		case 5:
    			{
    
    			} break;
    
    			// Ansonsten Fehler
    			//
    		default:
    			{
    				Fehler ();
    				Auswahl = 0;
    			}
    
    		} // switch
    
    	} // Optionen - while
    
    	return 0;
    
    } // Optionen
    
    // Daten löschen
    //
    int DatenLoeschen (CSpieler &Spieler, short &Auswahl)
    {
    	// Variablen
    	//
    	int t;
    	Auswahl = 0;
    
    	// Warnung: Resultat löschen?
    	//
    	do
    	{
    		// Titel
    		//
    		SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), 11);
    		cout << "SOLLEN ALLE DATEN UNWIDERRUFLICH GELOESCHT WERDEN?" << endl;
    		SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), 15);
    		cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << endl;
    
    		// Navigation
    		//
    		cout << "1. Ja, Daten loeschen" << endl;
    		cout << "2. Nein, Daten nicht loeschen" << endl;
    		cout << "~~~~" << endl;
    		cout << "Deine Auswahl: ";
    		cin >> Auswahl;
    
    		// clear screen
    		clear ();
    
    		switch (Auswahl)
    		{
    			// Ja, Daten löschen
    			//
    		case 1:
    			{
    				// Datei löschen
    				ifstream Input ("DATA.zrt", ios::binary);
    				Input.close ();
    				remove ("DATA.zrt");
    
    				// Werte initialisieren
    				Spieler.WerteInitialisieren ();
    
    				// Info
    				cout << "Daten wurden geloescht";
    
    				for (t=3; t>0; t--)
    				{
    					Time (1);
    					cout << ".";
    				}
    
    				// clear screen
    				clear ();
    
    				// Spielernamen eingeben
    				cin.ignore ();
    				Spieler.SpielernamenEingeben ();
    
    				// Datei speichern
    				DateiSpeichern (Spieler);
    
    			} break; // Ja, Daten löschen
    
    			// Nein, Daten nicht löschen
    			//
    		case 2:
    			{
    				// Info
    				cout << "Daten wurden nicht geloescht";
    
    				for (t=3; t<0; t--)
    				{
    					Time (1);
    					cout << ".";
    				}
    
    				// clear screen
    				clear ();
    
    			} break; // Nein, Daten nicht löschen
    
    			// Ansonsten Fehler
    			//
    		default:
    			{
    				Fehler ();
    				Auswahl = 0;
    			}
    
    		} // switch
    
    	} while (Auswahl != 1 && Auswahl != 2); // Warnung: Resultat löschen?
    
    	// Zurück zum Hauptmenü?
    	//
    	if (Auswahl == 1)
    		Auswahl = 5;
    	else
    		Auswahl = 0;
    
    	return 0;
    
    } // Daten löschen
    
    // Credit anzeigen
    //
    void Credit ()
    {
    	// Credit anzeigen
    	SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), 14);
    	cout << "============================================================\n";
    	cout << "============================================================\n";
    	cout << "============ ";
    	SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), 15);
    	cout << "PROGRAMMIERT MIT C++ VON MINISPIRI";
    	SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), 14);
    	cout << " ============\n";
    	cout << "============================================================\n";
    	cout << "============================================================\n\n\n\n\n\n";
    	SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), 15);
    
    	// Weiter
    	Weiter ();
    
    } // Credit anzeigen
    


  • Wie sieht denn die Klasse CSpieler aus? Du schreibst und liest sie ja binär, das darf man aber nur, wenn es ein POD (also im wesentlichen eine simple Struktur ohne Konstruktor usw. ist). Wahrscheinlich kracht es dann beim Beenden im Destruktor.



  • Bashar schrieb:

    Wie sieht denn die Klasse CSpieler aus? Du schreibst und liest sie ja binär, das darf man aber nur, wenn es ein POD (also im wesentlichen eine simple Struktur ohne Konstruktor usw. ist). Wahrscheinlich kracht es dann beim Beenden im Destruktor.

    Hallo,

    ich habe keinen Destruktor, nur eine simple normale Klasse:

    #include <iostream>
    #include "clear_screen.hpp"
    
    #ifndef CSPIELER_HPP
    #define CSPIELER_HPP
    
    class CSpieler
    {
    private:
    
    	// Membervariablen
    	//
    	char Spielername[100];
    	unsigned long Programmaufrufe;
    	unsigned long Gesamtpunkte;
    	unsigned long Highscore;
    	unsigned long ErreichterLevel;
    	unsigned long Versuche;
    	unsigned int AnzahlTitel;
    	std::string Titel[10];
    	std::string MomentanerTitel;
    
    public:
    
    	// Memberfunktionen
    	//
    
    	// Werte initialisieren
    	//
    	void WerteInitialisieren ()
    	{
    		for (int i=0; i<100; i++)
    			Spielername[i] = ' ';
    
    		Programmaufrufe = 1;
    		Gesamtpunkte = 0;
    		Highscore = 0;
    		ErreichterLevel = 0;
    		Versuche = 25;
    		AnzahlTitel = 0;
    		MomentanerTitel = "Kein Titel";
    	} // Werte initialisieren
    
    	// Titel initialisieren
    	//
    	void TitelInitialisieren ()
    	{
    		// Titel initialisieren
    		Titel[0] = "Anfaenger";
    		Titel[1] = "Amateur";
    		Titel[2] = "Fortgeschrittener";
    		Titel[3] = "Glueckspilz";
    		Titel[4] = "Wahrsager";
    		Titel[5] = "Champion";
    		Titel[6] = "Winner";
    		Titel[7] = "Meister";
    		Titel[8] = "Doktor Win";
    		Titel[9] = "Profi";
    	} // Titel initialisieren
    
    	// +1 Programmaufruf
    	//
    	void Plus1Programmaufruf ()
    	{
    		Programmaufrufe++;
    	} // +1 Programmaufruf
    
    	void SpielernamenEingeben ()
    	{
    		// Abfrage
    		std::cout << "Spielername: ";
    		std::cin.get (Spielername, 999);
    
    		// clear screen
    		clear ();
    	}
    
    	void TitelAnzeigen ();
    	void DatenAnzeigen ();
    
    	void Zahlenraten ();
    
    };
    
    #endif
    


  • Hallo

    Ist zwar etwas ins Blaue geraten, aber ich glaub dies liegt an diesen Variablen:

    std::string Titel[10];
        std::string MomentanerTitel;
    

    Zum einen, da er im Absturz in xstring steht. Zum anderen dir Bashar gesagt es dürfen nur einfache Strukturen benutzt werden, deine Klasse ist zwar "einfach", aber die String-Klasse nicht. Diese hat Konstruktor und Destruktor.

    Und nur nebenbei wäre es vllt bessere, wenn du die Daten in eine Struktur packst und dann auch nur diese wegspeicherst.

    MfG marco



  • Marc-O schrieb:

    Und nur nebenbei wäre es vllt bessere, wenn du die Daten in eine Struktur packst und dann auch nur diese wegspeicherst.

    ??
    genau das versucht er doch?
    oder meist du struct statt class? das macht keinen unterschied

    bb



  • Heißt das, dass ich keine Strings verwenden darf?



  • Genau, strings sind nur ein Gag des Standardisierungsgremiums 🙄 Nein es heißt, dass du dir bei nicht-POD-Typen was einfallen lassen musst und es nicht einfach byteweise in eine Datei schaufeln darfst. So ein String beinhaltet in der Regel einen Pointer auf die eigentlichen String-Daten. Wenn du jetzt das string-Objekt byteweise aus einer Datei liest, bekommst du ein Objekt mit so einem Pointer drin ... und der Pointer ist genau der gleiche wie als das Objekt in die Datei reingeschrieben wurde. Aber was liegt da, wo der Pointer hinzeigt? Ziemlich wahrscheinlich nicht die eigentlichen String-Daten, wo sollen die auch herkommen.


Anmelden zum Antworten