Leeres Element im Container
-
Hey Leute,
wie der Titel schon sagt ist mein Problem ein leerer Eintrag im Container. Mein Programm liest mittels einer Whileschleife eine art tabellenform aus, dabei ist für mich jedoch nur der eine eintrag relevant, deshal liest es schrittweise bis an diese stelle und legt das ausgelesene in den Container. Jedoch sehe ich beim Debuggen, dass da ein leerer eintrag entsteht wenn die datei zu ende ist. Könnt ihr mir sagen wie ich das umgehen kann ? oder ob es da eine bessere lösung gibt?vector<string> gesamtT(20); while(!datei.eof()) { datei.get(eingelesen,100,'|'); cout <<eingelesen; datei.get(eingelesen,2); cout<<eingelesen; datei.get(eingelesen,100,'|'); cout <<eingelesen; datei.get(eingelesen,2); cout<<eingelesen; datei.get(eingelesen,100,'|'); cout <<eingelesen; datei.get(eingelesen,2); cout<<eingelesen; datei.get(eingelesen,100,'|'); cout <<eingelesen; datei.get(eingelesen,2); cout<<eingelesen; datei.get(eingelesen,100,'|'); cout<<eingelesen; if(i>19) { gesamtT.push_back(eingelesen); } else { gesamtT[i]=eingelesen; } datei.getline(eingelesen,100); cout<<eingelesen<<endl; ++i; }wäre auch hilfreich wenn ihr mir den Vorgang erläutern könntet warum die schleife dennoch etwas leeres einliest obwohl es doch eigentlich abbrechen sollte wenn das dateiende erreicht ist

Danke schonmal
-
Logik falschrum (Warum macht das jeder so? Gibt es da draußen irgendein total falsches Anfägnerbuch, das jeder liest? Stimmt, das gibt es. Bist du ein "C++ von A bis Z"-Opfer?). eof wird wahr, nachdem du über das Ende hinweg gelesen hast, nicht wenn du vor dem Ende stehst. Daher hast du hier über das Ende gelesen, Mist erhalten, den Mist abgespeichert und dann erst die Schleife abgebrochen. Du müsstest aber erst lesen, dann prüfen ob richtig gelesen wurde und dann gegebenenfalls abspeichern.
Bei deiner Schreibweise ist das natürlich ein bisschen umständlich, da du nach dem letzten Lesen prüfen musst, ob der Stream noch gut ist (und dann prüf doch gleich alles, anstatt nur eof, du willst schließlich alle Fehler abfangen). Besser geht es, wenn du für deinen Datensatz einen eigenen Leseoperator definierst, dann könntest du schreiben:
datansatz data; while ((datei >> data).good()) // Der Leseoperator sollte den Stream selbst zurückliefern speichere(data);Oder kurz durch implizite Umwandlung des Streams in einen bool'schen Ausdruck:
datansatz data; while (datei >> data) // Der Stream liefert 0 bei fail(), sonst etwas ungleich 0 speichere(data);Oder damit man den datensatz schön lokal hat:
for (datensatz data; datei >> data; speichere(data));
-
ja ich hab das so mit nem buch gelernt, jedoch heißt meins "Jetzt lerne ich C++ Das komplette starterkit für den einfachen einstieg in die Programmierung" von Dirkl Louis ^^ .
So nun zum Problem, könntest du mir genauer erklären wie das mit dem leseopertator funktioniert? denn wenn ich das so eingeben wie du bekomm ich nur fehlermeldung das irgendwo n semikolon fehlt, was aber nicht fer fall ist.
Denn wie du sicherlich gemerkt hast bin ich noch in der lernphase.^^
-
if((i>19)&&(!datei.eof())) { gesamtT.push_back(eingelesen); } else if(!datei.eof()) { gesamtT[i]=eingelesen; }Ahhh....okay nach etwa zwanzigmal lesen deiner antwort hab ich nun kapiert wie ichs machen kann, da du aber meintest dass das falsch ist und ich mich mit erlernen von c++ ja auf mein Studium vorbereiten möchte und mir keinen schlechten Stil angewöhnen möchte könntest du mir vlt. nochn Tipp geben oder ein Buch empfehlen oder irgendwas
?Danke erstmal für deine Hilfe

Lg Sc0rpe
-
Di übliche Technik wäre, wie schon angedeutet, den Operator >> mit istream und deiner Klasse zu überladen. Operatorüberladung kann man googlen, mach noch
Google: c++ overload stream operators
draus und du findest auch das was ich mit den Streams meine:class example { int a, b; friend std::istream &operator>>(std::istream &in, example &ex) { return in >> ex.a >> ex.b; } };Hier geben wir fein hübsch die Referenz auf den Stream selber zurück, genau so wie es (fast) alle Lesefunktionen der Standardbibliothek aus gutem Grund machen. Daher kann man auch so hübsch
return in >> ex.a;schreiben anstatt gleichbedeutend aber länger:in >> ex.a; return in;Denk dir Operatorüberladung als ganz normale Funktion mit komischem Namen. Der einzige Unterschied zu normalen Funktionen ist, dass man sie anstatt
mitoperator>>(stream, ex);auch mit der schöneren und konsistenteren, aber gleichbedeutenden, Schreibweisestream >> ex;aufrufen kann. Das erste kann man aber auch!Dann macht man eine Schleife wie in meiner ersten Antwort schon beschrieben, die so lange läuft, wie der Fehlerstatus des Streams nicht gesetzt ist. Ein Objekt wird nur dann abgespeichert, wenn das Lesen auch erfolgreich war, was man erreicht, indem man den Lesevorgang in die Schleifenbedingung packt und das Abspeichern in den Schleifenkörper. Ich habe dir oben schon erklärt wie man das kompakt als for-Schleife schreiben kann, aber ich benutze mal das anfängerfreundlichere while:
std::vector<example> examples; example ex; while(datei >> ex) // Der obige Operator, liefert den Dateistream selber zurück. Ging das Lesen gut, wird dieser zu true, ansonsten zu false examples.push_back(ex); // Wenn es gut ging, abspeichernAlles in allem, noch mit einem Ausgabeoperator der Symmetrie wegen:
#include <iostream> #include <sstream> #include <vector> class example { int a, b; friend std::istream &operator>>(std::istream &in, example &ex) { return in >> ex.a >> ex.b; } friend std::ostream &operator<<(std::ostream &out, const example &ex) { return out << ex.a << ' ' << ex.b; } }; int main() { std::stringstream datei("1 2 3 4 5 6 7 8 9 0"); std::vector<example> examples; for(example ex; datei >> ex; examples.push_back(ex)); std::cout << "Gelesene Wertepaare:\n"; for (std::vector<example>::iterator it = examples.begin(), end = examples.end(); it != end; ++it) std::cout << *it << '\n'; }Hier nochmal mit den gleichen Sprachmitteln die Schleife in der Form wie du sie hattest:
int main() { std::stringstream datei("1 2 3 4 5 6 7 8 9 0\n"); // Hier habe ich den letzten Wert mit einem Zeilenumbruch abgewschlossen std::vector<example> examples; while (!datei.eof()) { example ex; datei >> ex; examples.push_back(ex); } std::cout << "Gelesene Wertepaare:\n"; for (std::vector<example>::iterator it = examples.begin(), end = examples.end(); it != end; ++it) std::cout << *it << '\n'; }Beobachte, wie nun der letzte Wert doppelt eingefügt wird, wie ich oben erklärt habe. Dies passiert nur, wenn auf den letzten Wert noch irgendetwas folgt, wie hier der Zeilenumbruch. Was aber ziemlich normal ist in einer Datei, dass diese auf einen Zeilenumbruch endet. Erklärung warum das so ist, findest du in meiner ersten Antwort.
Und noch etwas wichtiges:
Besorg dir ein gutes Buch: Lieber nichts lernen, als schlecht lernen! Denn etwas falsch gelerntes vergisst man so leicht nicht. Es wird zu schlechten Angewohnheiten, die man nicht mehr los wird. Siehe zweiter Link in meiner Signatur.
-

Vielen Dank für die nette, schnelle und ausführliche Hilfe

Ich Liebe diese Forum
Lg Sc0rpeThema kann geschlossen werden
