seekg springt weiter als es sollte
-
Hier ein Ausschnitt einer Funktion, die eine Bildschirmauflösung aus einer Textdatei ausliest:
for (int zahlpos = 0; zahlpos < 20; zahlpos++) { if (Aufloesung.get() != 'x') { AktuellesTextstueck[zahlpos] = Aufloesung.get(); printf(&AktuellesTextstueck[zahlpos]); printf("\n"); } else { AktuellesTextstueck[zahlpos] = '\0'; zahlpos = 20; } Aufloesung.clear(); Aufloesung.seekg(1, ios::cur); nZahl = Aufloesung.tellg(); printf("Position: "); printf(itoa(nZahl,Zahl,10));printf("\n"); }Die Auflösung steht folgendermaßen in der Textdatei:
screen resolution: 124x78
Vorher wird der Lesezeiger schon so gesetzt, dass er auf der "1" der 124 steht. (Ich weiß, die Auflösung ist quatsch, ist auch nur zum Testen da.
)Die erste Ausgabe von printf ist also 1. Nun soll in dieser for-Schleife der Lesezeiger mit seekg immer ein Zeichen weiter springen. Tut er aber nicht. Im Internet habe ich gelesen, dass ich einen cléar-Befehl davorsetzen soll, wie er auch dort steht, aber das ändert rein gar nichts. Hier die Ausgabe:
1
Position: 147
n
Position: 156
e
Position: 165
v
Position: 173
g
Position: 180
e
Position: 187
p
Position: 193etc.
Warum erzeugt:
Aufloesung.seekg(1, ios::cur);Keinen Sprung um ein Zeichen nach vorne?
-
1. Wieso verwendest du
printfstattstd::cout.printfist C und sollte in C++ mit grosser Vorsicht verwendet werden.
2. Wieso verwendest duitoa? Das ist kein Standard C++ und nicht einmal Standard C. Zudem ist die Verwendung hier völlig überflüssig. Wenn du schon printf benutzt, dann benutze es richtig:
printf("Position: %d\n", nZahl);
Oder gleich in C++:
std::cout << "Position: " << nZahl << std::endl;
3. Ich habe gar nicht erst getestet, was bei dir falsch sein könnte. Ich habe auch gar nicht genügend Informationen. Ich müsste auch zuerst ein eigenes kleines Progrämmchen schreiben, welches dies umsetzt. Allerdings habe ich auch dafür eigentlich zu wenig Informationen. Die meisten Typangaben und Vorgehensweisen fehlen.
4. Mit C++ könntest du dies allerdings wesentlich einfacher lösen. Hier mal ein simples Progrämmchen, welches die Eingabe einer Auflösung erwartet, also zum Beispiel "124x78":#include <iostream> int main() { int width; int heigth; if(!(std::cin >> width)) { std::cout << "couldn't read width" << std::endl; return 0; } if(std::cin.get() != 'x') { std::cout << "Didn't find x character" << std::endl; return 0; } if(!(std::cin >> heigth)) { std::cout << "couldn't read height" << std::endl; return 0; } std::cout << "success" << std::endl; return 0; }Nicht vergessen,
std::cinist einstd::istreamObjekt.
Beim Einlesen einer Zahl über ein std::istream Objekt, wird so lange gelesen, bis die Zahl nicht mehr in den Speicher passt, dann wird der Stream ungültig, oder es wird ein Zeichen gefunden, welches keine Ziffer ist. Beim ersten Einlesevorgang wird dies ausgenützt, damit es beim 'x' abbricht.
Jeder Lesevorgang gibt den Stream selber zurück und dieser kann auf Gültigkeit geprüft werden. Somit kann jeweils immer gleich geprüft werden, ob der Lesevorgang gültig war.Grüssli
-
Ich benutzte kein cout, weil ich SDL in dem Projekt eingebunden habe und iostream und SDL sich irgendwie nicht vertragen. Wie printf genau funktioniert weiß ich nicht, da muss ich zugeben, hab ich solange rumprobiert, bis es funktioniert hat.
Cin und <iostream> bringt mir leider überhaupt nichts, da ja eine Textdatei ausgelesen werden soll bzw. muss.
Die verwendeten Variablen sind die folgenden:
char AktuellesTextstueck[21]; char nZahl[4]; //Ist nur für meine printf-Bastelei da, sonst sinnlosIch hab mal die printf verschönert und ein wenig mehr Code:
//Der Anfang der Funktion #ifndef _FSTREAM_ #define _FSTREAM_ #include <fstream> #endif using namespace std; bool AufloesungLaden(int* Position, char AktuellesTextstueck[21], int* ScreenX, int* ScreenY) { ...Auswertungen, die die richtige Zeile suchen und den Lesezeiger auf die 1 der 124 setzen... //X-Zahl auslesen for (int zahlpos = 0; zahlpos < 20; zahlpos++) { if (Aufloesung.get() != 'x') { AktuellesTextstueck[zahlpos] = Aufloesung.get(); printf(&AktuellesTextstueck[zahlpos]); printf("\n"); } else { AktuellesTextstueck[zahlpos] = '\0'; zahlpos = 20; } Aufloesung.clear(); Aufloesung.seekg(1, ios::cur); nZahl = Aufloesung.tellg(); printf("Position: %d\n", nZahl); }Später benutze ich atoi, um die ausgelesenen Character in Zahlen umzuwandeln. Was soll ich denn sonst verwenden, wenn das kein Standard ist? Ich hab mal eine Umwandlung für vierstellige Arrays in Zahlen geschrieben und das waren aber 70 Zeilen. Warum sollte ich es mir umständlicher als nötig machen? Oder gibt es dafür noch eine andere Funktion?
-
Little Programmer schrieb:
Später benutze ich atoi, um die ausgelesenen Character in Zahlen umzuwandeln. Was soll ich denn sonst verwenden, wenn das kein Standard ist? Ich hab mal eine Umwandlung für vierstellige Arrays in Zahlen geschrieben und das waren aber 70 Zeilen. Warum sollte ich es mir umständlicher als nötig machen? Oder gibt es dafür noch eine andere Funktion?
Zum Beispiel
std::stringstream, schau mal bei www.cplusplus.com.
-
Danke, muss ich mich mal drin einarbeiten. Aber das war ja nicht mein eigentliches Problem, das ist nach wie vor unverändert. Hier mal die komplette Funktion, falls das endlich den Fehler offenbart. Die atois sind jetzt noch drin. Bitte einfach ignorieren im Moment. Erstmal zur Erklärung. Eine übergeordnete Funktion läd von Beginn der Datei an die ersten 20 Zeichen in AktuellesTextstueck[21] und gibt dies dann an die folgende Problemfunktion weiter. Anschließend werden wieder 20 Zeichen ausgelesen, diesmal aber vom zweiten Zeichen an. dies geht dann bis zum Ende der Datei. Die letzten 20 Zeichen sind Beschreibungstext für den Benutzer, da gibt es nichts mehr auszulesen. Das heißt jede dieser Funktionen wie die hier genannte wird einmal aufgerufen, während AktuellesTextstueck[21] gerade mit ihrem Suchtext beginnt. Ich weiß, dass ist eine miese Auslesefunktion, aber Hauptsache es funktioniert erstmal.
#ifndef _FSTREAM_ #define _FSTREAM_ #include <fstream> #endif using namespace std; bool AufloesungLaden(int* Position, char AktuellesTextstueck[21], int* ScreenX, int* ScreenY) { int Uebereinstimmung = 0; bool Funktioniert = false; char aufloesung[18] = {'s','c','r','e','e','n',' ','r','e','s','o','l','u','t','i','o','n',':'}; //Bildschirmauflösung auslesen for (int x = 0; x < 18; x++) { if (AktuellesTextstueck[x] == aufloesung[x]) { Uebereinstimmung++; } } if (Uebereinstimmung == 18) { //Variable leeren for (int x = 0; x < 20; x++) { AktuellesTextstueck[x] = '\0'; } //Bildschirmauflösung auslesen, dazu erst zurück, ein Feld hinter das 18te ifstream Aufloesung("config.txt", ios::in); Aufloesung.seekg((*Position + 17), ios::beg); char Zahl[4]; int nZahl; //Leerzeichen überspringen if (Aufloesung.get() == ' ') { while (Aufloesung.get() == ' ') { Aufloesung.seekg(1, ios::cur); } } //X-Zahl auslesen for (int zahlpos = 0; zahlpos < 20; zahlpos++) { if (Aufloesung.get() != 'x') { AktuellesTextstueck[zahlpos] = Aufloesung.get(); printf(&AktuellesTextstueck[zahlpos]); printf("\n"); } else { AktuellesTextstueck[zahlpos] = '\0'; zahlpos = 20; } Aufloesung.clear(); Aufloesung.seekg(1, ios::cur); nZahl = Aufloesung.tellg(); printf("Position: %d\n", nZahl); } //Text in Zahl umwandeln *ScreenX = atoi (AktuellesTextstueck); printf("ScreenX: %d\n", ScreenX); //Y-Zahl auslesen for (int zahlpos = 0; zahlpos < 20; zahlpos++) { if (Aufloesung.get() != 'x') { AktuellesTextstueck[zahlpos] = Aufloesung.get(); } else { AktuellesTextstueck[zahlpos] = '\0'; zahlpos = 20; } Aufloesung.seekg(1, ios::cur); } //Schließen Aufloesung.close(); //Text in Zahl umwandeln *ScreenY = atoi (AktuellesTextstueck); printf("ScreenY: %d\n", ScreenY); //Konfiguration erfolgreich geladen Funktioniert = true; printf("Aufloesung erfolgreich geladen.\n"); } return Funktioniert; }Nochmal zum Problem, das muss in Zeile 55 liegen. Die Funktion befindet sich in dieser for-Schleife auf der 1 folgenden Textes:
screen resolution: 124x78
Aber die Ausgabe der printfs gibt folgendes aus:
1
Position: 147
n
Position: 156
e
Position: 165
v
Position: 173
g
Position: 180
e
Position: 187
p
Position: 193Aus irgendeinem Grund geht der Lesezeiger nicht ein Zeichen weiter, sondern mehrere, das wiederspricht jeglicher Logik. Der Fehler kann eigentlich nur in Zeile 55 liegen, aber die ist ja ziemlich übersichtlich:
Aufloesung.seekg(1, ios::cur);Wie kann so etwas auftreten? Ich bin echt verwirrt.

Bitte, weiß denn niemand, wie so ein merkwürdiges Verhalten auftreten kann?

-
Wahrscheinlich benutzt du get falsch. Ich kann deinen Algorithmus nicht wirklich entwirren, aber mir scheint, du bist dir nicht bewusst, dass zweimal get() hintereinander nicht zweimal dasselbe Zeichen liefert, sondern dass jedesmal der Dateizeiger eine Position weiterrückt.
Das erklärt nicht, warum der Dateizeiger gleich 9 Zeichen hüpft, aber mehr als 1 Zeichen sollte es auf jeden Fall sein.
-
Little Programmer schrieb:
Ich benutzte kein cout, weil ich SDL in dem Projekt eingebunden habe und iostream und SDL sich irgendwie nicht vertragen.
Ehm, wie bitte? Könntest du dieses Problem etwas näher spezifizieren? Ein
std::coutist nicht viel anderes als einstd::ostreamund einstd::cinnicht viel anderes als einstd::istream. Einstd::ifstreamist auch einstd::istream. Und denstd::ifstreamverwendest du ja.Little Programmer schrieb:
Cin und <iostream> bringt mir leider überhaupt nichts, da ja eine Textdatei ausgelesen werden soll bzw. muss.
std::cinist einstd::istreamObjekt.std::ifstreamerbt vonstd::istream. Wenn dir da kein Licht aufgeht, dann lern zuerst C++.Dann nochmals zu deinem Code. Ganz ehrlich, der ist so hässlich, dass ich mir verdammt schwer tue, den durchzuarbeiten. Uneinheitliche Einrückungen, uneinheitliche Variablenbenennung, teilweise echt seltsame Vorgehensweise, unübersichtlich ... eben grauenhaft ...
Auch hast du überhaupt nicht die Möglichkeiten von C++ genutzt, nicht einmal die Möglichkeiten von C. Es ist mir ein Rätsel, wie du auf die Idee kommst, in dem Stadium von deinem Wissen über C++ mit der SDL anzufangen. Das kann ja nur katastrophal enden.Nur kurz zu deiner Schleife, wieso dort mehr als 1 Zeichen vorgerückt wird:
if(Aufloesung.get() != 'x') // get() -> Ein Zeichen vorwärts. { AktuellesTextstueck[zahlpos] = Aufloesung.get(); // get() -> Ein Zeichen vorwärts. // printf(&AktuellesTextstueck[zahlpos]); // Kann gefährlich sein. Zum Glück füllst du das Array zuerst mit Nullen. // Könnte man aber auch einfach anders angehen. Gäbe sowieso im ganzen Code // bessere Möglichkeiten. Erst recht mit C++ printf("%c\n", AktuellesTextstueck[zahlpos]); // printf("\n"); // unnötig geworden. } else { AktuellesTextstueck[zahlpos] = '\0'; zahlpos = 20; } // Aufloesung.clear(); // unnötig Aufloesung.seekg(1, ios::cur); // seekg -> 1 Zeichen vorwärts. nZahl = Aufloesung.tellg(); printf("Position: %d\n", nZahl);Also ganz ehrlich. Es löst zwar vielleicht dein aktuelles Problem nicht, aber lern erst vernünftig C++, bevor du dich an sowas wie die SDL ranwagst. Mir scheint, du probierst ohne Wissen, irgendetwas hinzubiegen. So sieht jedenfalls dein Code aus

C++ ist eine sehr komplexe Sprache. Nimm dir Zeit, übe zuerst fleissig auf der Konsole. Der Einstieg ist hart und erfordert viel Geduld. Probier nicht an fortgeschrittene Themen zu gehen, wenn du einfach noch nicht bereit dafür bist. Es hat keinen Sinn, das endet nur in einem GAU. Arbeite zum Beispiel mal ein C++ Grundlagen Buch durch. Empfohlen werden oft:
- C++ Primer
- Thinking in C++ 1&2 (Auch gratis als PDF verfügbar, nur Englisch)Auch noch einen Tipp: Probier von deutschen Variablennamen wegzukommen. Das sieht einfach nur hässlich aus in Kombination mit den restlichen englischen Namen aus den Bibliotheken. Die Sprache in der Informatik ist hauptsächlich Englisch, daran sollte man sich gewöhnen.
Grüssli
-
Danke für die ganzen Tipps. Bin zur Zeit dabei, "C++ für Dummies" durchzuarbeiten. Aber Bashar hat schonmal eine wichtige Sache genannt. Ich wusste nicht, das get() gleichzeitig ein Zeichen ausgibt und ein Zeichen weiter springt. Also eigentlich hätte es mir aus den ganzen while-Schleifen Beispielen aus dem Internet klar sein müssen, aber soweit hab ich nicht gedacht. Jetzt springt es immer noch zwei Zeichen weiter und liest ganz merkwürdige Zahlenwerte in die Integervariablen ein. Ich kenne fstream jetzt eigentlich nur aus dem Internet, aber es kommt noch einmal in meinem Buch vor. Ich lass das jetzt erstmal ruhen, bis ichs nochmal im Buch durchgelesen habe.