Probleme mit Datei E/A
-
Hallo
Ich hab vor für ein Spiel eine Bestenliste zu programmieren, und habe dafür mal ne Klasse geschrieben. Das problem ist nur dass wenn im Konstruktor, bzw im Destruktor die liste von ner datei gelesen, bzw. in sie geschrieben wird fehler auftreten. Macht sich in soweit bemerkbar dass nicht das richtige gelesn, bzw geschrieben wird.
Hier mal die relevaten code-schnipsel:
aus dem Konstruktor:
ifstream in(filename.c_str(), ios::binary); if(in) { for(int i = 0; i < 100; i++) { in.read((char *)&liste[i], sizeof liste[i]); cout << liste[i].punkte << endl; } }aus dem Destruktor:
ofstream out(filename.c_str(), ios::binary); for(int i = 0; i < 100; i++) { out.write((char *)&liste[i], sizeof liste[i]); } out.close();das array liste[100] ist ein Objekt volgender Struktur. Das Array ist in der klasse Private:
struct record { string name; int punkte; };Wenn mir jetzt einer Verraten könnte warum das nicht so geht wie ich mir das Vorstelle wäre ich wieder ein schritt weiter.
Manuel
-
cout.read und cout.write sind etwas zweifelhafte Funktionen - es kann gut gehen, muss aber nicht. 'int' ist oft kein Problem, aber sowas wie Zeiger schon und damit auch die Klasse 'std::string'. schreib einfach:
in >> liste[i].name >> liste[i].punkte;
und
out << liste[i].name << '\n' << liste[i].punkte << '\n';Hinzu kommt, dass read/write nicht gerade plattformunabhängig sind, op<< und op>> aber schon eher.
Grüße
FuxPS: wenn der Name auch Leerzeichen enthält, ist std::getline(out,liste[i].name) besser.
-
So wie du es beschrieben hast geht es, aber die Lösung gefällt mir irgendwie nicht.
Beim rumprobieren ist mir aufgefallen, dass wenn ich das nicht in einer Klassenfunktion sondern in einer normalen Funktion stehen habe ganz gut funktioniert: Bei Linux und Windoof. Nur eben nicht in der Klasse.
Hat das irgendein Grund?Manuel
-
struct record { string name; int punkte; };Wie groß ist denn sizeof record wenn name = "Hallo" und wenn name = "Hallo Welt" ist ?!?
Wie wärs mit nem op<< und op>> für record ? Da hast Du dann auch alle Informationen wenn Du es denn unbedingt binär speichern willst...
-
sizeof hat bei mir auch Probleme gemacht sobald der Datensatz aus verschiedenen Datentypen zusammengesetzt war. Ich fülle seitdem Strings immer mit Leerzeichen auf Solllänge auf. Datensatzbreite kann dann errechnet werden, da Speicherbedarf der Datentypen bekannt ist. Auch ein direkter Zugriff auf die Datensätze (gehe zu Satz x) ist nur bei konstanter Länge aller Datensätze möglich.
-
Hallo,
es geht nicht darum, ob dir meine Lösung gefällt oder nicht, dein Lösungsansatz ist schlicht weg falsch (read/write funktioniert mit deiner Struktur einfach nicht) und ich hab versucht einen anderen Weg zu zeigen. Ich kann ja verstehen, dass du es auf "deine Art" machen willst, aber wenn der Ansatz falsch ist, wird es recht schwer. Egal wie du es lösen willst, du musst 'name' und 'punkte' einzeln abspeichern, wobei read/write bei 'name' nicht funktioniert.
Beim rumprobieren ist mir aufgefallen, dass wenn ich das nicht in einer Klassenfunktion sondern in einer normalen Funktion stehen habe ganz gut funktioniert: Bei Linux und Windoof. Nur eben nicht in der Klasse.
Hat das irgendein Grund?Wenn der Programmcode sonst gleich ist, dürfte das nicht passieren.
Grüße
Fux
-
Man kann schon read und write dafür benutzen.
operatoren für die stuct überladen und in diesem das binärspeichern übernehmen. Nur ist die Frage ob man das so wirlich machen will ?!
Mein Tip wäre: Schreibe mal einen op<< und op>> für die Struktur. Dann kanste es sehr einfach weiterverarbeiten. Du Arbeitest dann wie Fux sagte mit << . Nur wird dann aus Deiner Struktur ein Datentyp der intern das schreiben übernimmt. Dort würde ich dann ein int speichern das die Länge des Strings angibt (der kann das so lange sein wie er will) und danach die Highscore.
Das solltest Du dann lesen und schreiben können wie Du willst.
Ich persönlich würde den op<< op>> überladen um den String in einer Zeile speichern zu können und mit getline wieder auszulesen. In der nächsten Zeile die Score...
-
@Fux
Ja es war ansonsten so ziemlich der gleiche code, um net zu sagen fast der selbe@Knuddlbar
Überladene Operatoren....
und das als C++ Anfänger ?!
Manuel
-
allesbelegt schrieb:
und das als C++ Anfänger ?!

Manuelread und write als Anfänger ?!
Na, willst nun Anfänger bleiben oder was gegen tun ?

Hier mal ein wenig was zum Spielen.
(Ich weiß nicht genau wie man das Problem mit der Zahl und den String am elegantesten löst....)
#include <iostream> #include <string> // FÜr Beispiele #include <vector> #include <fstream> #include <algorithm> #include <iterator> using namespace std; struct record { string name; int punkte; }; std::ostream & operator<<(std::ostream & out,const record & rec) { out<<rec.punkte<<' '; // Leerzeichen schreiben. Wenn Du sonst 12 Punkte hast und der Name 11Evil ist // Wäre das eingelesene falsch out<<rec.name<<'\n'; return out; } std::istream & operator>>(std::istream & in,record & rec) { in>>rec.punkte; in.get(); // Das Leerzeichen wegwerfen (bzw. das Trennzeichen) getline(in,rec.name); // Und den rest der Zeile für den Namen verwenden return in; } void tryOne() { // Beispielhandling für eigene lese Routinen std::vector<record> recvec; record temp; cin.clear(); temp.name = "Hallo"; temp.punkte = 12; recvec.push_back(temp); temp.name = "Hallo2"; temp.punkte = 13; recvec.push_back(temp); temp.name = "Hallo3"; temp.punkte = 14; recvec.push_back(temp); cout<<recvec[0]; cout<<recvec[1]; cout<<recvec[2]; fstream file("t:\\test.txt",ios::out); file<<recvec[0]; file<<recvec[1]; file<<recvec[2]; file.close(); file.open("t:\\test.txt",ios::in); file>>temp; cout<<temp; file>>temp; cout<<temp; file>>temp; cout<<temp; } void trytwo() { // Details hab ich im letzten Beitrag von // http://c-plusplus.net/forum/viewtopic.php?t=39470 // erklärt std::vector<record> recvec; record temp; cout<<"Eingabesyntax:\n Punkt Text\n Zwischen den Punkten und dem Textein leerzeichen einfügen!\nBeenden mit einem Buchstaben am Anfang\n\n"; while(cin>>temp) { recvec.push_back(temp); } fstream file("T:\\Test.txt",ios::out); copy(recvec.begin(),recvec.end(),ostream_iterator<record>(file,"\n")); file.close(); recvec.clear(); file.open("T:\\Test.txt",ios::in); istream_iterator<record> beg(file); istream_iterator<record> end; copy(beg,end,back_inserter(recvec)); copy(recvec.begin(),recvec.end(),ostream_iterator<record>(cout,"")); } int main(int argc, char * argv[]) { tryOne(); cout<<"Und nun trytwo\n\n"; trytwo(); return 0; }
-
ahmm..
ich glaub ich nehm dann doch die lösung von Fux

Manuel
-
Na, wer sich das nich mal anschaut wird immer davor zurückschrecken.
Das meiste ist nur ein Beispiel wie es verwendet wird.
std::ostream & operator<<(std::ostream & out,const record & rec) { out<<rec.punkte<<' '; // Leerzeichen schreiben. Wenn Du sonst 12 Punkte hast und der Name 11Evil ist // Wäre das eingelesene falsch out<<rec.name<<'\n'; return out; } std::istream & operator>>(std::istream & in,record & rec) { in>>rec.punkte; in.get(); // Das Leerzeichen wegwerfen (bzw. das Trennzeichen) getline(in,rec.name); // Und den rest der Zeile für den Namen verwenden return in; }Das hier ist das Geheimnis um record auch mit << und >> verwenden zu können.
und das als C++ Anfänger ?!

Aber wennst Dir das Beispiel nich anschauen magst...
-
Warum schauen solche sachen bei mir immer erst auf den dritten blick einfach aus?
Oder ist es doch net soo einfach ..Kannst du mir mal die Zeile genauer erklären?
std::ostream & operator<<(std::ostream & out,const record & rec)Funktionieren tuts auf jeden Fall
Manuel