Hallo!
Ich versuche gerade in C unter Verwendung des Befehls fread aus einem
Binärfile Einträge einer bestimmen Form (siehe Anhang) herauszulesen.
Sie bestehen aus einem Header mit fixer Länge und aus einem Content mit
zwei Strings variabler Länge.
Ich habs nun schon geschafft, dass ich den ersten Eintrag gesamt auslese
und dann in eine einfach verkettete Liste speicher mit genau diesen
Einträgen (ID, Latitude, ...).
Nun weiß ich aber nicht, wie viele solcher Einträge in der Datei
gespeichert sind, hat jemand vielleicht eine Idee, wie ich genau so oft
einlesen kann, bis kein Eintrag mehr vorhanden ist?
Meine bisherigen Gedankengänge:
Auf den return-Wert von fread schauen
http://www.cplusplus.com/reference/clibrary/cstdio/fread/
dieser liefert jedoch den gleichen Wert, wenn entweder ein Fehler
passiert bzw. EOF erreicht wurde.
Also so wirds wohl nicht gehen
Könnte mir jemand einen Tipp gebn?
Hans M. schrieb:> Auf den return-Wert von fread schauen
das ist schon richtig. Du kannst ja nach einem Fehler mit feof prüfen ob
du am ende bist.
Man könnte auch vorher die Dateigröße ermitteln und rechenn wie viele
einträge denn drin sind.
Das mit feof hab ich gerade gesehen, nur weiß ich nicht, wie man das in
mein Programm implementiert.
Ich hab im Anhang mal so Binärfile, aus welchem ich einlese, angehängt,
funktioniert dort dieses feof?
Könntest du mir zu diesem feof vielleicht ein Beispielprogramm zeigen?
Hans M. schrieb:> Funktioniert das genauso wie in diesem Example hier?>> #include <stdio.h>>> int main(void)> {> char buffer[256];> FILE * myfile;>> myfile = fopen("some.txt","r");>> while (!feof(myfile))
schon falsch.
C sieht nicht in die Zukunft! In C muss ein Leseversuch erfolgt sein und
aufgrund von eof fehlgeschlagen sein, ehe eof gemeldet wird.
Alle C-Lesefunktionen sind so gestrickt, dass man ihren Return-Wert
auswertet um damit die Schleife zu steuern, die das Lesen regelt. Erst
danach, nach der Schleife, überprüft man mittels feof ob die Schleife
abgebrochen wurde weil ein Fehler auftrat oder weil das Dateiende
erreicht wurde.
Die typische Forenfrage zu deinem Code lautet:
Hilfe, warum wird mein letzter Datensatz zweimal eingelesen.
Und so gehts richtig:
1
....
2
3
while(fgets(buffer,256,myfile)){// oder fread oder ...
if(feof(input_file)!=0)// hier will ich eigentlich herauskommen
9
{
10
*no_more_entries_flag=0;
11
returnfirst_element_of_list;
12
}
Das Problem ist, das ich, wenn zB. 3 Einträge einzulesen habe, dann lies
ich die 3 Einträge ein, komme in den 4. Schleifendurchlauf der While und
dort kommt es dann zu einem Segmentation, d.h. ich komme gar nicht mehr
in die Funktion readHeader (ein printf wird hier nicht mehr angezeigt,
jedoch wenn ich es am Anfang der While einfüge, schon)
Hat jemand eine Idee, wo mein Fehler liegen könnte, ich kann leider den
ganzen Code nicht posten, weil das bei der Abgabe mit Plagiatgefahr
enden könnte!
Ich könnte auch jemanden den Code senden, aber der darf ihn dann halt
nicht veröffentlichen.
Hans M. schrieb:> if(feof(input_file) != 0) // hier will ich eigentlich herauskommen> {> *no_more_entries_flag = 0;> return first_element_of_list;> }
Diese ganzen Negierungen machen es nicht leichter zu lesen:
wenn feof nicht null ist, lösche das Flag, das sagt, ob keine weiteren
Daten kommen. Und in der anderen Funktion fragst du dann ab, ob dieses
Flag nicht gesetzt ist.
Entworren heißt das:
Wenn das Dateiende erreicht ist, soll das Programm weiterlesen.
Hans M. schrieb:> Hat jemand eine Idee, wo mein Fehler liegen könnte, ich kann leider den> ganzen Code nicht posten, weil das bei der Abgabe mit Plagiatgefahr> enden könnte!
Hä? Das verstehe ich nicht.
Rolf Magnus schrieb:> Hä? Das verstehe ich nicht.
Nein, ich hab mich da schlecht ausgedrückt. Mein komplettes Programm
brauche ich für eine Hausübung und dort wird streng kontrolliert, ob
nicht jemand was kopiert hat mit Plagiattestprogramm und deswegen kann
ich so nicht den ganzen Code posten!
http://www.cplusplus.com/reference/clibrary/cstdio/feof/
A non-zero value is returned in the case that the End-of-File indicator
associated with the stream is set.
Hier steht ja, wenn feof ungleich Null ist, dann ist das Ende des File
erreicht.
>> if(feof(input_file) != 0) // hier will ich eigentlich herauskommen>> {>> *no_more_entries_flag = 0;>> return first_element_of_list;>> }
hier mache ich ja auch nichts anderes, sofern feof ungleich Null ist, so
springe aus der Header-Einlesefunktion heraus und hör auf zum Einlesen.
Bin gerade draufgekommen, dass, egal wie viele Einträge ich einlese, am
Ende jedes Mal bei mir ein Segmentation Fault kommt beim Ausführen!
Hab nun mit Valgrind getestet und hab folgenden Fehler bekommen:
==17148== 1 errors in context 1 of 2:
==17148== Invalid read of size 4
==17148== at 0x8048910: freeStringOfList (ass3.c:417)
==17148== by 0x804860B: main (ass3.c:229)
==17148== Address 0x1c is not stack'd, malloc'd or (recently) free'd
D.h. ich greife auf einen Speicherbereich zu, auf den ich nicht
zugreifen sollte, aber ich finde einfach nicht den Fehler.
Könnte ich jemanden einmal den Code zeigen, damit er sich das einmal
anschaut, ich komme einfach nicht auf den Fehler drauf :/
Hans M. schrieb:> Hier steht ja, wenn feof ungleich Null ist, dann ist das Ende des File> erreicht.>>>> if(feof(input_file) != 0) // hier will ich eigentlich herauskommen>>> {>>> *no_more_entries_flag = 0;>>> return first_element_of_list;>>> }>> hier mache ich ja auch nichts anderes, sofern feof ungleich Null ist, so> springe aus der Header-Einlesefunktion heraus und hör auf zum Einlesen.
Was ist denn genau die Bedeutung des no_more_entries_flag, und warum
setzt du es auf 0? In deiner while-Schleife in der übergeordneten
Funktion bleibst du doch solange drin, bis es nicht mehr 0 ist.
> Bin gerade draufgekommen, dass, egal wie viele Einträge ich einlese, am> Ende jedes Mal bei mir ein Segmentation Fault kommt beim Ausführen!> Hab nun mit Valgrind getestet und hab folgenden Fehler bekommen:>> ==17148== 1 errors in context 1 of 2:> ==17148== Invalid read of size 4> ==17148== at 0x8048910: freeStringOfList (ass3.c:417)> ==17148== by 0x804860B: main (ass3.c:229)> ==17148== Address 0x1c is not stack'd, malloc'd or (recently) free'd>> D.h. ich greife auf einen Speicherbereich zu, auf den ich nicht> zugreifen sollte,
Ja, und zwar in Zeile 417 von ass3.c.
> also es wird gesetzt,
Was wird da gesetzt?
Tu dir selbst einen Gefallen und achte darauf, wie deine Variablen
heißen. Und dann geh konsequent nach dem Muster vor:
0 bedeutet falsch (false), also die Bedingung die durch die Variable
ausgedrückt wird, ist NICHT erfüllt
1 bedeutet wahr (true). Die Bedingung ist erfüllt.
Damit KANN das hier nicht so lauten
Wenn eof vorliegt, dann gibt es offensichtlich keine Einträge mehr. "No
More Entries" muss daher TRUE sein. 0 ist aber nicht TRUE.
Und benutz nicht solche Makros wie INITIALISATION_CONSTANT_ZERO. Wenn
ein Flag nur TRUE oder FALSE sein kann (und das sind Flags nun mal,
sonst würden sie nicht Flags heißen), dann schreib das auch so
1
if(feof(input_file))
2
{
3
*no_more_entries_flag=TRUE;
4
returnfirst_element_of_list;
5
}
Jetzt ist das logisch: Wenn das File zu ende ist (feof liefert wahr),
dann gibt es keine Einträge mehr.
auf NULL. Du setzt aber NICHT error_code! Den würdest du zwar in der
aufrufenden Funktion abfragen, setzt es aber nie.
Summa summarum: Du hast da ein heilloses Durcheinander mit Fehlercode?,
gibt es noch Elemente?, konnte gelesen werden?.
Vereinfache das! Mach EINEN Fehlermechanismus und zieh den durch! Wenn
die readHeader Funktion bei einem Fehler NULL zurückliefert, dann ist
das ok. Der Aufrufer bricht dann einfach seinerseits die Leseschleife
ab:
So ungefähr:
1
while(header=readHeader(input_file,header)){
2
readContent(input_file,header);
3
number_of_entries++;
4
}
5
6
closeFile(&input_file);
einfach, simpel, überschaubar. Leider hast du nicht genug von deiner
Liste gezeigt, so dass ich nicht sagen kann, wie das einhängen in die
Liste funktioniert. Gefühlsmässig würde ich sagen: readHeader ist der
falsche Ort dafür. Denn ein neuer Knoten wird nur dann eingehängt, wenn
sowohl Header als auch Content korrekt gelesen werden konnte. Von daher
müsste das einhängen hier irgendwo
1
while(header=readHeader(input_file,header)){
2
if(readContent(input_file,header)){
3
// <--- neuen Knoten header an dieser Stelle in die Liste einhängen
4
number_of_entries++;
5
}
6
}
7
8
closeFile(&input_file);
erfolgen, wenn sowohl der Header als auch der Content korrekt gelesen
werden konnte. Da sieht man aber in deinem Code nichts davon, so dass du
entscheiden musst wie das gehen soll.