Like Tree1Danke
  • 1 Beitrag von Matthias Reitinger
ERLEDIGT
JA
ANTWORTEN
11
ZUGRIFFE
1944
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
  1. #1
    WingMan81 ist offline Mitglied
    Registriert seit
    Sep 2009
    Beiträge
    14
    Hallo,

    wie angedroht kommt auch schon mein nächstes Thema

    Dieses mal versuche ich aus einer Textdatei Werte einzulesen.
    Das einlesen mache ich mittels:
    Code c:
    1
    2
    3
    4
    5
    
    int a;
    double b, c, d;
     
    // puffer = Zeile aus Textdatei
    sscanf(puffer,"%i,%lf,%lf,%lf\n",&a, &b, &c, &d);

    puffer ist dabei ein char Array und beinhaltet jeweils eine Zeile aus einer Textdatei.
    Eine Zeile der Textdatei hat das Format:

    Code :
    1
    
    1,2.456,44.5558.16,55544

    Das Problem daran ist nun, dass aus irgendeinem Grund bei mir das "," als Trennzeichen einer Fließkommazahl genommen wird und nicht wie üblich der ".".
    Da die Textdateien aber vorgegeben sind muss ich den "." als Trennzeichen einer Fließkommazahlen behandeln. Ich verstehe auch überhaupt nicht wieso (wie ja doch normal) der Punkt nicht erkannt wird

    Ändere ich die Textdatei in
    Code :
    1
    
    1,2,456,44,5558,16,55544

    dann funktioniert alles und ich bekomme a=1 b= 2.456 c=44.5558 und d=16.55544. Aber wie gesagt: Format der Textdateien ist gegeben und ich kenne es auch von anderen Sprachen (Java,...) nur so das "." als Trennziffer erkannt werden. Laut API soll das ja auch bei C so sein. Seltsam, nicht wahr

    Hoffe ihr könnt mir wieder einmal helfen

    Viele Grüße und noch einen schönen Rest-Sonntag,
    WingMan
    Geändert von WingMan81 (27.09.09 um 16:12 Uhr)
     

  2. #2
    Avatar von saftmeister
    saftmeister ist offline Nutze den Saft!
    tutorials.de Premium-User
    Registriert seit
    May 2006
    Ort
    There is no place like 127.0.0.1
    Beiträge
    4.578
    Jaja, das liebe sscanf. Das hat mir auch schon den ein oder andern Arbeitstag versüßt

    Nein im Ernst. Ich bin dazu übergegangen, diese Hilfsfunktionen nicht zu verwenden, stattdessen mittels Pointer über die Zeile zu sausen und bedingungsbehaftet dann die Werte in Strukturen oder simple Variablen zu parsen. Das ist zwar nicht so elegant wie sscanf aber zuverlässig:

    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    /* Zeiger auf den Anfang der Zeile */
    char *p = puffer;
    char *part = puffer;
    char value[4][20];
    int i = 0;
    do{
      if(*p == ',')
      {
         *p = 0;
         strcpy(value[i], part);
         i++;
         p++;
         part = p;
         continue;
      }
      p++;
      if(*p == 0) break;
    } while(p != NULL);

    Anschließend kannst du mit value[0] - [3] alles tun, was du willst. Es ist außerdem noch relativ schnell. Sicherlich kann man dies auch noch optimieren.
     
    Grüße
    --
    Qualität des Codes wird in WTF's/Min gemessen: Je mehr, desto schlechter der Code ;-)

  3. #3
    WingMan81 ist offline Mitglied
    Registriert seit
    Sep 2009
    Beiträge
    14
    Hi,
    vielen Dank für Deine Antwort! Ich werde das auf jeden Fall auch mal so austesten, aber verstehen möchte ich doch ganz gern warum meine Lösung nicht so funktioniert wie sie es doch eigentlich sollte.
    Das ganze für mich ja mehr eine Übungsaufgabe und weniger für einen Produktiveinsatz gedacht, daher suche ich natürlich weiter nach der Auflösung

    Aber wie gesagt: Vielen Dank für Deine Antwort!

    VG,
    WingMan
     

  4. #4
    Registriert seit
    Dec 2001
    Ort
    Bayern
    Beiträge
    5.785
    Zitat Zitat von WingMan81 Beitrag anzeigen
    Das Problem daran ist nun, dass aus irgendeinem Grund bei mir das "," als Trennzeichen einer Fließkommazahl genommen wird und nicht wie üblich der ".".
    Da die Textdateien aber vorgegeben sind muss ich den "." als Trennzeichen einer Fließkommazahlen behandeln. Ich verstehe auch überhaupt nicht wieso (wie ja doch normal) der Punkt nicht erkannt wird
    Welche Formate bei der Ein- und Ausgabe verwendet werden, hängt von der gesetzten „Locale“ ab. Diese kann mit setlocale geändert werden. Einen Punkt als Dezimaltrennzeichen erhält man beispielsweise mit der Locale "C".

    Grüße, Matthias
    saftmeister bedankt sich. 
    „Gib einem Menschen einen Fisch, und er wird für einen Tag satt. Lehre ihn Fischen, und er wird ein Leben lang satt.“
    “For every complex problem, there is an answer that is short, simple and wrong.”
    “Pessimism is safe, but optimism is a lot faster!”

  5. #5
    Avatar von saftmeister
    saftmeister ist offline Nutze den Saft!
    tutorials.de Premium-User
    Registriert seit
    May 2006
    Ort
    There is no place like 127.0.0.1
    Beiträge
    4.578
    Danke für den Hinweis mit der Locale. Daran habe ich gar nicht gedacht. Noch ein Grund mehr, auf glibc-Funktionen zu verzichten, wenn man multi-linguale Applikationen entwickelt und darin Zeilen parsen muss. Vielen Dank, nun weiß ich wenigstens den Grund für mein Gefühl, es zu Fuss implementieren zu müssen.
     
    Grüße
    --
    Qualität des Codes wird in WTF's/Min gemessen: Je mehr, desto schlechter der Code ;-)

  6. #6
    deepthroat ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Jun 2005
    Beiträge
    8.731
    Hi.
    Zitat Zitat von saftmeister Beitrag anzeigen
    Danke für den Hinweis mit der Locale. Daran habe ich gar nicht gedacht. Noch ein Grund mehr, auf glibc-Funktionen zu verzichten, wenn man multi-linguale Applikationen entwickelt und darin Zeilen parsen muss.
    Ich finde zu ziehst die falschen Schlüsse. Das heißt nur, das man in Konfigurationsdateien bzw. Datendateien die Standardlocale verwenden sollte und nicht lokalisierte Daten abspeichert.

    Abgesehen davon ist deine Funktion fehlerhaft. Wie sollte denn p plötzlich NULL sein können (vor allem nachdem du es schon x-mal verwendet hast)? Außerdem kann es passieren, dass du über das Ende des Strings hinaus liest. Ein schönes Beispiel dafür, das man doch lieber die Funktionen der C Bibliothek (richtig) anwenden sollte bevor man sich was selber bastelt.

    @WingMan81: Um herauszufinden welche Locale gerade aktiv ist, kannst du setlocale aufrufen:
    Code c:
    1
    
    puts(setlocale(LC_NUMERIC, NULL));
    Gruß
     
    If at first you don't succeed, try again. Then quit. No use being a damn fool about it.

  7. #7
    WingMan81 ist offline Mitglied
    Registriert seit
    Sep 2009
    Beiträge
    14
    Hallo,

    vielen Dank für die Antworten! Das setlocal() wirkt wahre Wunder Es funktioniert nun alles so wie es soll!

    Viele Grüße
    WingMan
     

  8. #8
    Avatar von saftmeister
    saftmeister ist offline Nutze den Saft!
    tutorials.de Premium-User
    Registriert seit
    May 2006
    Ort
    There is no place like 127.0.0.1
    Beiträge
    4.578
    Zitat Zitat von deepthroat Beitrag anzeigen
    Hi.
    Ich finde zu ziehst die falschen Schlüsse. Das heißt nur, das man in Konfigurationsdateien bzw. Datendateien die Standardlocale verwenden sollte und nicht lokalisierte Daten abspeichert.
    Geschenkt. Brauch man nicht drüber zu diskutieren. Was mach ich aber mit Daten-Dateien, die bereits lokalisiert gespeichert wurden?

    Abgesehen davon ist deine Funktion fehlerhaft. Wie sollte denn p plötzlich NULL sein können (vor allem nachdem du es schon x-mal verwendet hast)?
    Ebenfalls geschenkt. Als Schleifen-Abbruch-Bedingung hätte ich ebenso 1 wählen können.
    Außerdem kann es passieren, dass du über das Ende des Strings hinaus liest.
    Mag sein, das ich was übersehe. Aber ich prüfe doch

    Code cpp:
    1
    
    if(*p == 0) break;

    Sollte das nicht genügen, wenn ich davon ausgehen darf, das der puffer Null-terminiert ist? Was übersehe ich?
     
    Grüße
    --
    Qualität des Codes wird in WTF's/Min gemessen: Je mehr, desto schlechter der Code ;-)

  9. #9
    deepthroat ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Jun 2005
    Beiträge
    8.731
    Zitat Zitat von saftmeister Beitrag anzeigen
    Geschenkt. Brauch man nicht drüber zu diskutieren. Was mach ich aber mit Daten-Dateien, die bereits lokalisiert gespeichert wurden?
    Du könntest die Daten entsprechend konvertieren.
    Zitat Zitat von saftmeister Beitrag anzeigen
    Ebenfalls geschenkt. Als Schleifen-Abbruch-Bedingung hätte ich ebenso 1 wählen können.
    Oder du hättest es auch einfach vernünftig programmieren können...
    Zitat Zitat von saftmeister Beitrag anzeigen
    Mag sein, das ich was übersehe. Aber ich prüfe doch

    Code cpp:
    1
    
    if(*p == 0) break;

    Sollte das nicht genügen, wenn ich davon ausgehen darf, das der puffer Null-terminiert ist? Was übersehe ich?
    Du springst über die Abfrage mit continue drüber. Schlechter Programmierstil break und continue zu benutzen obwohl absolut nicht notwendig.

    Gruß
     
    If at first you don't succeed, try again. Then quit. No use being a damn fool about it.

  10. #10
    Avatar von saftmeister
    saftmeister ist offline Nutze den Saft!
    tutorials.de Premium-User
    Registriert seit
    May 2006
    Ort
    There is no place like 127.0.0.1
    Beiträge
    4.578
    So besser?

    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    
    /* Zeiger auf Puffer-Anfang setzen */
    char *p = puffer;
    char *part = puffer;
     
    /* Result-Puffer */
    char value[4][20];
     
    /* Count-Variable */
    int i = 0;
     
    /* Solange Ende des Null-terminierten Puffers nicht erreicht */
    while(*p != 0)
    {
      /* Wenn Komma gefunden */
      if(*p == ',')
      {
        /* Terminiere Teil von part bis Komma */
        *p = 0;
        
        /* Kopiere Teil in Result-Variable */
        strcpy(value[i++], part);
        
        /* Setze neuen Part-Anfang aktuelle Position + 1 (nach 0-Terminator) */
        part = p+1;
      }
      
      /* Inkrementiere Zeiger */
      p++;
    }

    Das war einfach so schnell hingeschludert als Möglichkeit das Problem zu lösen. Zugegeben, es ist nicht sehr schön. Aber es hat mein Problem damals gelöst.
     
    Grüße
    --
    Qualität des Codes wird in WTF's/Min gemessen: Je mehr, desto schlechter der Code ;-)

  11. #11
    deepthroat ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Jun 2005
    Beiträge
    8.731
    Zitat Zitat von saftmeister Beitrag anzeigen
    So besser?
    Ja.

    Außer das man solche Kommentare wie
    Zitat Zitat von saftmeister Beitrag anzeigen
    Code c:
    1
    2
    
      /* Inkrementiere Zeiger */
    p++;
    besser weglassen sollte. Das dort der Zeiger inkrementiert wird, sieht man schließlich auch so.

    Gruß
    Geändert von deepthroat (28.09.09 um 20:10 Uhr)
     
    If at first you don't succeed, try again. Then quit. No use being a damn fool about it.

  12. #12
    Registriert seit
    Dec 2001
    Ort
    Bayern
    Beiträge
    5.785
    Zitat Zitat von saftmeister Beitrag anzeigen
    So besser?
    Alternativ-Vorschlag:
    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    
    char value[4][20];
    int i = 0;
    char *part = strtok(puffer, ",");
    while (part != NULL)
    {
      strcpy(value[i++], part);
      part = strtok(NULL, ",");
    }

    Grüße, Matthias
     
    „Gib einem Menschen einen Fisch, und er wird für einen Tag satt. Lehre ihn Fischen, und er wird ein Leben lang satt.“
    “For every complex problem, there is an answer that is short, simple and wrong.”
    “Pessimism is safe, but optimism is a lot faster!”

Ähnliche Themen

  1. Pattern von Fließkommazahlen
    Von Duckemai im Forum Algorithmen & Datenstrukturen mit Java
    Antworten: 5
    Letzter Beitrag: 10.08.10, 16:25
  2. Rechnen mit Fließkommazahlen
    Von Thomas Darimont im Forum Java
    Antworten: 3
    Letzter Beitrag: 06.03.06, 08:07
  3. zufallszahl zwischen 2 Fließkommazahlen
    Von Philipp_Frank im Forum PHP
    Antworten: 6
    Letzter Beitrag: 20.10.05, 23:07
  4. Fließkommazahlen
    Von c-hilgert im Forum C/C++
    Antworten: 2
    Letzter Beitrag: 09.06.04, 10:02
  5. sscanf in C#
    Von jccTeq im Forum .NET Archiv
    Antworten: 3
    Letzter Beitrag: 25.03.04, 15:59