fscanf geht nich
-
Hallo,
Diesmal wollte ich mal versuchen mittels fscanf ein Textfile einzulesen, nur leider klappt das (wiedermal) nicht. Ich bekomme keine direkte Fehlermeldung die sich auf eine Zeile bezieht, weiss jedoch dass der Fehler in der "while-Schleife" liegt. Ausserdem weiss ich auch nicht ob der Code so ueberhaupt funktionieren kann: Es soll aus dem Stream des FILE-pointers in den char* direkt eingelesen werden mittels fscanf().Fragen:
1. Wird dabei eig ein '\0' angehaengt?
2. Habe ich hier irgendeine Sicherheit ueber die Allokation des Speichers fuer content, falls dieser mitgegeben allokierte zu klein wird?
3. Meine Hauptfrage ist jedoch, warum funktioniert der Code nicht?Danke im voraus
#include <xyz.h> FILE* get_read_file_pointer(char filename[FILENAME_MAX]) { FILE* fp = NULL; if(filename == NULL) return NULL; if((fp = fopen(filename, "r")) == NULL){ perror("Reading \'%s\' failed! "); return NULL; } return fp; } int read_formated(FILE* fp, char* content) { printf("read_formated(fp, content)\n"); if(fp == NULL) return -1; while((fscanf(fp, "%s", content)) != EOF) // FIXME: geht nich! ; printf("read_formated(fp, content) - done\n"); return 0; }; int main(){ FILE *fp = NULL; char *content = malloc(LEN_LINE * sizeof(char)); strcpy(content, ""); char file2[] = "file2.txt"; // ... printf("Get read file pointer to %s\n", file2); fp = get_read_file_pointer(file2); printf("Reading out formated: %i\n", read_formated(fp, content)); printf("%s\n", content); strcpy(content, ""); close_stream(fp); printf("Done.\n\n"); // ... return EXIT_SUCCESS; }
-
@1: ja
@2: ja
@3: deshalb:
FILE* get_read_file_pointer(char filename[FILENAME_MAX]) { FILE* fp = NULL; if(filename == NULL) return NULL; if((fp = fopen(filename, "r")) == NULL){ perror("Reading \'%s\' failed! "); return NULL; } return fp; }
die funktion funktioniert nicht weil du den FILE-pointer fp IN der funktion
lokal auf den STACK anlegst und ihm dann zurückgibst. problem: nach dem
verlassen der funktion wird er gelöscht. du musst es stattdessen mit call per
reference machen, dh: einfach einen FILE-pointer als parameter übergeben und da
die werte hineinschreiben.int read_formated(FILE* fp, char* content) { printf("read_formated(fp, content)\n"); if(fp == NULL) return -1; while((fscanf(fp, "%s", content)) != EOF) // FIXME: geht nich! ; printf("read_formated(fp, content) - done\n"); return 0; };
also mit fscanf ließt du ja etwas von der tastatur in eine datei ein. aber (so
habs ich verstanden) du willst ja den text aus der datei in ein char-array
schreiben. also verwend die funktion fgets. sie schreibt dir den inhalt der
datei in einen string.// am anfang noch ein int length; // so gehört die while-schleife do{ length = strlen ( content ); fgets ( content + length, LEN_LINE - length, ptr); // LEN_LINE ist die dimension in der main-funktion while ( !feof ( fp ) );
mfg Gaste
-
Gaste schrieb:
@1: ja
Soweit stimmt's noch.
@2: ja
Da ist schon die Frage etwas unklar - welche Allokation meinst du eigentlich? (malloc() liefert NULL zurück, wenn der RAM nicht ausreicht für deine Anforderung, fscanf() prüft nicht, wieviel Platz es benötigt.
@3: deshalb:
FILE* get_read_file_pointer(char filename[FILENAME_MAX]) { FILE* fp = NULL; if(filename == NULL) return NULL; if((fp = fopen(filename, "r")) == NULL){ perror("Reading \'%s\' failed! "); return NULL; } return fp; }
die funktion funktioniert nicht weil du den FILE-pointer fp IN der funktion
lokal auf den STACK anlegst und ihm dann zurückgibst. problem: nach dem
verlassen der funktion wird er gelöscht. du musst es stattdessen mit call per
reference machen, dh: einfach einen FILE-pointer als parameter übergeben und da
die werte hineinschreiben.Wer hat dir denn sowas erzählt? Du kannst den FILE* ganz normal per return übergeben - die Daten dahinter bleiben gültig, bis du ihn an fclose() zurückgibst. (mit malloc() angeforderte Speicherbereiche bleiben genauso außerhalb des Stacks)
also mit fscanf ließt du ja etwas von der tastatur in eine datei ein. aber (so
habs ich verstanden) du willst ja den text aus der datei in ein char-array
schreiben. also verwend die funktion fgets. sie schreibt dir den inhalt der
datei in einen string.fscanf() liest schon aus Datei ein, das ist nicht das Problem. (scanf() liest von Tastatur)
@Fabeltier: Der Aufruf sieht schon falsch aus - du liest so lange Strings aus der Datei ein, bis du ein EOF zurückbekommst, und gibst anschließend die letzte gelesene Eingabe aus. Wie bist du überhaupt darauf gekommen, dort eine while-Schleife zu benötigen?
if((fscanf(fp, "%s", content)) == EOF) { printf("Fehler beim Lesen\n"); return false; } return true;
(PS: "irgendwas ist nicht richtig" ist eine miserable Fehlerbeschreibung ;))
-
Hallo,
zu Gaste
Ich arbeite hier erstens mit einem Zeiger, also handelt es sich meines Wissens um Speicher auf dem Heap und nicht auf dem Stack und zweitens funktioniert die Funktion, ich habe sie lediglich der Vollstaendigkeit halber angegeben. Ob es besser ist einen Zeiger als Parameter mitzugeben und den Return Value eher als Kontrollwert fuer die Funktion benutzt oder ob man den FILE* per Return Value zurueckgibt ist afaik eher Geschmackssache, ich muss aber zugeben, dass mir die Parametervariante mittlerweile auch etwas besser gefaelltzu 2. und 1.
Ich verstehe es so, es werden Zeichen eingelesen und an den Speicher auf den *content zeigt angehaengt. Daher frage ich mich, ob nun ein '\0' ueberhaupt angehaengt wird, wenn das Einlesen vorbei ist und (2.) was passiert, wenn kein Speicher mehr vorhanden ist, *content ist ja nur ein Zeiger und somit nicht auf eine bestimmte Laenge eines Speicherbereichs, auf dessen Anfang er zeigt/zeigen soll, festgelegt.zu 3.
ich habe meinen Code nach folgendem Link zusammengefriemelt:
http://www.galileo-press.de/openbook/c_von_a_bis_z/c_018_008.htm#RxxobKap01800804002A1E1F03E18C
Gleich dort das erste Beispiel: /* csv_log.c */Dort wird auch eine while Schleife benutzt bis EOF eingelesen wird. Nunja, es handelt sich um das einlesen einer Structur und fscanf scheint einige Facetten zu haben, weswegen ich mir nicht sicher bin ob ich die Funktion so ueberhaupt uebernehmen kann.
Wie funktioniert die Funktion mit "fscanf" nun richtig? Einfach nur ohne while?
-
Fabeltier schrieb:
zu 2. und 1.
Ich verstehe es so, es werden Zeichen eingelesen und an den Speicher auf den *content zeigt angehaengt. Daher frage ich mich, ob nun ein '\0' ueberhaupt angehaengt wird, wenn das Einlesen vorbei ist und (2.) was passiert, wenn kein Speicher mehr vorhanden ist, *content ist ja nur ein Zeiger und somit nicht auf eine bestimmte Laenge eines Speicherbereichs, auf dessen Anfang er zeigt/zeigen soll, festgelegt.@1: fscanf() nimmt den übergebenen Zeiger als die Anfangsadresse eines char-Arrays (und geht davon aus, daß dieses groß genug für die Eingabe ist) - dort packt es den eingelesenen String dann hinein (inklusive '\0' als Abschluß).
@2: Aber es hat keine Möglichkeit festzustellen, wieviel Platz in dem Array tatsächlich verfügbar ist. Wenn der Bereich als zu klein ist für die Eingabe, schreibt er einfach hinter dem Array weiter - mit teilweise dramatischen Folgen (je nachdem, was dort steht).zu 3.
ich habe meinen Code nach folgendem Link zusammengefriemelt:
http://www.galileo-press.de/openbook/c_von_a_bis_z/c_018_008.htm#RxxobKap01800804002A1E1F03E18C
Gleich dort das erste Beispiel: /* csv_log.c */Dort wird auch eine while Schleife benutzt bis EOF eingelesen wird. Nunja, es handelt sich um das einlesen einer Structur und fscanf scheint einige Facetten zu haben, weswegen ich mir nicht sicher bin ob ich die Funktion so ueberhaupt uebernehmen kann.
Wie funktioniert die Funktion mit "fscanf" nun richtig? Einfach nur ohne while?
Ja, dort wird aber auch innerhalb der Schleife der Inhalt des eingelesenen Struct's ausgewertet - auf ein Beispiel umgesetzt wäre das etwa:
while((fscanf(fp, "%s", content)) != EOF) { //mach was mit dem Inhalt von 'content' }
Du willst (wenn ich das richtig verstanden habe) jeweils eine einzelne Zeile auslesen und an das Hauptprogramm zurückgeben - das funktioniert eher mit der if()-Variante, die ich unten vorgeschlagen habe:
int read_formated(FILE* fp, char* content) { printf("read_formated(fp, content)\n"); if(fp == NULL) return -1; if((fscanf(fp, "%s", content)) == EOF) { printf("Dateiende erreicht\n"); return -1; } printf("read_formated(fp, content) - done\n"); return 0; }; ... int num=0; while(read_formated(fp,content)==0) { printf("%d:\t%s\n"),num,content); ++num; }
-
Hm, gut, aber wenn nun der Puffer (also die allokierte Groesse auf die *content zeigt) nun wieder nicht ausreicht, etwa fuer eine Zeile (eine Zeile endet mit '\n' und kann beliebig lang sein, wie ich schon gelernt habe
). Dann habe ich spaetestens das naechste Problem mit fscanf(), wenn *content keinen Speicher mehr hat.
Ich wuerde schon gerne checken ob ich noch Platz habe fuer weitere Ein-Lesungen und einigermassen veruschen sicherzugehn. Nun haette ich folgenden Loesungsvorschlag: ich lese nicht direct in den *content ein, sondern benutze ein char arr[] mit fester Groesse, dieses wuerde ich dann gerne vollschreiben und dann das ganze mit strcat() an *content anhaengen, afaik checkt strcat() ja ob es moeglich ist weiteren Speicher anzukonkatenieren bzw allokiert den notwendigen einfach mit (oder ist das auch nur eine Illusion von mir?).
Mein Problem mit fscanf() nur irgendwie wieder, ist dass fscanf irgendwie einfach weiterliest und nicht bei etwa dem x-ten Zeichen (der Groesse des temp arrays) zu lesen aufhoert oder kann man das irgendwie einbauen? Wenn ja, wie?
Eine Alternative waere zeichenweise einzulesen mit fgetc() - das muesste imo diese Kontrollmoeglichkeiten bieten, eine andere fgets() mit einem uebergebenem Puffer und zeilenweise, nur kann ich fgets() eigentlcih besser kontrollieren als fscanf()? Oder schreibt fgets() auch einfach weiter, wenn kein Speicher mehr vorhanden ist?
-
Fabeltier schrieb:
Ich wuerde schon gerne checken ob ich noch Platz habe fuer weitere Ein-Lesungen und einigermassen veruschen sicherzugehn. Nun haette ich folgenden Loesungsvorschlag: ich lese nicht direct in den *content ein, sondern benutze ein char arr[] mit fester Groesse, dieses wuerde ich dann gerne vollschreiben und dann das ganze mit strcat() an *content anhaengen, afaik checkt strcat() ja ob es moeglich ist weiteren Speicher anzukonkatenieren bzw allokiert den notwendigen einfach mit (oder ist das auch nur eine Illusion von mir?).
Ja, das ist auch eine Illusion - die Funktionen wie strcat() oder sprintf() gehen einfach davon aus, daß der Platz ausreicht - und schreiben im Ernstfall über das Array-Ende hinaus (in fremde Speicherblöcke). Vergrößern können sie den Speicher aus eigener Kraft erst recht nicht.
Wenn du sicherstellen willst, daß deine Array-Grenzen eingehalten werden, mußt du die Array-Größe mit übergeben (strncat() beschränkt die Länge, bei fscanf() kannst du die Länge im Formatstring übergeben als
fscanf("%80s",content);
(fest vorgegebene Länge) bzw. fscanf("%*s",content,len);[/c] (variable Länge - bei der Reihenfolge der Parameter bin ich mir nicht 100% sicher).Eine Alternative waere zeichenweise einzulesen mit fgetc() - das muesste imo diese Kontrollmoeglichkeiten bieten, eine andere fgets() mit einem uebergebenem Puffer und zeilenweise, nur kann ich fgets() eigentlcih besser kontrollieren als fscanf()? Oder schreibt fgets() auch einfach weiter, wenn kein Speicher mehr vorhanden ist?
Wenn du fgets() eine falsche Größenangabe übergibst, verlässt es sich darauf. Aber ansonsten beachtet es die übergebene Arraygröße.
(btw, dir ist klar, daß fscanf("%s") nicht zeilen- sondern wortweise liest?)
-
Danke fuer die ausfuehrlichen Antworten!
fscanf/wortweise - nein war mir nicht klar, ich erinnere mich aber an etwas mit Problemen von fscanf und Spaces gelesen zu haben, war mir aber nicht mehr sicher.
Also folgere ich nun,
Loesung 1: entweder ich setze einen Puffer fester Laenge ein (bspw ein char[]) und uebergebe diesen Puffer, etwa fgets() mit. Jedesmal wenn dieser "voll" ist, allokiere ich dessen Groesse an Speicher fuer *content und kopiere dann den Inhalt des Puffers dort hinein. Den Puffer kann ich dann wieder loeschen und darin weiterschreiben.oder Loesung 2: ich lese Zeichenweise mit fgetc() ein und kann somit direkt checken wann welcher Speicher voll ist und ggf. neuen Speicher sicher dazu allokieren.
Naja, ich weiss, dass strcat() wenigstens ein '\0' am Schluss anhaengt
Ich hoffe das ist so richtig?