tutorials.de Buch-Aktion 05/2012
Seite 1 von 2 12 LetzteLetzte
ERLEDIGT
JA
ANTWORTEN
18
ZUGRIFFE
561
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    Avatar von javaDeveloper2011
    javaDeveloper2011 javaDeveloper2011 ist offline Mitglied Brokat
    Registriert seit
    Feb 2011
    Beiträge
    443
    Blog-Einträge
    5
    Hallo,

    ich möchte gerne drei Double-Variablen hintereinander korrekt einlesen.
    Dabei giebt es leider einige Probleme:
    • cin.fail() reagiert nicht, bei:
      • "5000hgh", hier würde einfach "5000" eingelesen und "hgh" kommt gleich in die nächst Variable, wo dann der Fehler auftritt
      • "fhzf400", hier wird für das aktuelle Einlesen ein Fehler gemeldet, jedoch gets gleich weiter zur nächsten Variablen, die dann "400" zugewiesen bekommt, der User hat damit keine Changese mehr den ersten Wert zu berichtigen
      ("5000hgh" und "fhzf400" sind natürlich nur Beispiele dafür, dass an Anfang oder Ende ein korrekter double-Wert steht, aber trotzdem ein logischer Fehler vorliegt)
    • Soweit ich das verstanden hab, setzt
      Code cpp:
      1
      
      cin.clear();
      (nur) die Fehler-Flags zurück.?
      cin.get() und cin.sync() hab ich immer wieder an allen möglichen stellen eingesetzt und rausgenommen, wo wäre das jetzt eigentlich sinfoll?
    • Ich würde gerne das Komma als Dezimaltrennzeichen verwenden, unter Linux funktioniert das mit
      Code cpp:
      1
      
      cin.imbue(locale("de_DE.uft-8"));
      und
      Code cpp:
      1
      
      fout.imbue(locale("de_DE.uft-8"));
      Bei Windows hingegen hilft auch stundenlanges googeln nichts.
    • Noch was:
      eingetlich möchte ich auch das man das Programm zu jeder Zeit per ESC-Druck beenden kann, da es in einer Endlosschleife läuft. Falls irgendwie möglich, sollte zu Anfang das Komandozeilenfenster gecleart werden, nicht bloß runterscrollen oder Leerzeilen schreiben!
      Beides selbstverständlich für Linux, Windows, Mac und auch ältere Versionen, sonst macht das ganze für mich keinen Sinn.

    Freue mich sehr auf eure Hilfe, weil ich hier mittlerweile am verzweifeln bin,
    javaDeveloper2011
     

  2. #2
    deepthroat deepthroat ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Jun 2005
    Beiträge
    8.168
    Hi.
    Zitat Zitat von javaDeveloper2011 Beitrag anzeigen
    ich möchte gerne drei Double-Variablen hintereinander korrekt einlesen.
    Dabei giebt es leider einige Probleme:[LIST][*]cin.fail() reagiert nicht, bei:[LIST][*]"5000hgh", hier würde einfach "5000" eingelesen und "hgh" kommt gleich in die nächst Variable, wo dann der Fehler auftritt
    Das ist doch völlig OK, oder nicht?
    Zitat Zitat von javaDeveloper2011 Beitrag anzeigen
    [*]"fhzf400", hier wird für das aktuelle Einlesen ein Fehler gemeldet, jedoch gets gleich weiter zur nächsten Variablen, die dann "400" zugewiesen bekommt, der User hat damit keine Changese mehr den ersten Wert zu berichtigen
    Das liegt aber dann an deinem Code.
    Zitat Zitat von javaDeveloper2011 Beitrag anzeigen
    [*]Soweit ich das verstanden hab, setzt
    Code cpp:
    1
    
    cin.clear();
    (nur) die Fehler-Flags zurück.?
    Ja.
    Zitat Zitat von javaDeveloper2011 Beitrag anzeigen
    cin.get() und cin.sync() hab ich immer wieder an allen möglichen stellen eingesetzt und rausgenommen, wo wäre das jetzt eigentlich sinfoll?
    sync() wäre sinnvoll wenn du die gepufferte Eingabe löschen möchtest.

    Wie willst du denn eigentlich einlesen? Zeilenweise? Dann nimm getline und verarbeite die gelese Zeile mit einem istringstream:
    Code cpp:
    1
    2
    3
    4
    5
    6
    
    while (getline(cin, line)) {
      istringstream input(line);
      double d1, d2, d3;
      if (input >> d1 >> d2 >> d3 && input.peek() == EOF) {
      }
    }
    (ist nur ein Beispiel, es hängt davon ab wie du Einlesen willst)
    Zitat Zitat von javaDeveloper2011 Beitrag anzeigen
    [*]Ich würde gerne das Komma als Dezimaltrennzeichen verwenden, unter Linux funktioniert das mit
    Code cpp:
    1
    
    cin.imbue(locale("de_DE.uft-8"));
    und
    Code cpp:
    1
    
    fout.imbue(locale("de_DE.uft-8"));
    Eigentlich sollte es "utf-8" heißen.

    Unter Windows heißen die Locales leider etwas anders. Versuch mal "de". Das funktioniert zumindest mit dem MS Compiler.
    Zitat Zitat von javaDeveloper2011 Beitrag anzeigen
    [*]Noch was:
    eingetlich möchte ich auch das man das Programm zu jeder Zeit per ESC-Druck beenden kann, da es in einer Endlosschleife läuft. Falls irgendwie möglich, sollte zu Anfang das Komandozeilenfenster gecleart werden, nicht bloß runterscrollen oder Leerzeilen schreiben!
    Beides selbstverständlich für Linux, Windows, Mac und auch ältere Versionen, sonst macht das ganze für mich keinen Sinn.
    Dann mußt du unterschiedlichen Code schreiben. Oder z.B. ncurses (PDcurses unter Windows) verwenden.

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

  3. #3
    Avatar von javaDeveloper2011
    javaDeveloper2011 javaDeveloper2011 ist offline Mitglied Brokat
    Registriert seit
    Feb 2011
    Beiträge
    443
    Blog-Einträge
    5
    Hi,

    leider werde auch auß deiner antwort noch nicht wirklich schlau.

    Das ist doch völlig OK, oder nicht?
    Natürlich nicht! Der User giebt irgendwas ein, ob er nun dachte dass nam mit Komma Dezimalzahlen trennt, ein Prozent-, oder Euro-Zeichen anhängt, oder sich einfach vertiptt, am Ende haben manche Varialen den wert 0, andere irgend einen ungewollten oder es kommt eine - für den User unverständliche - Fehlermeldung nach der anderen.
    sync()
    bewirkt nur dass die Variablen bei jeklichem Fehler einfach bei 0 bleiben und weiter gemacht wird.

    Wie ich einlesen will:
    - es erscheint ein Name (der Variablen) in der Promt und danach der Cursor.
    - Der User giebt in die gleiche Zeile einen Double-wert ein und drückt Enter
    - Falls es kein komplett absolut korrekter double-Wert war, erscheint ne Fehlermeldung und in der Zeile drunter wieder Name + Cursor
    - Wenn alles gut ging gets genau so mit der nächsten Variablen weiter.

    Ich hab auch mal ein kleines Beispiel in Java geschriben, um zu zeigen wie das Einlesen funktionieren soll, Komma als Dezimltrennzeichen funktioniert, Clear-Screen hab ich jetzt eindgültig aufgegeben und Beenden mit ESC hab ich nichtmal in Java hinbekommen, aber ich denke du weisst, was ich vorhabe:
    Code java:
    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.io.IOException;
    import java.text.DecimalFormat;
    import java.text.ParseException;
    import java.util.Locale;
     
    public class ReadTest{
     
        public static void main(String[] args) {
            double v1 = 0, v2 = 0;
            boolean v1_korrekt = false, v2_korrekt = false;
            DecimalFormat deutschesFormat = (DecimalFormat) DecimalFormat.getInstance(Locale.GERMAN);
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            
            while(!v1_korrekt){
                System.out.print("Variable 1: ");
                try{
                    String s = reader.readLine();
                    try{
                        v1 = deutschesFormat.parse(s).doubleValue();
                        v1_korrekt = true;
                    }
                    catch(ParseException ex){
                        System.err.println("Bitte geben Sie eine gültige Dezimalzahl ein!");
                    }
                }
                catch(IOException ex){
                    System.err.println(ex.toString());
                }
            }
     
            while(!v2_korrekt){
                System.out.print("Variable 2: ");
                try{
                    String s = reader.readLine();
                    try{
                        v1 = deutschesFormat.parse(s).doubleValue();
                        v2_korrekt = true;
                    }
                    catch(ParseException ex){
                        System.err.println("Bitte geben Sie eine gültige Dezimalzahl ein!");
                    }
                }
                catch(IOException ex){
                    System.err.println(ex.toString());
                }
            }
     
            System.out.println(v1 + " + "  + v2 + " = " + (v1+v2));
            System.out.println(v1 + " - "  + v2 + " = " + (v1-v2));
            System.out.println(v1 + " * "  + v2 + " = " + (v1*v2));
            System.out.println(v1 + " / "  + v2 + " = " + (v1/v2));
        }
     
    }

    javaDeveloper2011
     

  4. #4
    deepthroat deepthroat ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Jun 2005
    Beiträge
    8.168
    Hi.
    Zitat Zitat von javaDeveloper2011 Beitrag anzeigen
    Natürlich nicht! Der User giebt irgendwas ein, ob er nun dachte dass nam mit Komma Dezimalzahlen trennt, ein Prozent-, oder Euro-Zeichen anhängt, oder sich einfach vertiptt, am Ende haben manche Varialen den wert 0, andere irgend einen ungewollten oder es kommt eine - für den User unverständliche - Fehlermeldung nach der anderen.
    Das hat aber nichts mit dem Einlesen an sich zu tun. Du mußt halt einfach prüfen ob nach dem erwarteten Wert noch ungültige Zeichen kommen.
    Zitat Zitat von javaDeveloper2011 Beitrag anzeigen
    bewirkt nur dass die Variablen bei jeklichem Fehler einfach bei 0 bleiben und weiter gemacht wird.
    Du mußt schon prüfen ob überhaupt etwas eingelesen wurde. Scheinbar hast du das nicht gemacht.
    Zitat Zitat von javaDeveloper2011 Beitrag anzeigen
    Wie ich einlesen will:
    - es erscheint ein Name (der Variablen) in der Promt und danach der Cursor.
    Das dürfte recht einfach sein.
    Zitat Zitat von javaDeveloper2011 Beitrag anzeigen
    - Der User giebt in die gleiche Zeile einen Double-wert ein und drückt Enter
    Dann lies die Zeile mit getline aus und verabeite diese mit einem istringstream.
    Zitat Zitat von javaDeveloper2011 Beitrag anzeigen
    - Falls es kein komplett absolut korrekter double-Wert war, erscheint ne Fehlermeldung und in der Zeile drunter wieder Name + Cursor
    s.o.
    Zitat Zitat von javaDeveloper2011 Beitrag anzeigen
    - Wenn alles gut ging gets genau so mit der nächsten Variablen weiter.
    Schreibe dir eine Funktion die du mit den verschiedenen Variablen aufrufen kannst.

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

  5. #5
    Avatar von javaDeveloper2011
    javaDeveloper2011 javaDeveloper2011 ist offline Mitglied Brokat
    Registriert seit
    Feb 2011
    Beiträge
    443
    Blog-Einträge
    5
    Hallo deepthroat,

    ne extra Funktion und getline() waren ne sehr gute Idee.

    Ich hab sie auch noch in eine Header-Datei ausgelagert, und will noch Funktionen für andere Datentypen hinzufügen.
    der Code:
    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    
    #ifndef DOUBLE_IO_H
    #define DOUBLE_IO_H
     
    #include <iostream>
    #include <string>
    #include <sstream>
    #include <stdlib.h>
    #include <stdexcept>
     
    // Name zur Anzeige bei Eingabeaufforderung
    // Variable wird nicht-konstant übergeben (per Referenz), aber auch zurückgegeben
    double& readVar(const std::string& name, double& var) {
        bool korrekt = false;
     
        while(!korrekt){
            std::cout << name << ": ";
            std::string s;
            std::getline(std::cin, s);
            bool alleZeichenZahlen = true, erstesKomma = true;
            // Im string sind erlaubt...
            for(int i=0; i<s.length(); i++){
                // ... Zahlen
                if(isdigit(s[i])){
                    continue;
                }
                // ... 1 x ',' außer ganz am Anfang oder ganz am Ende
                else if(s[i] == ',' && erstesKomma && i > 0 && i < s.length()-1){
                    s[i] = '.';         // atof() akzeptiert nur Punkt als Dezimaltrennzeichen
                    erstesKomma = false;
                    continue;
                }
                else{
                    alleZeichenZahlen = false;
                    break;
                }
            }
            if(alleZeichenZahlen){
                var = atof(s.c_str());
                korrekt = true;
            }
            else{
                std::cerr<< "*** Bitte geben Sie eine gueltige Dezimalzahl ein! ***" << std::endl;
            }
        }
     
        return var;
    }
     
    // Nur Name erforderlich, günstig wenn zuvor keine Variable vorliegt, so wird der Code kürzer   
    double& readVar(const std::string& name) {
        double d;   // Zwar ne lokale variable, die per Referenz übergeben wird, funktioniert aber irgendwie
        return readVar(name, d);
    }
     
    // Name und
    // double-Variable zur Ausgabe
    void writeVar(const std::string& name, const double& var) {
        std::ostringstream oss;
        oss << var;
        std::string s = oss.str();
        // Bei ganzen Zahlen
        try{
            s.replace(s.find('.'), 1, ","); // Komma als Dezimaltrennzeichen
        }
        catch(std::out_of_range ex){
        }
        std::cout << name << ": " << s << std::endl;
    }
     
    #endif

    Das mit Komma statt Punkt hab ich jetzt manuel gelöst, war kaum mehr aufwand und damit erspaare ich mir das ganze mit locals und ihrer portierung.
    Meine Frage: In Zeile 51 übergebe ich ne Referenz auf eine nicht-globale Variable, eigentlich doch verboten, aber hier ist es sehr praktisch und funktioniert auch einwandfrei. Kann ich das dann so lassen?

    An sonsten wäre da noch die Sache mit den Umlauten, es geht lediglich um einige statische Strings wie "gültig" im oberen Listing \u00FC bewikt beim mingw32-Cross-Compiler leider auch nichts, irgend ne Idee?

    Über Vorschläge zu clearscreen und Programm Beenden per ESC freue ich mich natürlich weterhin,
    javaDeveloper2011
     

  6. #6
    Steiner_B Steiner_B ist offline Mitglied Platin
    Registriert seit
    Mar 2004
    Ort
    Wien
    Beiträge
    573
    Hallo,

    Das mit der Referenz in Zeile 51 halte ich für keine gute Idee, da dies nur solange funktioniert bis der Speicherbereich in der die lokale Variable lag überschrieben wird. Eigentlich ist es hier aber auch nicht notwendig eine Referenz zurück zu geben. Du kannst einfach einen double zurückgeben, dann hast du das Problem nicht.
    javaDeveloper2011 bedankt sich. 

  7. #7
    Avatar von javaDeveloper2011
    javaDeveloper2011 javaDeveloper2011 ist offline Mitglied Brokat
    Registriert seit
    Feb 2011
    Beiträge
    443
    Blog-Einträge
    5
    Hi,

    hast recht, ich hatte nicht mehr dran gedacht, dass der Compiler trotzdem je nach Parameterzahl die richtige überladene Funktion raussucht, auch wenn ein Mal ein Wert und das andere Mal ne Referenz zurückgegeben wird.

    Gruß
     

  8. #8
    deepthroat deepthroat ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Jun 2005
    Beiträge
    8.168
    Hi.

    Da sind noch einige Fehler drin.

    Insbesondere prüfst du immer noch nicht ob überhaupt etwas eingelesen wurde. Falls cin in einem Fehlerzustand ist, hast du eine Endlosschleife.

    Und ich sehe nirgendwo das du auch Gleitkommazahlen in wissenschaftlicher Notation und neg. Zahlen akzeptieren würdest.

    \edit:
    Zitat Zitat von javaDeveloper2011 Beitrag anzeigen
    An sonsten wäre da noch die Sache mit den Umlauten, es geht lediglich um einige statische Strings wie "gültig" im oberen Listing \u00FC bewikt beim mingw32-Cross-Compiler leider auch nichts, irgend ne Idee?
    Du müßtest dem GCC erstmal mitteilen welcher Zeichensatz zur Laufzeit verwendet werden soll. (-fexec-charset)

    Wenn du das Programm unter einem deutschen Windows ausführst, ist der aktive Zeichensatz in der Konsole cp850. Das kannst du z.B. mit "chcp 65001" zu UTF-8 ändern (bzw. SetConsoleOutputCP). Du mußt aber noch die Schriftart der Konsole z.B. auf Lucida umstellen (damit Unicode Zeichen auch angezeigt werden können).

    Du kannst auch den Eingabezeichensatz (Encoding deiner Datei) angeben (-finput-charset), dann mußt du nicht Escapesequenzen in Stringliteralen benutzen.

    Gruß
    Geändert von deepthroat (18.08.11 um 08:27 Uhr)
    javaDeveloper2011 bedankt sich. 
    If at first you don't succeed, try again. Then quit. No use being a damn fool about it.

  9. #9
    Avatar von javaDeveloper2011
    javaDeveloper2011 javaDeveloper2011 ist offline Mitglied Brokat
    Registriert seit
    Feb 2011
    Beiträge
    443
    Blog-Einträge
    5
    Hi,

    Ich prüfe jetzt auch noch ob überhaupt etwas eingegeben wurde, wenn eine gültige Zahl eingegeben wurde, aber es Technisch ein Problem giebt, hilft es mit ja auch nichts zur nächsten Variablen weiter zu gehen. Im Hauptprogramm, dass den Header benutzt gibts sowieso ne Englosschleife, und das ist so gewollt.

    Dass extrem große bzw. kleine Zahlen (die mit e drinnen) und negative nicht erlaubt sind finde ich gerade wunderbar, denn die meisten meiner Programme können sowieso nicht sinfoll mit ihnen arbeiten, so entfällt die nachträglich Prüfung auf > 0.

    Bevor es wieder Probleme mit der Portierung, ect. giebt lasse ich die Paar umlaute lieber als ue, oe, ae, ... stehen, trotzdem Danke. Wahrscheinlich probiere ich es irgendwann nochmal.

    javaDeveloper2011
     

  10. #10
    deepthroat deepthroat ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Jun 2005
    Beiträge
    8.168
    Zitat Zitat von javaDeveloper2011 Beitrag anzeigen
    Im Hauptprogramm, dass den Header benutzt gibts sowieso ne Englosschleife, und das ist so gewollt.
    Dein Programm kann also nie beendet werden, außer indem man es abschießt?

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

  11. #11
    Avatar von javaDeveloper2011
    javaDeveloper2011 javaDeveloper2011 ist offline Mitglied Brokat
    Registriert seit
    Feb 2011
    Beiträge
    443
    Blog-Einträge
    5
    Hi,

    deshalb wollte ich ja des Beenden mit ESC ermöglichen.
    Geht das irgendwie, also es soll immer möglich sein, auch ohne anschließenden ENTER-Druck.

    Gruß
     

  12. #12
    cwriter cwriter ist offline Mitglied Gold
    Registriert seit
    Mar 2010
    Beiträge
    242
    Ja, mit GetAsyncKeyState() oder GetKeyState() oder (ganz einfach): getch().

    Gruss
    cwriter
     
    Intel inside - Idiot outside :-)

    Ich schreibe in C und bin Anfänger.
    ______________________________

    Falls ich eines Tages einen guten Beitrag schreiben werde, bitte bewerten und/oder Danke sagen.
    Danke

  13. #13
    Avatar von javaDeveloper2011
    javaDeveloper2011 javaDeveloper2011 ist offline Mitglied Brokat
    Registriert seit
    Feb 2011
    Beiträge
    443
    Blog-Einträge
    5
    Sieht mir aber leider alles nach Windows-only aus.
     

  14. #14
    cwriter cwriter ist offline Mitglied Gold
    Registriert seit
    Mar 2010
    Beiträge
    242
    getch() ist in der conio.h, glaube ich. Hat Linux die nicht?
     
    Intel inside - Idiot outside :-)

    Ich schreibe in C und bin Anfänger.
    ______________________________

    Falls ich eines Tages einen guten Beitrag schreiben werde, bitte bewerten und/oder Danke sagen.
    Danke

  15. #15
    Avatar von javaDeveloper2011
    javaDeveloper2011 javaDeveloper2011 ist offline Mitglied Brokat
    Registriert seit
    Feb 2011
    Beiträge
    443
    Blog-Einträge
    5
    Nein, leider nicht.
     

Ähnliche Themen

  1. Korrekt byteweise einlesen
    Von Tim Bureck im Forum .NET Café
    Antworten: 2
    Letzter Beitrag: 24.08.10, 19:01
  2. Variablen anhängen geht nicht korrekt
    Von kannaum im Forum PHP
    Antworten: 5
    Letzter Beitrag: 14.09.09, 16:53
  3. Antworten: 15
    Letzter Beitrag: 15.01.09, 14:43
  4. Variablen werden nicht korrekt ausgegeben
    Von multimolti im Forum PHP
    Antworten: 7
    Letzter Beitrag: 28.03.07, 00:26
  5. CSV-Datei korrekt einlesen
    Von DanielBodensee im Forum Delphi, Kylix, Pascal
    Antworten: 1
    Letzter Beitrag: 24.04.04, 22:46

Stichworte