[GELÖST] Zahlen mit Dezimalpunkt aus Datei einlesen



  • Hallo Leute,

    probiere jetzt schon seit Stunden und kriege es nicht hin...

    ich habe eine Datei mit folgendem Inhalt:

    1.000000 2.000000
    3.000000 4.000000
    5.000000 6.000000
    

    Jetzt will ich die Zahlen in ein double Array schreiben...

    Habe es so versucht:

    file = fopen(dateiName, "r");
    
    while ((fscanf(file, "%lf %lf", &readX, &readY)) != feof){
    	werteX[counter] = readX;
    	werteY[counter] = readY;
    
    	printf("\n%.2lf; %.2lf; %.2lf; %.2lf; %i", readX, werteX[counter], readY, werteY[counter], counter);		
    
    	counter++;
    }
    

    Allerdings ist der Output:

    1.00; 1.00; -92559631349317831000000000000000000000000000000000000000000000.00;
    -92559631349317831000000000000000000000000000000000000000000000.00; 0
    1.00; 1.00; -92559631349317831000000000000000000000000000000000000000000000.00;
    -92559631349317831000000000000000000000000000000000000000000000.00; 1
    1.00; 1.00; -92559631349317831000000000000000000000000000000000000000000000.00;
    -92559631349317831000000000000000000000000000000000000000000000.00; 2
    1.00; 1.00; -92559631349317831000000000000000000000000000000000000000000000.00;
    -92559631349317831000000000000000000000000000000000000000000000.00; 3
    1.00; 1.00; -92559631349317831000000000000000000000000000000000000000000000.00;
    -92559631349317831000000000000000000000000000000000000000000000.00; 4
    1.00; 1.00; -92559631349317831000000000000000000000000000000000000000000000,00;
    -92559631349317831000000000000000000000000000000000000000000000.00; 5
    1.00; 1.00; -92559631349317831000000000000000000000000000000000000000000000.00;
    -92559631349317831000000000000000000000000000000000000000000000.00; 6
    

    Irgendwie krieg ich das nicht hin! Der ließt irgendwir auch mehr Zeilen ein als wirklich vorhanden sind... Wo liegt mein Fehler?

    Kann mir jemand einen Tipp geben?



  • Falsche Benutzung von feof.

    feof ist eine Funktion. Aber auch das Makro EOF wäre hier falsch.
    Teste auf die richtige Anzahl erfolgreich gelesener Elemente:

    while ((fscanf(file, "%lf %lf", &readX, &readY)) == 2){
    ....
    

    Bleibt die Frage, warum dein System das , als Dezimaltrenner hat.
    Hast du an der locale rum gebastelt?



  • DirkB schrieb:

    Falsche Benutzung von feof.

    feof ist eine Funktion. Aber auch das Makro EOF wäre hier falsch.
    Teste auf die richtige Anzahl erfolgreich gelesener Elemente:

    while ((fscanf(file, "%lf %lf", &readX, &readY)) == 2){
    ....
    

    Bleibt die Frage, warum dein System das , als Dezimaltrenner hat.
    Hast du an der locale rum gebastelt?

    Okay, werde ich ausprobieren! Warum geht es den hier nicht mit EOF? Hatte das nämlich als erstes und habe dann auch festgestellt das es nicht geht!

    Das mit der Locale hatte ich auch schon gemerkt und geändert hatte hier nur die alte txt gepostet... da sind eigentlich Punkte statt Kommas! Hatte aber trotzdem nicht geholfen! der liest nicht beide Zahlen ein!



  • ph87 schrieb:

    Warum geht es den hier nicht mit EOF?

    Weil noch Daten in der Datei drin stehen. Allerdings kann fscanf (mit den gegebenen Formatspecifiern) damit nichts anfangen.

    Das Problem bei dir tritt nach der 1 (von der 1.00000) auf. Danach kann fscanf mit den Zeichen (. oder ,)* nichts mehr anfangen und gibt eine 1 zurück. readY wird nicht geändert.
    Beim nächsten Aufruf steht immer noch das Zeichen (mit dem fscanf nichts anfangen kann) im Eingabestrom und gibt 0 zurück. readX und readY bleiben unverändert.

    So erreichst du nie das Dateiende. Also auch kein EOF.

    Ändere mal deine Eingabedatei in

    3.141 2.000000
    3.000000 4.000000
    5.000000 6.000000
    

    und schau nach, ob in deiner Ausgabe überhaupt eine 3 in der ersten Zahl ist. Und ob Nachkommstellen vorhanden sind.

    *Meine Vermutung, da du in deinem Ursprungspost bei der Ausgabe noch ein Dezimalkomma hattest.



  • okay, habe es jetzt noch mal probiert...

    Textdatei:

    3.140000 3.240000
    2.000000 3.000000
    4.000000 5.000000
    

    Ausgabe:

    3.00; 3.00; -92559631349317831000000000000000000000000000000000000000000000.00;
    -92559631349317831000000000000000000000000000000000000000000000.00; 0
    3.00; 3.00; -92559631349317831000000000000000000000000000000000000000000000,00;
    -92559631349317831000000000000000000000000000000000000000000000.00; 1
    3.00; 3.00; -92559631349317831000000000000000000000000000000000000000000000,00;
    -92559631349317831000000000000000000000000000000000000000000000.00; 2
    3.00; 3.00; -92559631349317831000000000000000000000000000000000000000000000,00;
    -92559631349317831000000000000000000000000000000000000000000000.00; 3
    3.00; 3.00; -92559631349317831000000000000000000000000000000000000000000000,00;
    -92559631349317831000000000000000000000000000000000000000000000.00; 4
    3.00; 3.00; -92559631349317831000000000000000000000000000000000000000000000,00;
    -92559631349317831000000000000000000000000000000000000000000000.00; 5
    

    Wenn ich

    while ((fscanf(file, "%lf %lf", &readX, &readY)) == 2){}
    

    dies probiere macht der nichts... scheint die Schleife zu überspringen!



  • Wenn ich

    while ((fscanf(file, "%lf %lf", &readX, &readY)) == 2){}
    

    dies probiere macht der nichts... scheint die Schleife zu überspringen!
    Das fscanf macht er einmal. Allerdings liefert dies 1 zurück und somit wird der Schleifenkörper nicht ausgeführt.

    Die 3 von der 3.14 wird eingelesen. Mit dem . kann fscanf dann nichts mehr anfangen.

    Auf was für einem System und mit welchem Compiler versuchst du das?
    Womit hast du die Textdatei erstellt?



  • DirkB schrieb:

    Wenn ich

    while ((fscanf(file, "%lf %lf", &readX, &readY)) == 2){}
    

    dies probiere macht der nichts... scheint die Schleife zu überspringen!
    Das fscanf macht er einmal. Allerdings liefert dies 1 zurück und somit wird der Schleifenkörper nicht ausgeführt.

    Die 3 von der 3.14 wird eingelesen. Mit dem . kann fscanf dann nichts mehr anfangen.

    Auf was für einem System und mit welchem Compiler versuchst du das?
    Womit hast du die Textdatei erstellt?

    Vielen Dank erstmal für deine Hilfe Dirk!!!

    Ja da hätte ich auch drauf kommen können... 😉

    Ich arbeite mit VS2013 unter Win 8.1

    Also so werden die Daten geschrieben:

    file = fopen(dateiName, "w+");
    	for (counter = 0; counter < anzahl; counter++){
    		fprintf(file, "%lf %lf\n", werteX[counter], werteY[counter]);
    	}
    
    	fclose(file);
    

    Wie könnte man das sonst lösen, wenn fscanf vielleicht für diesen Fall ungeeignet ist? (Habe allerdings ein paar Beispiele auf google gefunden wo es angeblich aber gehen soll siehe z.B. http://www.tutorials.de/c-c/364648-zahlen-aus-datei-array-eintragen-programmiersprache-c.html... 🙄 )

    Mit fgetc und dann alles umwandeln? Gehts auch einfacher?



  • Merkwürdig - und Du änderst wirklich nix mehr am locale oder so?

    Leider hast Du bisher kein komplettes minimales Beispiel gebracht, das den Fehler aufweist.

    Hier mal ein kompletter round-trip(Array, FILE, Array), der tut auch bei Dir tadellos?

    #include <stdio.h>
    #include <string.h>
    
    void clear(double *s, size_t n){
      memset(s, 0, n*sizeof(double));
    }
    
    void write_to_file(FILE *f, const double *vx, const double *vy, size_t n){
      while(n--)
        fprintf(f, "%f %f\n", *vx++, *vy++);
    }
    void write(const char *filename, const double *vx, const double *vy, size_t n){
      FILE *f = fopen(filename, "w");
      if(!f)
        return;
      write_to_file(f, vx, vy, 3);
      fclose(f);
    }
    
    void read_from_file(FILE *f, double *vx, double *vy, size_t n){
      while(n--
        && fscanf(f, "%lf %lf", vx++, vy++)==2) /* loop */ ;
    }
    
    void read(const char *filename, double *vx, double *vy, size_t n){
      FILE *f = fopen(filename, "r");
      if(!f)
        return;
      read_from_file(f, vx, vy, 3);
      fclose(f);
    }
    
    int main(){
      const char filename[]="test.dat";
      double vx[] = { 1.23, 4.56, 7.89 };
      double vy[] = { 9.87, 6.54, 3.21 };
      write(filename, vx, vy, 3);
      clear(vx, 3);
      clear(vy, 3);
      read(filename, vx, vy, 3);
      write_to_file(stdout, vx, vy, 3);
    }
    


  • read und write kommen zwar nicht im C-Standard vor, jedoch sind es POSIX Funktionen.
    Daher halte ich die Namenswahl für sehr unglücklich.

    read_from_file könnte ruhig n zurück geben.

    Tausche 3 gegen n in Zeile 16 und 29



  • DirkB schrieb:

    Tausche 3 gegen n in Zeile 16 und 29

    Ja, das ist ein copy und paste Fehler.



  • Du schreibst mit fprintf unter einer anderen locale als du mit fscanf liest, und das ist dein ganzes Problem.



  • So, vielen vielen Dank euch!!! Habe irgendwo in einer .c datei doch noch ein setlocale gefunden... 🙄
    Danke für die Hinweise!!!

    Habe jetzt aber ein anderes Problem wenn ich versuche mein Array dynamisch zu lassen bekomme ich beim 2. aufruf von hauptmenue einen Fehler...

    Beim ersten aufruf von hauptmenue()wird das array beliebig vergrößert und in der Ausgabe steht auch das richtige drin... wenn ich das hauptmenue() das 2. mal aufrufe bricht das programm ab (in Zeile 82)!

    //main
    int main(void)
    {
    	double *werteX = NULL;
    	double *werteY = NULL;
    
    	werteX = calloc(5, sizeof(double));
    	werteY = calloc(5, sizeof(double));
    
    	hauptmenue(werteX, werteY);
    
    }
    
    //hauptmenue
    void hauptmenue(double *werteX, double *werteY){
    	int auswahl, anzahl = 0;
    
    	do{
    		//system("cls");
    		printf("\n"
    			"Berechnung einer Ausgleichsgeraden\n"
    			"==================================\n"
    			"(1) Daten aufnehmen\n"
    			"(2) Daten ausgeben\n"
    			"(3) Daten korrigieren\n"
    			"(4) Daten speichern\n"
    			"(5) Daten laden\n"
    			"(6) Ausgleichsgerade ermitteln\n"
    			"(0) Ende\n"
    			"\n"
    			"Treffen Sie eine Wahl: "		
    			);
    
    		scanf("%i", &auswahl);
    		while (getchar() != '\n');
    
    		switch (auswahl){
    		case 1: anzahl = menue1(werteX, werteY); break; 
    		case 2: menue2(werteX, werteY, anzahl); break;
    		case 3: menue3(werteX, werteY, anzahl); break;
    		case 4: menue4(werteX, werteY, anzahl); break;
    		case 5: anzahl = menue5(werteX, werteY); break;
    		case 6: menue6(werteX, werteY, anzahl); break;
    		default: break;  
    		}
    
    	} while (auswahl != 0);
    
    }
    
    //Menü Daten aufnehmen 
    int menue1(double *werteX, double *werteY){
    	int counter = 0;
    
    	double *test1, *test2;
    
    	printf("\n"
    		"(1) Daten aufnehmen: (Ende ersten Punkt noch einmal eingeben)\n"
    		"____________________\n"
    		"\n");
    
    	do{	
    		//X-Koordinate einlesen	
    		printf("%i. Punkt: x: ", counter + 1);
    		scanf("%lf", &werteX[counter]);
    		while (getchar() != '\n');
    
    		//Y-Koordinate einlesen	
    		printf("%i. Punkt: y: ", counter + 1);
    		scanf("%lf", &werteY[counter]);
    		while (getchar() != '\n');
    
    		counter++;
    
    		printf("\n%i; %i\n", counter, ARRAYSIZE);
    
    		if (counter == 4){
    			test1 = realloc(werteX, (counter + 1) * sizeof(double));
    			test2 = realloc(werteY, (counter + 1) * sizeof(double));
    
    			if (test1 != NULL && test2 != NULL){
    				werteX = test1;
    				werteY = test2;
    			}
    
    		}
    
    	} while (counter <= 1 || werteX[0] != werteX[counter - 1] || werteY[0] != werteY[counter - 1]);
    
    	return counter - 1;
    }
    


  • werteX und werteY sind lokale Variblen in menu1.
    Wenn du denen neue Werte zuweist, bekommt hauptmenu davon nichts mit.



  • DirkB schrieb:

    werteX und werteY sind lokale Variblen in menu1.
    Wenn du denen neue Werte zuweist, bekommt hauptmenu davon nichts mit.

    Wieso sind die Lokal? Ich übergebe doch im Parameter den Pointer also muss du adresse bekannt sein! Und die Adresse ändere ich ja auch im Pointer... Oder was verstehe ich da falsch?

    Wie kann ich die Adressen von werteX und werteY dann dem hauptmenue() wieder mitteilen?



  • ph87 schrieb:

    Wieso sind die Lokal? Ich übergebe doch im Parameter den Pointer also muss du adresse bekannt sein!

    Normale Funktionsparameter:
    Ich gebe dir einen Zettel, auf denen der Wert steht, mit dem du arbeiten sollst.
    Jetzt kannst du auf dem Zettel rumändern was du willst, das bekomme ich nicht mit.

    Mit Zeigern als Parameter:
    Ich gebe dir einen Zettel, auf denen der Ort notiert ist, wo du den Wert findest.
    Jetzt kannst du den Wert ändern. Da ich auch weiss wo dieser Ort ist, bekomme ich die Änderung mit.
    Den Zettel sehe ich aber auch nicht.

    Du besorgst dir jetzt aber einen andern Ort (mit dem realloc) und notierst das auf dem Zettel. 👎

    ph87 schrieb:

    Wie kann ich die Adressen von werteX und werteY dann dem hauptmenue() wieder mitteilen?

    Du musst die Adresse der Pointer übergeben.
    😕 😮
    Ja, die Adresse der Pointer. Dann hast du sog. Doppelzeiger
    (Ich gebe dir einen Zettel, auf denen den Ort notiert ist, wo ich den Ort des Wertes notiert habe.)

    int main(void)
    {
        double *werteX = NULL;
        double *werteY = NULL;
    
        werteX = calloc(5, sizeof(double));
        werteY = calloc(5, sizeof(double));
    
        hauptmenue(&werteX, &werteY, 5);  // Adressen von den Pointern übergeben     
    }
    
    //hauptmenue
    void hauptmenue(double **werteX, double **werteY, size_t anzahl ){
        int auswahl, anzahl = 0;
    
        do{
    ...  
            switch (auswahl){
            case 1: anzahl = menue1(werteX, werteY,anzahl ); break;  // hier hast du schon den richtigen Typ
    ....}
    
    //Menü Daten aufnehmen
    int menue1(double **werteX, double **werteY,size_t anzahl ){// auch hier Adressen von den Pointern übergeben  
    ....   
               test1 = realloc(*werteX, (counter + 1) * sizeof(double));  
                 if (test1 != NULL && test2 != NULL){
                    *werteX = test1;  // einmal dereferenzieren, wenn du die Adresse vom Array willst
    .....
    }
    

    Oder du baust werteX, werteY und die Anzahl in eine struct und gibst diese als Rückgabewert zurück.



  • Danke, das habe ich jetzt so weit verstanden!!!

    So sieht es jetzt bei mir aus!!!

    Habe alles übernommen wie du meintest,... allerdings kriege ich immer sobald er in die if-Schleife mit den realloc Zeilen springt einen Fehler:

    Ausnahmefehler bei 0x0FA0B2CE (msvcr120d.dll) in Ausgleichsgerade.exe: 0xC0000005: Zugriffsverletzung beim Lesen an Position 0x4017FFFC
    

    Sind die test1 & test2 variablen richtig deklariert? (Zeile 58)

    Und wie bekomme ich jetzt mit dem scanf die eingelesenen Werte in das Array? (Zeilen 67-74)

    //main
    int main(void)
    {
    	double *werteX = NULL;
    	double *werteY = NULL;
    
    	werteX = calloc(ARRAYSIZE, sizeof(double));
    	werteY = calloc(ARRAYSIZE, sizeof(double));
    
    	hauptmenue(&werteX, &werteY);
    
    }
    
    //Hauptmenü
    void hauptmenue(double **werteX, double **werteY){
    	int auswahl, anzahl = 0;
    
    	do{
    
    		printf("\n"
    			"Berechnung einer Ausgleichsgeraden\n"
    			"==================================\n"
    			"(1) Daten aufnehmen\n"
    			"(2) Daten ausgeben\n"
    			"(3) Daten korrigieren\n"
    			"(4) Daten speichern\n"
    			"(5) Daten laden\n"
    			"(6) Ausgleichsgerade ermitteln\n"
    			"(0) Ende\n"
    			"\n"
    			"Treffen Sie eine Wahl: "		
    			);
    
    		scanf("%i", &auswahl);
    		while (getchar() != '\n');
    
    		switch (auswahl){
    		case 1: anzahl = menue1(&werteX, &werteY); break; 
    		case 2: menue2(werteX, werteY, anzahl); break;
    		case 3: menue3(werteX, werteY, anzahl); break;
    		case 4: menue4(werteX, werteY, anzahl); break;
    		case 5: anzahl = menue5(werteX, werteY); break;
    		case 6: menue6(werteX, werteY, anzahl); break;
    		default: break; 
    		}
    
    	} while (auswahl != 0);
    
    }
    
    //Menü Daten aufnehmen 
    int menue1(double **werteX, double **werteY){
    	int counter = 0;
    
    	double *test1, *test2;
    
    	printf("\n"
    		"(1) Daten aufnehmen: (Ende ersten Punkt noch einmal eingeben)\n"
    		"____________________\n"
    		"\n");
    
    	do{	
    		//X-Koordinate einlesen	
    		printf("%i. Punkt: x: ", counter + 1);
    		scanf("%lf", &werteX[counter]);
    		while (getchar() != '\n');
    
    		//Y-Koordinate einlesen	
    		printf("%i. Punkt: y: ", counter + 1);
    		scanf("%lf", &werteY[counter]);
    		while (getchar() != '\n');
    
    		counter++;
    
    		if (counter >= ARRAYSIZE){
    			test1 = realloc(*werteX, (counter + 1) * sizeof(double));
    			test2 = realloc(*werteY, (counter + 1) * sizeof(double));
    
    			if (test1 != NULL && test2 != NULL){
    
    				*werteX = test1;
    				*werteY = test2;
    			}
    
    		}
    
    	} while (counter <= 1 || werteX[0] != werteX[counter - 1] || werteY[0] != werteY[counter - 1]);
    
    	return counter - 1;
    }
    


  • 1. es gibt keine if-Schleife

    2. was sagt dein Compiler zu Zeile 69 und 74?
    Nichts? Dann hast du falsche Einstellungen bezüglich der Warnungen.

    scanf möchte bei %lf einen Zeiger auf double haben.

    werteX ist ein double**
    werteX[i] ist ein double*
    &werteX[i] ist jedenfalls nicht dass, was du möchtest.

    Nicht probieren, genau überlegen. (werteX[i] ist es auch nicht)
    Wenn du dir über die Reihenfolge nicht sicher bist, mach Klammern.



  • Ja, es gibt keine If- Schleife!!! keine Ahnung warum ich Schleife geschrieben habe...

    Ich habe schon viele Programme geschrieben allerdings habe ich noch nie diese Doppel Zeiger gebraucht... Haben das im Techniker leiderauch nicht angesprochen und habe deswegen auch so meine Probleme damit!

    Sind die test variablen denn richtig deklariert?
    Wie wäre es dann richtig mit dem scanf?
    so?

    scanf("%lf",*werteX++);
    

    Tut mit leid stehe irgendwie auf dem Schlauch!



  • Habe es jetzt auch so versucht:

    scanf("%lf", &(*werteX)[counter]);
    

    Das geht aber nur im ersten durchgang! Im 2. verändert sich nichts! Ich sehe auch im debugger, dass der Wert sich nicht ändert!



  • ph87 schrieb:

    Habe es jetzt auch so versucht:

    scanf("%lf", &(*werteX)[counter]);
    

    Das geht aber nur im ersten durchgang! Im 2. verändert sich nichts! Ich sehe auch im debugger, dass der Wert sich nicht ändert!

    Welcher zweite Durchgang? Meinst du, wenn counter = 1 ist?
    Da du ja bis ARRAYSIZE alles schon in eienm Speicherbereich hast, sollten sich die Adressen um sizof(double) unterscheiden.

    printf("werteX: %p | *werteX %p | &(*werteX)[counter] %p | counter %d\n", werteX, *werteX, &(*werteX)[counter], counter);
    

    Sonst kannst du auch &werteX[0][counter] oder *werteX+counter nehmen.

    Ach, gerade noch gesehen:
    Schau mal, wie ich menu1 (am 20:35:47 06.03.2014) aufrufe,

    case 1: anzahl = menue1(werteX, werteY,anzahl ); break;  // hier hast du schon den richtigen Typ
    

    und wie du das machst:

    case 1: anzahl = menue1(&werteX, &werteY); break;
    

    Und ich meine nicht anzahl.
    Auch da muss dich der Compiler warnen!
    Wenn keine Warnung kommt, stell den Warnlevel anders ein.
    Wenn du die Warnungen wiederholt ignorierst, dann wundere dich nicht, wenn dein Programm nicht funktioniert.


Log in to reply