[erledigt] fscanf-verständnis
-
Moin,
ich bin nicht sonderlich gut in c, ich benutze es, weiß aber manchmal leider nicht was genau hinter den Befehlen steckt. Das ist natürlich nicht optimal, daher möchte ich das ein wenig ändern.
Folgenden code nutze ich in einem Programm um einen 2D-Array aus einer ascii-datei einzulesen:
[code] #include <stdio.h> #include <strings.h> main() { int j,k; float npt_y,npt_z, **ne_norm; FILE *filein_ne; char *filename_ne ="data.dat", char_tmp; npt_y =1000; npt_z =1000; ne_norm =matrix(0,npt_y,0,npt_z); //------------------------------------------------- //---jetzt kommt der erwähnte code-Schnipsel------- //------------------------------------------------- filein_ne =fopen(filename_ne,"r"); if (filein_ne==NULL) { printf("error opening the file %s\n",filename_ne); return(-1); } else { printf("status: file %s successfully opened \n",filename_ne); j =0; k =0; while (!feof(filein_ne)) //---if EOF => not 0; if not EOF => 0 { char_tmp =fgetc(filein_ne); if (char_tmp=='\n') { k++; j =0; } if ( j<npt_y && k<npt_z ) { fscanf(filein_ne,"%f", &ne_norm[j][k]); } j++; } fclose(filein_ne); printf("status: finished reading from %s\n",filename_ne); } } [/code]
Das funktioniert auch, allerdings muss ich sagen, dass ich gerade nicht verstehe, warum. Mein Verständnis: Die Datei wird zeilenweise durchlaufen und immer wenn ein Ende der Zeile erreicht ist, dann werden die entsprechenden Zähler für den array, in den die Werte 'reingeschrieben werden sollen, wieder auf null gesetzt.
Meine Frage: Das einlesen macht doch der fscanf-Befehl, aber woher weiß der, dass er immer ein Element weiterspringen muss
Ich danke schonmal im voraus!
-
Das weiß er nicht. das weiterspringen macht das
j++
.
-
aber das j++ sorgt doch nur dafür, dass in dem array ne_norm eine Position weitergegangen wird. Irgendwer muss dem Programm doch auch sagen, dass er in der eingelesenen Datei ein Element weiter muss
-
fscanf sorgt selbst dafür, dass der Dateizeiger entsprechend weitergezählt wird bis zum 1.Zeichen, welches sich nicht mehr hinsichtlich des übergebenen Formats, in diesem Fall "%f", interpretieren lässt.
Dein Programm sollte eigentlich nicht funktionieren, fgetc liest ein Zeichen und der Dateizeiger springt dabei ein Zeichen weiter, sodass dass anschließende fscanf erst ein Zeichen zu spät mit der Auswertung beginnen kann. Hier würde sich ungetc anbieten.
Überlicherweise realisiert man das zeilenweise Lesen einer Textdatei in C mittels
fgets und arbeitet dann mit dem Zeilenstring weiter mittels Stringfunktionen, in deinem Fall also sscanf (statt fscanf).
-
ja, ich habe da gestern abend auch noch mal nachgedacht und ich glaube, ich habe das ganze jetzt etwas vereinfacht:
[code] float readFile_2D(int i, int j, int npt_i, int npt_j, char filename[], float **array_2D) { int retValue; FILE *file_in; //---open in read-only-mode file_in =fopen(filename,"r"); //---check if file exists if (file_in==NULL) { printf("ERROR: could not read the following file: %s\n",filename); exit(1); } //------read the data else { printf("following file was successfully opened: %s\n",filename); for ( i=0 ; i<npt_i ; i++ ) { for ( j=0 ; j<npt_j ; j++ ) { retValue =fscanf(file_in, "%f", &array_2D[i][j]); if ( retValue==EOF || retValue<=0 ) { printf("ERROR: during read of file %s, size mismatch between file-array and data-array\n",filename); exit(1); } } } //------close the file fclose(file_in); } printf("status: following file was successcully closed: %s\n",filename); } //------------------------------------------------------------------------------------------ [/code]
Vielen Dank auf jeden Fall für die schnelle Klärung meiner Frage, nämlich das fscanf automatisch ein Element weiterhüpft.
Aber was halten denn die Experten von der Variante oben, die ist doch OK, oder?
-
Nö, nicht OK.
Der Returnwert float wird nirgendwo returniert, besser wäre ein Boolean-Äquivalenztyp.
Temporäre Variablen i,j übergibt man normalerweise nicht als Parameter.
exit() returniert das ganze Programm und nicht die Funktion und sollte durch "return erfolgreichausgeführtodernicht" ersetzt werden.
Vor jedem return/exit einer Funktion sollte eine temporär geöffnete Datei immer geschlossen werden.
Im Sinne der besseren Lesbarkeit sollte eine Textdatei auch entsprechend geöffnet werden, mit "rt" statt "r".
Bestimmt habe ich noch was vergessen, aber das sollte erstmal reichen?!
-
aalemann schrieb:
Aber was halten denn die Experten von der Variante oben, die ist doch OK, oder?
Keine Ahnung, was die Experten davon halten.
Mit exit nimmst du dem Programm die Möglichkeit, sich sauber zu beenden, reservierter Speicher kann nicht freigegeben werden.
Dann würde ich das Öffnen der Datei und die Ausgabe von Fehlermeldungen von der Funktion readFile_2D trennen ( i, j brauchst du nicht zu übergeben und wozu der ungenutzte Rückgabetyp float?).
So in etwa:int readFile_2D ( FILE* fp, unsigned ni, unsigned nj, float **array_2D ) { unsigned i, j; for ( i = 0; i < ni; i++ ) for ( j = 0; j < nj; j++ ) if ( 1 != fscanf ( fp, "%f", &array_2D[i][j] ) || feof(fp) ) return 1; return 0; } int main() { ... if ( readFile_2D ( fp, ni, nj, ptr )) // Fehlerbehandlung bzw. Fehlermeldung. ... }
-
Wutz schrieb:
aber das sollte erstmal reichen?!
Wahrhaftig! Vielen Dank euch allen