Probleme beim Einlesen von Werten



  • Hallo zusammen,

    ich möchte ein Programm schreiben mit dem ich verschiedene Werte aus einer Datei einlese und dann weiter verrechnen kann und sie mir auf dem Bildschirm anzeigen lassen kann.
    Das Problem ist die angezeigten Werte sind nicht die, die ich vorher in die Datei geschrieben habe.
    Hab jetzt mal ein verkürztes Programm geschrieben, welches nur die Dateigröße sowie die einzelnen Dateinhalte einlesen und auf dem Bildschirm wieder ausgeben soll. Der Fehler bleibt. Die Anzahl der Zahlen in der Datei wird richtig ermittelt, allerdings werden die Werte als 0.000000 ausgegeben.
    Falsch eingelesen oder falsch ausgegeben, vielleicht falscher Typ (habs mit %f,%s,%c probiert)?
    Die Datei hab ich vorher mit einem anderen Projekt erzeugt.
    Habs mit .csv ; mit .dat und mit .txt versucht.
    Kann mir jemand helfen?
    Vielen Dank schon mal im Voraus

    Hier noch der Quellcode:

    #include <stdio.h>
    #include <eigene.h>
    #include <conio.h>
    #include <string.h>
    
    void main (void)
    
    {	
    	FILE*dateizeiger;
    	int g;
    	char name[50];
    	printf("Bitte Dateinamen eingeben: ");
    	scanf ("%s",name);
    	dateizeiger=fopen(name,"r");
    	fseek(dateizeiger,0,SEEK_END);
    	g=ftell (dateizeiger);
    	g=g/sizeof(float);
    
    	printf("\nEs sind derzeit: %i Zahlen in der Datei.\n",g);
    
    	char inhalt[50];
    	int i;
    
    	for (i=0;i<g;i++)
    	{
    		fscanf(dateizeiger,"%f ",&inhalt[i]);
    		printf("\nWert %i betraegt: %f ", i+1,inhalt[i]);
    	}fclose(dateizeiger);
    }
    


  • Zeile 21: Inhalt sollte ein float Array sein. Kein char Array!!
    Zudem ist der Dateizeiger nach fseek(.., SEEK_END); am ende, du musst ihn erst wieder mit z.B. rewind() an den Anfang setzen.

    Zudem musst du garantieren, dass das Array groß genug ist. Den Rückgabewert von fscanf fragst du auch nicht ab, das würde dir auch ersparen die Dateigröße auslesen zu müssen. Willst du eigentlich nur alle floats auf dem Bildschirm ausgeben, oder sollen sie auch im Programm abgespeichert werden?



  • Außerdem dürfte deine Berechnung der Anzahl auch nicht ganz hinhauen - float ist auf den meisten Systemen 4 bis 8 Byte groß, die Größe der Zahlendarstellung in Textform kann deutlich schwanken von 2 bis 200 Byte (etwa).



  • Vorab vielen Dank für Deine Hilfe,
    das Inhalt vom Typ char war und die Ausgabe mit %f ist irgendwann beim Ausprobieren schief gegangen.
    Hab deine Änderungen vorgenommen und mir wurde dann keine 0.000000 sondern -107374176 ausgeben. Kannst du mir das Erklären?

    habs jetzt mit fread probiert und die Messwerte werden jetzt richitg angezeigt

    fread(&inhalt[i],sizeof(float),1,dateizeiger);
    

    und weiter verarbeiten kann ich die Werte im Programm so auch.
    juhu 🙂 😃 🙂 😃



  • Erst mal ist es interessant, wie du die Daten geschrieben hast.
    Mit printf oder mit fwrite. (kannst du die Datei mit dem Editor ansehen)?

    Wenn du sie mit printf geschrieben hast funktioniert deine Rechnung mit g/sizeof(float) nicht.

    Hast du sie mit fwrite geschrieben, kannst du sie nicht mit fscanf einlesen.



  • Hab sie mit fwrite in die Datei geschrieben. Mit fread klappt es jetzt aber.
    Bin Anfänger und froh das es jetzt überhaupt klappt. Hat denn fread irgendwelche Nachteile, so dass ich es auf scanf ändern sollte?



  • fread()/fwrite() hat eventuell den Nachteil, daß es nicht portabel sein könnte - und daß du die Daten nicht mit dem Texteditor bearbeiten kannst. Im Gegenzug bekommst du wirklich exakt die selben Werte zurück, die du in die Datei geschrieben hast.

    Ansonsten ist es eher wichtig, daß die Einlese-Funktion zur Schreib-Funktion passt - fwrite()/fread() arbeiten mit der binären Repräsentation der übergebenen Daten, fprintf()/fscanf() mit ihrer Darstellung als lesbarer Text.



  • eydasgehtab schrieb:

    Hab sie mit fwrite in die Datei geschrieben.

    🙄 Wie kommt man dann auf die Idee, sie mit scanf() einzulesen? 😃
    floats sehen in Binär halt anders aus, als in einer für Menschen lesbaren Form.
    http://de.wikipedia.org/wiki/Gleitkommazahl



  • Hab jetzt wieder auf fscanf umgestellt. Jetzt ist das Problem, dass die Dateigröße nicht mehr richtig ermittelt wird. Liegt das jetzt an dem fseek?
    Kann man fseek für Textdateien verwenden?

    Wie kann ich denn jetzt die Dateigröße auslesen?

    Cooky451 du hast bei einem Beitrag schon den Rückgabewert von fscanf erwähnt?
    Wie geht das denn damit?



  • Zeig doch mal bitte, wie du die Dateien schreibst.



  • Wir haben mal ein Programm geschrieben mit dem wir eine Datei erstellen und Inhalte einfügen können. Hier der Quellcode:

    #include <stdio.h>
    #include <eigene.h>
    #include <conio.h>
    
    //<dateizeiger>=fopen(<dateiname>,<modus>);
    
    void datei (char[]);
    void schreiben (char[]);
    void lesen (char[]);
    void groesse (char[]);
    
    void main (void)
    {	char name[30];
    	char wahl;
    	datei (name);
    
    	do
    {	clrscr();
    	printf("\t\tDateinamen eingeben..........1\n");
    	printf("\t\tWerte in Datei schreiben.....2\n");
    	printf("\t\tWerte aus Datei lesen........3\n");
    	printf("\t\tGroesse der Datei anzeigen...4\n\n");
    	printf("\t\tProgramm beenden...........X/x\n\n");
    	wahl=getch();
    
    switch (wahl)
    	{	case'1':datei (name);break;
    		case'2':schreiben (name);break;
    		case'3':lesen (name);break;
    		case'4':groesse (name);break;
    
    	}
    }while (wahl!='x'&&'X');
    }
    void datei (char name[30])
    { clrscr();
    	printf("\nBitte Name der Datei: ");
    	scanf ("%s",name);
    }
    
    void lesen (char name[30])
    { 
    	float wert;
    	FILE*datei;
    	datei=fopen(name,"r");
    	if (datei)
    	{
    	clrscr();
    	do
    	{	//fscanf(datei,"%f ",&wert);
    		fread(&wert,sizeof(float),1,datei);
    		if (!feof(datei))printf("%f\n",wert);
    	}while (!feof(datei));
    	fclose (datei);
    }else printf ("\Aus der gewünschten Datei kann nicht gelesen werden");
     getch();	
    }
    
    void schreiben (char name[30])
    
    {	float wert;
    	char ant;
    	FILE*datei;
    	datei=fopen(name,"w");
    	do
    	{
    	clrscr();
    	printf("Bitte eine reele Zahl: ");
    	scanf("%f",&wert);
    	//fprintf(datei,"%f ",wert);
    	fwrite(&wert,sizeof(float),1,datei);
    	printf("\nNoch eine Zahl ?");
    	ant=getch();
    	}while (ant=='j');
    
    	fclose (datei);
    
    }
    
    void groesse (char name[30])
    
    {	
    	FILE*datei;
    	int g;
    	datei=fopen(name,"r");
    	fseek(datei,0,SEEK_END);
    	g=ftell (datei);
    	g=g/sizeof(float);
    	printf("Es sind derzeit: %i Zahlen in der Datei.",g);
    	fclose(datei);
    	getch();
    
    }
    

    [code]

    Damit erzeuge ich dann beispielsweie eine Datei hallo.csv: Kopier die in den entsprechenden Ordner und ruf die in meinem Programm dann auf.



  • Zeile 50 gehört jetzt in das Projekt und Zeile 71 auch. Zeilen 51 und 72 gehören raus. Wir wollen ja auch mit fscanf wieder einlesen und nicht mehr mit fread.



  • Wenn du mit fprintf schreibst, stehen die Zahlen als Text in der Datei. Somit kannst du von der Größe der Datei nicht mehr darauf schließen, wie viele Zahlen jetzt drin stehen.

    <conio.h> und somit auch getch() etc. sind kein standard C.

    Was mir immer noch nicht so ganz klar ist, was soll das Programm überhaupt machen? Es schreibt Zahlen als Text in eine Datei, und liest diese auch wieder aus - aber letzten Endes machst du nichts damit 😕

    (Kommentare über die Einrückung etc. spare ich mir hier mal oO)



  • Ne das sind nur Teilprogramme. Wollte die Fehlermöglichkeiten möglichst klein halten. Das Programm soll auf Wunsch Standardabweichung, Schwankungsbreite und Trendgerade von Werten, aus einer Datei eingelesen, berechnen. Die Datei erstellen wir vorher mit einem anderen Programm.

    Hier ist mal mein aktueller Quellcode:
    Das Problem mit der Dateigröße hat sich auch geklärt.

    #include <stdio.h>		//normale Ein-/Ausgabe
    #include <math.h>		//wegen Wurzel und Quadrat
    #include <conio.h>		// wegen getch()
    #include <eigene.h>		// wegen clrscr()
    #include <string.h>		// wegen Dateiarbeit
    
    void datei(char[]);// unsere einzelnen Funktionen
    void lesen(char[]);	
    void Schwankungsbreite(char[]);
    void arithmetisches_Mittel(char[]);
    void Koeffizienten(char[]);
    void Vergleich_Trendgerade (char[]);
    
    int g;						// Dateigroesse
    double messwert[50];			// Feld für einzelne Messwerte
    
    void main (void)
    {	char name [30];
    	char wahl;
    	datei(name);				// gezwungener Aufruf der Funktion: datei
    	do
    	{
    	 clrscr(); // Bildschirm löschen und dann unser Menü anzeigen
    	 printf ("\t\n\nImportieren der Messwerte aus CSV-Datei.................................1\n");
    	 printf ("\t\n\nBerechnung und Ausgabe der Schwankungsbreite der Messwerte..............2\n");
    	 printf ("\t\n\nBerechnung und Ausgabe des arith. Mittels und der Standardabweichung....3\n");
    	 printf ("\t\n\nBerechnung und Ausgabe der Koeffizienten der Trendgeradenm..............4\n");
    	 printf ("\t\n\nVergleich der tatsaechlichen Messwerte mit der Trendgeraden.............5\n");
    	 printf ("\t\n\nProgrammende ...........................................................E\n");
    	 wahl=getch();
    
    	 switch (wahl)  // Menüauswahl treffen
    	 {
    		case '1':datei(name);break;				
    		case '2':Schwankungsbreite (name);break;
    		case '3':arithmetisches_Mittel (name); break;
    		case '4':Koeffizienten (name); break;
    		case '5':Vergleich_Trendgerade (name); break;
    		case 'E':printf("\nProgrammende\n\n");break;
    		default: printf ("Falsche Eingabe, bitte neu: ");
    		getch();
    	 }
      } while (wahl!='E');
    
    }	
    
    void datei (char name [30])
    {	
    	clrscr();
    	FILE*datei;
    	printf ("\nBitte Namen der einzulesenden CSV-Datei eingeben: ");
    	scanf ("%s",name);
    	datei=fopen(name,"r");
    
    	// Dateigröße ermitteln
    	struct {float a;short b;char c[];}satz;
    	fseek(datei,0,SEEK_END);
    	g=ftell (datei);
    	g=g/sizeof(satz);
    	printf("Dateigroesse: %i daten ",g);
    	// Messwerte einlesen
    	int i;						// Zählervariable
    
    	rewind (datei);				// Dateizegier wieder auf Anfang setzen
    	for (i=0;i<g;i++)
    	{	
    		//fread(&messwert[i],sizeof(float),1,datei);
    		fscanf(datei,"%lf ",&messwert[i]);
    		printf("\nDer %i. Wert betraegt: %lf",i+1,messwert[i]);//brauch man nicht nur zu Kontrolle
    
    	}fclose (datei);
    	getch();
    }// Ende Funktion: datei
    
    // Schwankungsbreite
    void Schwankungsbreite(char name [30])
    {	
    	clrscr();
    	float max,min,diff;
    	int i;
    
    	max=0;
    	for (i=0;i<g;i++)
    	{	
    		if
    		(messwert[i]>max)
    			max=messwert[i];
    		else ;
    	}printf("\nDer maximal Wert betraegt: %lf",max);
    
    	min=max;
    	for (i=0;i<g;i++)
    	{	
    		if
    		(messwert[i]<min)
    			min=messwert[i];
    		else ;
    	}printf("\nDer minimal Wert betraegt: %lf",min);
    		printf("\n\nDie Messwerte schwanken zwischen %lf und %lf.",min, max);
    
    		diff=max-min;
    		printf("\n\nDie Messwerte schwanken um %lf.",diff);
    
    	// Werte in Protokolldatei schreiben
    	{	FILE*fp;
    	fp=fopen ("Protokolldatei.txt","a");
    
    		fprintf (fp,"\nDer maximal Wert betraegt: %lf",max);
    		fprintf (fp,"\nDer minimal Wert betraegt: %lf",min);
    
    	fclose (fp);
    	}getch();
    }
    
    // arithmetisches Mittel und Standardabweichung
    void arithmetisches_Mittel(char name [50])
    {	
    	clrscr();
    	float ergebnis,summe;		// Hilfsvariablen: ergebnis=Arith. Mittel und Summe=Summe aller Messwerte
    	int i;						// Zählervariable
    
    	summe=0;
    	for (i=0;i<g;i++)
    	{	
    	summe+=messwert[i];
    	ergebnis=summe/g;
    	}	
    
    	printf ("\nDas arithmetische Mittel betraegt: %lf\n\n",ergebnis);
    
    	float v[50],z,s;	// v=x-/x; z= Zwischenergebnis nach dem Quadrieren; t= z/(n-1); s=standardabweichung
    	int j;				// Zählervariable
    
    	for (j=0;j<g;j++)
    	z=0;
    	for (i=0;i<g;i++)
    	{
    	v[j]=messwert[i]-ergebnis;		// berechnung von v für jeden einzelnen Messwert
    
    	z=z+pow((v[j]),2);
    	}
    	s=sqrt(z/(g-1));
    
    	printf("Die Standardabweichung betraegt: %lf\n\n",s);
    
    	getch();
    
    	// Werte in Protokolldatei schreiben
    	{	FILE*fp;
    	fp=fopen ("Protokolldatei.txt","a");
    
    		fprintf (fp,"\nDas arithmetische Mittel betraegt: %lf",ergebnis);
    		fprintf (fp,"\nDie Standardabweichung betraegt: %lf",s);
    
    	fclose (fp);
    	}
    }// Ende der Funktion: Arithmetisches Mittel
    
    // Koeffizienten der Trandgeraden
    void Koeffizienten(char name [30])
    {
    }
    
    // Vergleich der Koeffizienten der Trandgeraden
    void Vergleich_Trendgerade(char name [30])
    {
    }
    

    [code]



  • Globale Variablen sind böse 😉
    Wenn die Zahlen eh als Text vorliegen, braucht man kein Programm mehr um sie zu schreiben oder? Geht ja auch mit einem Texteditor. Von dem Menü würde ich auch Abschied nehmen, über Startparameter kann man das eigentlich einfacher regeln. (Ist auch üblicher).

    Einlesen kann man z.B. so machen:

    void read_file(const char *name, double *buf, int size) // Größe des Arrays übergeben, um Überlauf zu vermeiden. Wichtig!
    {
      FILE *file = fopen(name, "r");
      if (!file)
        perror(name), exit(-1);
      while (size-- && 1 == fscanf(file, "%lf ", buf++)) // scanf() gibt die Anzahl der erfolgreich gelesenen Einheiten zurück.
        printf("%lf\n", *(buf - 1)); // hier kannst du auch einfach ein ";" schreiben, das printf dient nur der Überprüfung.
    }
    
    int main(int argc, char *argv[])
    {
      double nums[50];
      if (argc < 2)
        return -1; // Hier würde man dann ausgeben, wie das Programm zu bedienen ist.
      read_file(argv[1], nums, sizeof(nums) / sizeof(*nums));
    }
    


  • Gut,also das mit der Dateigrösse auslesen klappt doch nicht. Es werden mehr Werte eingelesen als in der Datei sind und als 0 angegeben. Weist du warum?



  • eydasgehtab schrieb:

    Gut,also das mit der Dateigrösse auslesen klappt doch nicht. Es werden mehr Werte eingelesen als in der Datei sind und als 0 angegeben. Weist du warum?

    cooky451 schrieb:

    Wenn du mit fprintf schreibst, stehen die Zahlen als Text in der Datei. Somit kannst du von der Größe der Datei nicht mehr darauf schließen, wie viele Zahlen jetzt drin stehen.

    Lies bitte meinen Post oben, du musst die Dateigröße gar nicht auslesen!



  • eydasgehtab schrieb:

    Gut,also das mit der Dateigrösse auslesen klappt doch nicht. Es werden mehr Werte eingelesen als in der Datei sind und als 0 angegeben. Weist du warum?

    Wenn du eine Fließkommazahl mit %f bei printf ausgibst, werden üblicherweise 6 Nachkommstellen angegeben. Dann kommen noch die Vorkommastellen, der Dezimalpunkt und das Leerzeichen dazu. Macht ca. 10 bis 16 Zeichen.

    sizeof(float) ist auf den meisten Systemen 4.

    Mit printf werden die Variablen (meist) in ASCII-Zeichen geschrieben.
    Bei fwrite wird die Variable binär in die Datei geschrieben.



  • Hab jetzt von meinem Dateigröße Auslesen und der For- Schleife danach Abschied genommen. Mach es jetzt nur noch mit einer Do-while-Schleife. und lass dann auch jedes mal g inkrementieren. Funktioniert soweit auch.

    do
    {       i=i+1;
            g=g+1;
            fscanf(datei,"%lf ",&messwert[i]);
            printf("\nDer %i. Wert betraegt: %lf",i+1,messwert[i]);
    }while(!feof(datei));
    


  • Wo ist denn jetzt der Unterschied zwischen i und g ?
    Und warum machst du am Anfang schon i=i+1 ?



  • Hab das noch geändert, ich inkrementier i und g natürlich erst am Ende der Schleife. Der erste Index ist also 0 so wie i auch initialisiert wird. Der Unterschied zwischen i und g ist der, dass i einfach in jeder Funktion als Index des Feldes und als Zählervariable für for- Schleifen genommen wird und somit der Index immer stimmt. g ist global vereinbart und stellt die Anzahl der Messwerte da. Man hätte es bestimmt auch kombinieren können.Aber so funktionierts auch 😉


Anmelden zum Antworten