Datum:
Angehängte Dateien: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?
Datum:
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.
Datum:
Angehängte Dateien: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?
Datum:
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)) { fgets(buffer,256,myfile); printf("%s",buffer); } fclose(myfile); return 0; } |
Datum:
Ich habs glaube ich geschafft, habs mit dieser While-Schleife mit dem feof versucht und ich kann tatsächlich alle Einträge auslesen :).
Datum:
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:
.... while( fgets(buffer,256,myfile) ) { // oder fread oder ... printf("%s",buffer); } if( !feof(myfile) ) { printf( "Fehler beim Lesen der Datei!" ); .... } fclose(myfile); |
Datum:
Ich schaffs leider doch nicht -_- ich komme leider aus dieser Schleife nicht mehr heraus. Ausschnitt aus der Hauptfunktion
while(!(no_more_entries_flag)) { first_element_of_list = readHeader(input_file, error_code, &no_more_entries_flag); if(*error_code != 0) { closeFile(&input_file); return first_element_of_list; } first_element_of_list = readContent(input_file, first_element_of_list, error_code); if(*error_code != 0) { closeOpenedFile(&input_file); return first_element_of_list; } first_element_of_list = first_element_of_list->next; number_of_entries++; } |
Ausschnitt aus der Header-Einlesefunktion, wie ich überprüfe, ob ich das Ende des Files erreicht habe
if((fread(&(first_element_of_list->header), sizeof(Header), 1, input_file)) != 1) { first_element_of_list = NULL; return first_element_of_list; } if(feof(input_file) != 0) // hier will ich eigentlich herauskommen { *no_more_entries_flag = 0; return first_element_of_list; } |
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.
Datum:
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.
Datum:
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 :/
Datum:
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.
Datum:
Rolf Magnus schrieb: > Bedeutung des no_more_entries_flag, in der ReadHeader-Funktion habe ich folgende if
if(feof(input_file) != 0) { *no_more_entries_flag = INITIALISATION_CONSTANT_ZERO; return first_element_of_list; } |
also es wird gesetzt, sobald feof ungleich Null ist, also sobald das Ende des files erreicht wurde.
Datum:
> 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
if(feof(input_file) != 0) { *no_more_entries_flag = INITIALISATION_CONSTANT_ZERO; return first_element_of_list; } |
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
if(feof(input_file)) { *no_more_entries_flag = TRUE; return first_element_of_list; } |
Jetzt ist das logisch: Wenn das File zu ende ist (feof liefert wahr), dann gibt es keine Einträge mehr.
Datum:
Und du solltest tunlichst hier
while(!(no_more_entries_flag))
{
first_element_of_list = readHeader(input_file,
error_code, &no_more_entries_flag);
...
|
nach dem Leseversuch sowohl first_element_of_list UND no_more_entries_flag auswerten. first_element_of_list kann NULL sein. Du setzt es hier
if((fread(&(first_element_of_list->header), sizeof(Header), 1, input_file)) != 1) { first_element_of_list = NULL; return first_element_of_list; } |
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:
while( header = readHeader(input_file, header) ) {
readContent( input_file, header );
number_of_entries++;
}
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
while( header = readHeader(input_file, header) ) { if( readContent( input_file, header ) ) { // <--- neuen Knoten header an dieser Stelle in die Liste einhängen number_of_entries++; } } 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.
