Anfängerproblem - Lesefunktion gibt falschen Wert zurück
-
Hi Expertz

Ich wollte vor kurzem eine Funktion schreiben, welche mir den wert einer (Text)Datei mit einem Befehl ausgibt. Das habe ich auch geschafft (-> es wird zumindest mal Compiliert
), nur leider gibt mir die Funktion blöderweise einen falschen Wert zurück
. Ich will das Programm so einfach wie möglich halten (vom quelltext her), auch wenn das bedeuten sollte, dass es dann insgesamt etwas langsamer wird, ich bin mir auch bewusst, dass es andere, lange Lösungen gibt, die besser laufen würden, will aber keine 100 Zeilen, die ich auf keinem Auge blicke, nur wegen dieser kleinen Funktion in meinem Quelltext haben... Vielleicht könnt ihr mir ja helfen. Im voraus schon mal vielen Dank 
#include <iostream> #include <fstream> #include <string> using namespace std; template<class T> unsigned char lese(T var, char *lese) { ifstream datei_l; datei_l.open(lese, ios::in|ios::binary); if(!datei_l) { cerr << datei_l << " Error" << endl; return 0; } //datei_l.getline(var, 1); -> Geht nicht, weil ...? //datei_l >> var; -> Geht nicht, weil ...? //for (int i=1; i < datei_l.size(); ++i) {datei_l >> var[i];} -> Geht nicht, weil "ifstream hat keine funkt. namens ".size()"" datei_l.read(reinterpret_cast<char*>(&var), sizeof(var)); //-> Geht nicht, weil var ein zeiger ist? (wegen sizeof()??) } int main() { char einlesen[100]; //string einlesen; -> gedacht für Befehl Z.18 "for (int i=1; i < datei_l.size(); ++i) {datei_l >> var[i];}" char quelle[20]; cout << "Quelle: "; cin >> quelle; lese(einlesen, quelle); cout << "datei: " << einlesen << endl; //for (int i=0; i < einlesen.size(); ++i) {cout << einlesen[i];} (-> ausgabe für "einlesen" (wenn "einlesen" ein string wäre)) system("pause"); }
-
Zunächst solltest Du uns noch verraten, was in der Datei steht. Ist es ein binäres Abbild eines Speichers oder etwas was auch ein Mensch mit Hilfe eines Texteditors lesen kann?
Bedenke, dass ein Ausdruck wie 'datei_1 >> var' und 'datei_1.read( &var, .. )' gänzlich unterschiedliche Dinge tun.
:xmas2: Werner
-
oh sry
Das Programm sollte zunächst einmal normalen Text, vom "Mensch" geschrieben einlesen können, (dann brauche ich wahrscheinlich auch kein ios::binary, oder?)
-
Nein, das ios::binary bzw. ios_base::binary benötigst Du nicht.
Wenn es sich um eine 'lesbare Datei' handelt, so ist 'datei_1 >> var' die richtige Wahl. Dein Template könnte etwa so aussehen:template<class T> bool lese( T& var, char *dateiname ) // T& liefert die Referenz; die Funktion liefert 'true' falls das Lesen ok ging { ifstream datei_l(dateiname); if(!datei_l.is_open()) { cerr << datei_l << " Error" << endl; return false; } datei_l >> var; // genau so sollte es gehen // datei_l.read(reinterpret_cast<char*>(&var), sizeof(var)); // geht nicht, da die Datei lesbaren Text enthält und kein Speicherabbild if( datei_1 ) return true; return false; }Und der Aufruf:
int main() { // char einlesen[100]; string ist immer besser als char[] string einlesen; string quelle; cout << "Quelle: "; cin >> quelle; if( lese(einlesen, quelle) ) cout << "datei: " << einlesen << endl; //for (int i=0; i < einlesen.size(); ++i) {cout << einlesen[i];} (-> ausgabe für "einlesen" (wenn "einlesen" ein string wäre)) system("pause"); }:xmas2: Werner
-
Ah, mein Profil geht wieder (-> Ich bin fast_schon_noob)
Vielen Dank für die Mühe, Werner Salomon, leider ist das Problem so noch immer nicht gelöst,
Fehlermeldung des Compilers:"31 C:\Dokumente(...) cannot convert `std::string' to `char' for argument `2' to `bool lese(T&, char*) [with T = std::string]' "*
wenn ich in Z.7 string statt char einsetze, kommt das gleiche heraus, wenn ich den Zeiger bei "Dateiname"(Z.7) auch noch entferne,
Fehlermeldung:"31 C:\Dokumente (...) instantiated from here".Trotzdem, nice Try
-
Einige Anmerkungen zum Code von Werner:
Werner Salomon schrieb:
template<class T> // Es heißt „lies“, nicht „lese“. // 'string' statt 'char*' bool lies(T& var, string const& dateiname) { ifstream datei_l(dateiname.c_str()); // Da wir Strings verwenden … if(!datei_l.is_open()) { cerr << datei_l << " Error" << endl; return false; } datei_l >> var; // genau so sollte es gehen // Was soll denn folgender Code? // if( datei_1 ) // return true; //return false; // Besser: return datei_l.good(); }Außerdem finde ich by-ref-out-Parameter immer ein wenig mittelmäßig furchtbar. Parameter haben gefälligst Eingabeparameter zu sein, die Ausgabe erledigt der Rückgabwert. Man kann ja ein 'std::pair' zurückgeben.
-
AAHHH! Jetzt lässt es sich kompilieren
. Stimmt, das mit dem ".c_str()" hätte mir auch auffallen müssen. Danke Konrad Rudolph!
EDIT1: Wäre es eigentlich möglich jetzt eine ganze Zeile einzulesen, also dass man nur noch schreiben muss: lese(var, quelle, 3); und man bekommt den wert von Zeile 3 in eine Variabe übergeben?
EDIT2:// Es heißt „lies“, nicht „lese“.
Die Funktion "lese" sollte schon "lese" heißen und nicht "lies" (ich kanns mir so besser merken);)
-
double *T schrieb:
Vielen Dank für die Mühe, Werner Salomon, leider ist das Problem so noch immer nicht gelöst,
Fehlermeldung des Compilers:"31 C:\Dokumente(...) cannot convert `std::string' to `char' for argument `2' to `bool lese(T&, char*) [with T = std::string]' "*stimmt - das kommt davon, wenn man den geposteten Code vorher nicht selber übersetzt.
double *T schrieb:
AAHHH! Jetzt lässt es sich kompilieren
. Stimmt, das mit dem ".c_str()" hätte mir auch auffallen müssen. Danke Konrad Rudolph!Ja so isses richtig.
Konrad Rudolph schrieb:
Einige Anmerkungen zum Code von Werner:
Werner Salomon schrieb:
// Was soll denn folgender Code? // if( datei_1 ) // return true; //return false; // Besser: return datei_l.good(); }Das 'return datei_l.good();' ist schlicht falsch. Korrekt wäre
return !datei_l.fail();oder
return bool( datei_l );was dasselbe ist und das wiederum ist funktional genau der gleiche Code wie am Anfang. Und ich hätte in meinem Code geschrieben
return bool( datei_l >> var );bzw. die Funktion 'lese' würde es so gar nicht geben ... aber das ist eine andere Geschichte.
Der Unterschied zwischen good() und !fail() liegt im EOF-bit. Ist dies gesetzt, so ist good()==false. Das heißt aber nicht, das ein vorher durchgeführter Leseversuch schiefgegangen ist, sondern zunächst nur, dass das Lesen bei EOF aufgehört hat, was völlig ok sein kann. Wenn z.B. außer dem interessierenden Wert nichts in der Datei steht.
Konrad Rudolph schrieb:
Außerdem finde ich by-ref-out-Parameter immer ein wenig mittelmäßig furchtbar. Parameter haben gefälligst Eingabeparameter zu sein, die Ausgabe erledigt der Rückgabwert. Man kann ja ein 'std::pair' zurückgeben.
.. bin ich gänzlich Deiner Meinung; nur ist es immer schwierig, bei solchem newbie-code das richtige Mass der Antwort zu finden.
:xmas2: Werner
-
Pff gibt soviele Möglichkeiten (operator void*, !operator!, fail, usw.) ... und
if(!datei_l.is_open())kann auch durch
if (!datei)ersetz werden ...
template<class T> bool read(std::string const& file_name, T& data) { std::ifstream file_stream(file_name.c_str()); return (!file_stream ? false : !!(file_stream >> data)); }Aber das nur für die, die auf nen bissel komischen code stehen

-
(D)Evil_loggedoff schrieb:
template<class T> bool read(std::string const& file_name, T& data) { std::ifstream file_stream(file_name.c_str()); return (!file_stream ? false : !!(file_stream >> data)); }Aah, dann hättest Du die letzte Zeile auch gleich richtig schreiben können (Achtung, ich benutze 'not' statt '!', ändert aber nix):
return not (not file_stream or not (file_stream >> data));
-
doch ändert was
Du nutzt operator void*, ich operator! 
-
(D)Evil schrieb:
doch ändert was
Du nutzt operator void*, ich operator! 
Nein, ich benutze 'operator not', das ist dasselbe wie 'operator !'. '!' == 'not'.
So, ich gehe jetzt schlafen.
-
Ah sorry hab übersehen, dass davor noch ein not stand ... sonst wäre der Rückgabewert ja falsch
Okay hast recht ^^