Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Toxic

Frischling

  • »Toxic« ist der Autor dieses Themas

Beiträge: 53

Wohnort: Niedersachsen

Beruf: Ingenieur

  • Private Nachricht senden

1

19.04.2009, 20:23

Fehler beim Speichern und Laden einer Struktur

Hallo, ich habe einen Fehler den ich mir nicht ganz erklären kann und hoffe auf die Hilfe eines Profis.

Folgendes, ich erweitere gerade das kleine SDL-Spiel aus dem Buch, abschließend ist jetzt eine Highscoretabelle dran dessen Werte natürlich auch gespeichert werden sollen. Die Werte befinden sich dabei in einer Struktur und es handelt sich jeweils um ein int-Array und um ein char-Array.
Hinsichtlich des int-Arrays funktioniert alles einwandfrei, beim char-Array tritt ein Fehler auf welchen ich mir nicht so ganz erklären kann.

Führe ich das Programm so wie es unten steht aus, läuft alles einwandfrei. Habe ich bereits alles einmal gespeichert und verzichte durch auskommentieren darauf die Speicherfunktion aufzurufen, funktioniert auch alles ganz so wie gewünscht.

So und nun kommt das was ich ganz und gar nicht verstehe. Kommentiere ich die Zeilen in der Speicherfunktion aus in welcher in das char-Array geschrieben wird und rufe ich die Speicherfunktion so wie eben nicht auf, bekomme ich per cout die Meldung das die Datei nicht geöffnet werden konnte. Die Werte aus dem int-Array werden aber auch dann korrekt ausgegeben wenn ich sie auskommentiere.

Ich verstehe zum einen nicht warum die Werte aus einer Funktion die ich gar nicht aufrufe überhaupt einen Einfluss haben und zum anderen warum hiervon nur die char aber nicht die int-Variablen betroffen sind.

Ich habe mir die Mühe gemacht das ganze in ein lauffähiges kleines Programm zu packen, der Fehler tritt auch hier auf.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <iostream>
#include <fstream>

using namespace std; 

class CLoadSave
{

public:
    void Save(int Wert, int Pos);
    void Load(int *pWert, char* *pText); 

    struct m_sWerte 
    {
        int Points[10]; 
        char* Names[10][20]; 
    }; 

    
};

int main()
{
    CLoadSave *m_pLoadSave;
    m_pLoadSave = new CLoadSave;
    
    int Wert; 
    char* Text;

    //Speichervorgang aufrufen 

    m_pLoadSave->Save(1, 1);


    //Inhalt der Highscoretabelle ausgeben

    for(int i=0; i<=9; i++)
    { 
        Wert = i; 
        m_pLoadSave->Load(&Wert, &Text);
        cout << "Wert: "<<Wert<<endl; 
        cout << "Text: "<<Text<<endl; 
    }



    return 0; 
}

void CLoadSave::Save(int Wert, int Pos)
{
    m_sWerte Werte; 

    Werte.Points[0] = 6500;
    Werte.Points[1] = 18000;
    Werte.Points[2] = 19200;
    Werte.Points[3] = 31400;
    Werte.Points[4] = 38000;
    Werte.Points[5] = 50200;
    Werte.Points[6] = 61200;
    Werte.Points[7] = 88700;
    Werte.Points[8] = 96100;
    Werte.Points[9] = 142100;
    Werte.Points[10] = 10000000;

    Werte.Names[0][19] = "Name0";
    Werte.Names[1][19] = "Name1";
    Werte.Names[2][19] = "Name2";
    Werte.Names[3][19] = "Name3";
    Werte.Names[4][19] = "Name4";
    Werte.Names[5][19] = "Name5";
    Werte.Names[6][19] = "Name6";
    Werte.Names[7][19] = "Name7";
    Werte.Names[8][19] = "Name8";
    Werte.Names[9][19] = "Name9";
    
    //Datei zum Schreiben öffnen und Highscore hineinschreiben 

    ofstream Output("Highscore.hsc", ios::binary); 
    Output.write ((char*) &Werte, sizeof (Werte)); 

    //Datei schließen 

    Output.close(); 

}//Ende SaveHighscore


//LoadHighscore

//Aufgabe: Die Daten der Highscoretabelle in einer Datei speichern 

void CLoadSave::Load(int *pWert, char* *pText)
{
    m_sWerte Werte; 
    int Textzaehler = *pWert; 

    //Datei zum Schreiben öffnen und Highscore hineinschreiben 

    ifstream Input("Highscore.hsc",ios::binary); 
    
    //Überprüfung ob die Datei korrekt geladen werden konnte 

    if (Input == NULL)
    {
        cout << "Datei konnte nicht geoeffnet werden." << endl; 
    }else{
    Input.read ((char*) &Werte, sizeof (Werte)); 
    }
    
    *pWert = Werte.Points[*pWert];
    *pText = Werte.Names[Textzaehler][19];

    //Datei schließen 

    Input.close(); 
    
}//Ende Load


Diese Zeile auskommentieren:

C-/C++-Quelltext

1
//m_pLoadSave->Save(1, 1); 


Und das auch noch:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
/*
Werte.Names[0][19] = "Name0";
Werte.Names[1][19] = "Name1";
Werte.Names[2][19] = "Name2";
Werte.Names[3][19] = "Name3";
Werte.Names[4][19] = "Name4";
Werte.Names[5][19] = "Name5";
Werte.Names[6][19] = "Name6";
Werte.Names[7][19] = "Name7";
Werte.Names[8][19] = "Name8";
Werte.Names[9][19] = "Name9";
*/
Wenn Architekten ihre Häuser so bauen würden wie Programmierer ihre Programme, könnte ein einziger Specht ganze Städte zerstören !

K-Bal

Alter Hase

Beiträge: 703

Wohnort: Aachen

Beruf: Student (Elektrotechnik, Technische Informatik)

  • Private Nachricht senden

2

19.04.2009, 20:46

Moin!

Was mir erstmal aufgefallen ist:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct m_sWerte
{
     int Points[10];   
     
     char* Names[10][20];   
     
     // 200 char Pointer? Das müsste wohl eher so aussehen:

     
     char* Names[10];

     // Besser:


     std::string Names[10];
}; 


Dann noch diese Zeile:

C-/C++-Quelltext

1
2
Output.write ((char*) &Werte, sizeof (Werte)); 
// Gefährlich, weil die Länge der char* nicht konstant ist!


Gruß,
Marius

ph4nt0m

Frischling

Beiträge: 81

Beruf: Student

  • Private Nachricht senden

3

19.04.2009, 20:49

Ohne jetzt den Quelltext komplett durchgeschaut zu haben, kann ich dir zumindest schon einmal sagen, dass du einige Bereichsüberschreitungen in deinem Code hast:


C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
Werte.Points[0] = 6500; 
Werte.Points[1] = 18000; 
Werte.Points[2] = 19200; 
Werte.Points[3] = 31400; 
Werte.Points[4] = 38000; 
Werte.Points[5] = 50200; 
Werte.Points[6] = 61200; 
Werte.Points[7] = 88700; 
Werte.Points[8] = 96100; 
Werte.Points[9] = 142100; 
Werte.Points[10] = 10000000; // Hier ist ein Fehler


Dein "Points" Array kann nur 10 Elemente aufnehmen, also die Elemente mit den Indizes 0 bis 9.


C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
Werte.Names[0][19] = "Name0"; 
Werte.Names[1][19] = "Name1"; 
Werte.Names[2][19] = "Name2"; 
Werte.Names[3][19] = "Name3"; 
Werte.Names[4][19] = "Name4"; 
Werte.Names[5][19] = "Name5"; 
Werte.Names[6][19] = "Name6"; 
Werte.Names[7][19] = "Name7"; 
Werte.Names[8][19] = "Name8"; 
Werte.Names[9][19] = "Name9";


Hier verstehe ich außerdem nicht ganz, warum du als zweiten Index immer 19 angibst. Normalerweise dürfte das sowieso nicht funktionieren, da du einem char ein char[] zuweist.

Edit: Stimmt, der Typ ist nicht char, sondern char*, dennoch ist diese Zuweisung wahrscheinlich nicht so von dir gedacht. Du solltest strcpy oder (wie K-Bal schon sagte) tatsächlich std::string benutzen.
;)

4

19.04.2009, 20:57

Zitat von »"ph4nt0m"«

Normalerweise dürfte das sowieso nicht funktionieren, da du einem char ein char[] zuweist.

nein, einem char* einen const char*, das geht. //EDIT: ja, hab ph4nt0ms edit gesehen, aber erst nachm posten ;)
Und damit hätten wir auch den fehler: er speichert einen zeiger auf ein statisch allokiertes objekt. das geht solange gut, wie an derselben stelle in dem ladeneden programm dasselbe statisch allokierte objekt liegt, was nur solange der Fall ist, wie der entsprechende teil von Load() nicht auskommentiert wird. Auf gutdeutsch: so ist das blödsinn.
du musst die strings selbst speichern, nicht die zeiger darauf ;)

ph4nt0m

Frischling

Beiträge: 81

Beruf: Student

  • Private Nachricht senden

5

19.04.2009, 21:37

Ganz genau, also hast du was diese Problematik angeht zwei Möglichkeiten für deine Struktur:


C-/C++-Quelltext

1
2
3
4
5
struct m_sWerte 
{ 
    int Points[10];    
    char Names[10][20]; 
};


C-/C++-Quelltext

1
2
3
4
5
struct m_sWerte 
{ 
    int Points[10];    
    std::string Names[10]; 
};


Letztere Möglichkeit ist in C++ wohl die in den meisten Fällen empfehlenswerte Lösung, insbesondere da du so 10 Zeichenketten im Prinzip beliebiger Länge ablegen und diesen genau so Daten zuweisen kannst, wie du es in deinem ursprüngliche Code versucht hast.

Die erste Variante mit dem char-Array ist weniger flexibel, da deine Zeichenketten nur eine gewisse Maximallänge (in diesem Fall 19 Zeichen) haben dürfen. Außerdem musst du die Daten etwas "umständlicher" über strcpy oder besser strncpy in das char-Array hineinkopieren.
;)

K-Bal

Alter Hase

Beiträge: 703

Wohnort: Aachen

Beruf: Student (Elektrotechnik, Technische Informatik)

  • Private Nachricht senden

6

19.04.2009, 21:39

Zitat von »"ph4nt0m"«


Die erste Variante mit dem char-Array ist weniger flexibel, da deine Zeichenketten nur eine gewisse Maximallänge (in diesem Fall 19 Zeichen) haben dürfen.


Das dachte ich zuerst auch, aber das ist ja kein char-Array sondern ein char*-Array!

7

19.04.2009, 22:18

Mir gefällt auch

C-/C++-Quelltext

1
std::string Names[10];
nicht besonders. Ich finde, man sollte so wenig wie möglich auf Low-Level-Konstrukte (und dazu gehören rohe Arrays) zurückgreifen, da diese einfach sehr fehleranfällig sind.

Mögliche Alternativen - im Release-Modus ohne Overhead - wären:

C-/C++-Quelltext

1
2
std::tr1::array<std::string, 10> Names;
boost::array<std::string, 10> Names;
Im Debug-Modus hat man dann Assertions, die zum Beispiel Laufzeitüberschreitungen erkennen. Zudem hat man richtige Iteratoren und einige andere nützliche Funktionen wie size().

Toxic

Frischling

  • »Toxic« ist der Autor dieses Themas

Beiträge: 53

Wohnort: Niedersachsen

Beruf: Ingenieur

  • Private Nachricht senden

8

19.04.2009, 22:41

Vielen Dank an alle, ich konnte den Fehler einkreisen und nachdem ich es jetzt ein wenig abgeändert habe funktioniert es.
Es lag tatsächlich an diesem merkwürdigen char* Array, ich denke es reicht wenn ich erwähne das ich dieses lediglich so aufgrund einer Fehlermeldung verwendet habe die bei der Normalform char xy[10][10] gekommen ist. In einem anderen Forum hatte jemand einen ähnlichen Fehler und dort wurde das scheinbar so gelöst...

Für die Nachwelt hier einmal der abgeänderte Code.
Es stimmt natürlich was Nexus geschrieben hat, aber ich entscheide mich jetzt doch mal für den ,,Lowie-Code" weil ich einfach noch nicht so weit bin das andere wirklich zu durchschauen.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <iostream>
#include <fstream>
#include <string>

using namespace std; 

class CLoadSave
{

public:
    void Save(int Wert, int Pos);
    void Load(int *pWert, std::string *pText); 

    struct m_sWerte 
    {
        int Points[11]; 
        std::string Names[10];
    }; 

    
};

int main()
{
    CLoadSave *m_pLoadSave;
    m_pLoadSave = new CLoadSave;
    
    int Wert; 
    std::string Text;

    //Speichervorgang aufrufen 

    m_pLoadSave->Save(1, 1);


    //Inhalt der Highscoretabelle ausgeben

    for(int i=0; i<=9; i++)
    { 
        Wert = i; 
        m_pLoadSave->Load(&Wert, &Text);
        cout << "Wert: "<<Wert<<endl; 
        cout << "Text: "<<Text<<endl; 
    }



    return 0; 
}

void CLoadSave::Save(int Wert, int Pos)
{
    m_sWerte Werte; 

    Werte.Points[0] = 6500;
    Werte.Points[1] = 18000;
    Werte.Points[2] = 19200;
    Werte.Points[3] = 31400;
    Werte.Points[4] = 38000;
    Werte.Points[5] = 50200;
    Werte.Points[6] = 61200;
    Werte.Points[7] = 88700;
    Werte.Points[8] = 96100;
    Werte.Points[9] = 142100;
    Werte.Points[10] = 10000000;

    Werte.Names[0] = "Name0";
    Werte.Names[1] = "Name1";
    Werte.Names[2] = "Name2";
    Werte.Names[3] = "Name3";
    Werte.Names[4] = "Name4";
    Werte.Names[5] = "Name5";
    Werte.Names[6] = "Name6";
    Werte.Names[7] = "Name7";
    Werte.Names[8] = "Name8";
    Werte.Names[9] = "Name9";
    
    //Datei zum Schreiben öffnen und Highscore hineinschreiben 

    ofstream Output("Highscore.hsc", ios::binary); 
    Output.write ((char*) &Werte, sizeof (Werte)); 

    //Datei schließen 

    Output.close(); 

}//Ende SaveHighscore


//LoadHighscore

//Aufgabe: Die Daten der Highscoretabelle in einer Datei speichern 

void CLoadSave::Load(int *pWert, std::string *pText)
{
    m_sWerte Werte; 
    int Textzaehler = *pWert; 

    //Datei zum Schreiben öffnen und Highscore hineinschreiben 

    ifstream Input("Highscore.hsc",ios::binary); 
    
    //Überprüfung ob die Datei korrekt geladen werden konnte 

    if (Input == NULL)
    {
        cout << "Datei konnte nicht geoeffnet werden." << endl; 
    }else{
    Input.read ((char*) &Werte, sizeof (Werte)); 
    }
    
    *pWert = Werte.Points[*pWert];
    *pText = Werte.Names[Textzaehler];

    //Datei schließen 

    Input.close(); 
    
}//Ende Load


Ich denke ihr hättet euch alle dafür ein Bier verdient :) Da man das leider nicht per Mail verschicken kann werde ich die nächsten Tage mein fertiges Spiel hier reinstellen, dann habt ihr die Gelegenheit die Highscore-Liste mal in Aktion zu sehen. ;)
Wenn Architekten ihre Häuser so bauen würden wie Programmierer ihre Programme, könnte ein einziger Specht ganze Städte zerstören !

ph4nt0m

Frischling

Beiträge: 81

Beruf: Student

  • Private Nachricht senden

9

19.04.2009, 22:50

C-/C++-Quelltext

1
Werte.Points[10] = 10000000;

Dieser Fehler ist immer noch drin. Wenn du wirklich 11 statt 10 Werten speichern willst, musst du das Array auch mit einer entsprechenden Größe anlegen. Außerdem solltest du am besten noch das "using namespace std;" entfernen und stattdessen std::ofstream usw. verwenden.
;)

Toxic

Frischling

  • »Toxic« ist der Autor dieses Themas

Beiträge: 53

Wohnort: Niedersachsen

Beruf: Ingenieur

  • Private Nachricht senden

10

19.04.2009, 23:03

Ich weiss habe das mit dem Array jetzt eben behoben, bin eben auch auf den Fehler gestossen :)

Das mit dem std::ofstream gucke ich mir jetzt an.
Wenn Architekten ihre Häuser so bauen würden wie Programmierer ihre Programme, könnte ein einziger Specht ganze Städte zerstören !

Werbeanzeige