Abfrage von leerer Eingabe (Enter)



  • Egal wie, es sollte doch möglich sein, die leere Enter-Taste abzufragen oder?


  • Mod

    ThomasLanger schrieb:

    Egal wie, es sollte doch möglich sein, die leere Enter-Taste abzufragen oder?

    Ja, habe ich doch erklärt. Wenn zwischen zwei newlines nichts kommt, dann war die Eingabe wohl leer.

    Wenn es denn überhaupt eine Eingabe war, denn einem C++-Programm ist herzlich egal, woher die Daten kommen, daher ist der Begriff der Entertaste nicht direkt überprüfbar, denn es ist nicht gesagt, dass Eingaben von einer Tastatur kommen. Wenn du tatsächlich unbedingt auf Entertasten bestehst, musst du das Betriebssystem um genauere Informationen über Eingabegeräte fragen. Aber das ist hier doch gar nicht nötig, was spricht denn gegen die vorgeschlagene Lösung?



  • SeppJ schrieb:

    was spricht denn gegen die vorgeschlagene Lösung?

    Der Code-Bloat und die Ineffizienz.

    #include <iostream>
    
    struct special_newline_ctype : std::ctype<char>
    {
      mask table[table_size];
    public:
      special_newline_ctype(size_t refs = 0) : std::ctype<char>(table, false, refs) {
        std::copy(classic_table(), classic_table()+table_size, table);
        table['\n'] = (mask)cntrl;
      }
    };
    
    class line_guard {
      std::istream& os;
      std::locale l;
    public:
      line_guard(std::istream& os = std::cin) : os(os), l(os.getloc())
      { os.imbue(std::locale(l, new special_newline_ctype)); }
    
      bool eol() { os >> std::skipws; return os.peek() == '\n'; }
    
      ~line_guard() {
        os.clear(); os.imbue(l);
        os.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
      }
    };
    
    int main()
    {
      int x, y;
      std::cout << "Bitte Von-Bis eingeben! " << std::endl;
      for (;;) {
        line_guard g;
        std::cout << "Von: ";
        if (std::cin >> x) break;
      }
      {
        line_guard g;
        std::cout << "Bis: ";
        if (!(std::cin >> y))
          y = x;
      }
      std::cout << x << " -- " << y << '\n';
    }
    

    @ThomasLanger: Ein- und Ausgabe sind unter C++ leider kein Anfängerthema, ich würde es so lassen, wie du es hattest.



  • Wenn es in C++ so kompliziert sein soll, eine "leere" Eingabe abzufangen, muss ich mir was anderes einfallen lassen, möglicherweise eine andere Programmiersprache.
    Trotzdem Dankeschön


  • Mod

    ThomasLanger schrieb:

    Wenn es in C++ so kompliziert sein soll, eine "leere" Eingabe abzufangen,

    Hör nicht auf mont, der beliebt zu scherzen. Es ist zwar an sich eine sehr saubere Lösung, aber ganz sicher nicht die Lösung die ein Neuanfänger sucht. getline und stringstream helfen dir vorerst sicherlich mehr, später kannst du dir angucken, was es mit monts Lösung auf sich hat.



  • SeppJ schrieb:

    Es ist zwar an sich eine sehr saubere Lösung, [...]

    Ja, abgesehen vom Speicherleak in line_guard und fehlenden limits header.


  • Mod

    [Rewind] schrieb:

    SeppJ schrieb:

    Es ist zwar an sich eine sehr saubere Lösung, [...]

    Ja, abgesehen vom Speicherleak in line_guard und fehlenden limits header.

    So ganz genau hatte ich es gar nicht angeguckt. Ich war stillschweigend davon ausgegangen, dass jemand, der mit solchem Code angibt, keine solchen Fehler macht. Die Grundidee ist an sich eine ähnliche, wie meine erste Eingebung auf die Frage.



  • Mein Hinweis ist aber keineswegs negativ oder abwertend gemeint. Recht hast du trotzdem.



  • [Rewind] schrieb:

    Ja, abgesehen vom Speicherleak in line_guard

    Wo denn? Ich weise darauf hin, dass std::ctype einen eingebauten Referenzzähler hat (wie du an meiner Implementation von special_newline_ctype siehst). Die iostreams sind halt wirklich alt und gehören mMn durch einen besseren Ansatz ersetzt.

    SeppJ schrieb:

    Hör nicht auf mont, der beliebt zu scherzen.

    Jo, das war ein provokanter Post.

    SeppJ schrieb:

    Ich war stillschweigend davon ausgegangen, dass jemand, der mit solchem Code angibt, keine solchen Fehler macht

    Ganz schlechte Einstellung. Den Code, den ich damals geschrieben habe, war einer meiner ersten Versuche mit den Streams. (Um zum Scherzen zurück zu kommen, ich habe mich "mont" genannt, weil ich gehofft habe, mich irgendwann als "Sderne" ausgeben zu können, dann wäre da eine Diskussion zwischen Sone, mont und Sderne gewesen.)

    Wenn ich jetzt nochmal drüber schaue hat es da noch einige gravierendere Fehler drin, die [Rewind] nicht gesehen hat. z.B. ist std::skipws hier absolut falsch am Platz, da gehört ein std::ws hin. Ausserdem hätte ich special_newline_ctype völlig anders, unter Benutzung der alten locale implementieren sollen.



  • Und wo wird der für special_newline_ctype mit new allokierte Speicher wieder freigegeben? Oder übersehe ich da was?



  • [Rewind] schrieb:

    Ich glaube nicht, dass der Destructor ~locale () deinen mit Oper. new allokierten Speicher wieder freigibt.

    Doch tut er. Kannst gerne mittels printf debugging zählen, wie oft special_newline_ctype erstellt und freigegeben wird. Da ist kein Leck.



  • Am einfachsten würde es über die conio.h gehen.

    0x0ERROR



  • ThomasLanger schrieb:

    Auch wenn ihr diese Frage nicht mehr lesen könnt, stelle ich sie in der Hoffnung eine Hilfe zu bekommen:
    cout << "Bitte Von-Bis eingeben! " << endl;
    cout << "Von: "; cin >> x;
    y=x;
    cout << "Bis: "; cin >> y;

    wenn bei bis die Enter Taste gedrückt wird, soll gelten dass y=x ist.
    Bisher alles versucht, was man so findet, also abfragen ob Eingebe leer ist.

    Hallo Thomas,

    ich habe vor Jahren mal das kleine is_endl gebaut, welches Dein Problem lösen sollte:

    #include "is_endl.h" // (s.u.)
    #include <iostream>
    #include <limits> // numeric_limits
    
    int main()
    {
        using namespace std;
        int x, y;
        cout << "Bitte Von-Bis eingeben! " << endl;
        cout << "Von: "; cin >> x;
        cin.ignore( numeric_limits< streamsize >::max(), '\n' ); // überliest den Rest der 1.Zeile
        y=x;
        cout << "Bis: "; 
        if( !is_endl( cin ) ) // keine leere Eingabe
            cin >> y; // dann lese den 'bis'-Wert
    
        cout << x << " " << y << endl;
        return 0;
    }
    

    Das Thema IO unter C++ krankt auch ein wenig am vorhandenen Input - sprich Literatur. Aber das ist ein anderes Thema.

    anbei noch mal der aktuelle Code von is_endl (ich lerne auch noch dazu):

    // -- Datei is_endl.h
    #ifndef SAM_IS_ENDL_H_
    #define SAM_IS_ENDL_H_
    #include <istream>
    #include <locale>
    #include <streambuf>
    
    template< typename E, typename Traits >
    bool is_endl( std::basic_istream< E, Traits >& in )
    {
        if( in.eof() ) // EOF vorher abfangen, da sentry den Stream auf fail setzt, falls eof()==true ist!
            return false;
        typename std::basic_istream< E, Traits >::sentry ok( in, true ); // true := noskipws
        if( ok )
        {
            std::ios_base::iostate state = std::ios_base::goodbit;
            try
            {
                const bool skipws_ = in.flags() & std::ios_base::skipws;
                const std::ctype< E >& ct = std::use_facet< std::ctype< E > >( in.getloc() );
                for( typename std::basic_istream< E, Traits >::int_type m = in.rdbuf()->sgetc(); ; m = in.rdbuf()->snextc() )
                {
                    if( Traits::eq_int_type( Traits::eof(), m ) )
                    {
                        state |= std::ios_base::eofbit;
                        break;
                    }
                    const E c = Traits::to_char_type( m );
                    if( c == ct.widen( '\n'  ) )
                    {
                        in.rdbuf()->sbumpc();   // consume the char (here LF)
                        return true;
                    }
                    if( !skipws_ || !ct.is( std::ctype_base::space, c ) )
                        break;          // noskipws || readable char follows
                }
            }
            catch( ... )
            {
                state |= std::ios_base::badbit;
                if( in.exceptions() & std::ios_base::badbit )
                    throw; // re-throw
            }
            in.setstate( state );
        }
        return false;
    }
    #endif  // ifndef SAM_IS_ENDL_H_
    

    Gruß
    Werner


Log in to reply