Problem bei verschachtelten while/if Anweisungen



  • SeppJ schrieb:

    DerNoob1993 schrieb:

    Man kann alle cins auf einmal einlesen sprich 5+6 direkt nach dem allersten cout eingeben. Und dann werden alle anderen cout der Reihe nach ausgegeben,und die anderen cins übergangen ( das ergebniss ist sogar richtig) ,aber wieso kann ich in das erste cin die gesamte Rechnung einlesen verstehe das grade nicht. http://epvpimg.com/EZnbe hier ist ein Bild wie ich das ganze meine.Er liest ja zuerst nur den int wert ein wie kann ich in diesen denn die Rechnung einlesen?

    Falsches Verständnis, was cin ist. cin ist nicht "lese etwas von der Tastatur ein". cin ist ein Streamobjekt, welches an den Zeichenstrom stdin gekoppelt ist. Ein Konsolenprogramm ist wie eine schwarze Kiste, da geht ein Lochstreifen* rein, da stehen Zeichen drauf (stdin) und es gehen zwei Lochstreifen raus (stdout und stderr). Das cin-Objekt sitzt in dieser schwarzen Kiste und sieht nur diesen Lochstreifen. Es weiß nicht, wo er her kommt oder wie lang er ist. Es kann sich nur die Zeichen auf diesem Lochstreifen angucken. Das passiert, wenn du irgendwelche Lesefunktionen auf cin aufrufst. Dann gucken diese Funktionen sich den Lochstreifen an, fahren ihn dabei ggf. weiter und warten eventuell auch auf weitere Zeichen, falls die aktuelle Funktion noch nicht fertig ist. Dieses Warten erweckt bei Anfängern oft den Eindruck, dass die Lesefunktionen irgendwie aktiv Eingaben von der Tastatur einlesen würden. Dabei warten sie bloß darauf, dass über den Zeichenstrom stdin weitere Zeichen erscheinen.

    Wie kommen diese Zeichen nun nach stdin? Dies kann sehr verschieden sein (und das ist auch gut so). Ich nehme mal an, dass du dein Programm von irgendeiner Konsole startest und dabei keine weitere Aktion unternimmst, um stdin irgendwie umzuleiten. Die Konsole wird dann einfach ihr eigenes stdin an dein Programm weiterleiten. Aber wo kommt das stdin der Konsole her? Die Konsole läuft in einem Terminal (heutzutage meistens ein Terminalemulator). Eventuell läuft der Terminal(emulator) auch nochmal in irgendetwas anderem. Aber irgendwann kommt man an der untersten Schicht an und diese Programmschicht fragt tatsächlich irgendwie Zeichen von der Tastatur ab, die dann weitergeleitet werden. Diese Eingaben werden dann mehr oder weniger unverändert an dein Programm weitergeleitet, ohne jede Information darüber, wo sie herkommen, wann sie entstanden sind oder sonst etwas. Einfach bloß ein langer Bytestrom. Ich sage fast unverändert, denn direkt die Tastendrücke weiterzuleiten wäre eher unpraktisch. Irgendeine Ebene zwischen der Tastatur und deinem Programm sorgt auch noch dafür, dass die Sondertasten so funktionieren, wie man es kennt. Also dass man Mit Delete und Backspace die Eingabe verändern kann und erst mit Druck der Entertaste wird die Eingabe tatsächlich an die nächste Ebene weitergeleitet. Wieder sieht es so aus, als hätte die cin-Lesefunktion auf die Entertaste gewartet. Dabei hat sie bloß auf weitere Zeichen auf stdin gewartet, während eine ganz andere Ebene auf den Abschluss der Eingabe mittels Entertaste gewartet hat und erst dann die von ihr gesammelte Eingabe an die stdins der weiteren Ebenen weitergeleitet hat, bis sie letztendlich bei deiner cin-Lesefunktion angekommen sind.

    Nun sollte auch verständlich sein, warum es egal ist, wann und wie du deine Eingabe für das Programm durchführst. Dein Programm sieht sowieso nur einen Zeichenstrom und es ist ihm egal, wie dieser Zustande kommt.

    *: Für die Jüngeren:
    http://en.wikipedia.org/wiki/Punched_tape

    Vielen Dank für deine ausführliche Antwort ich denke ich habe das Prinzip von cin jetzt einigermaßen verstanden.

    Ich weiß ich frage echt viel , und zum Teil auch echt doofe Fragen 😃 , aber ich habe da grade noch ein Problem an dem ich nicht weiterkomme.

    Es geht darum ,dass ich in ner while Schleife prüfen möchte ,ob der User den richtigen Typ der Variable einliest ( nicht ,dass er nachher in einen int wert einen string einliest , und das Programm abstürzt ,oder sinnloses ausgibt 🙂
    Mein Lösungsansatz habe ich in einem kleinen "Testprojekt" getestet ,allerdings klappt das ganze einfach nicht.

    #include <iostream>
    
    int main()
    {       long number_one = 0;
            int richtige_eingabe = 0 ;
    	while(richtige_eingabe == 0)
    	{
    	cout << "Erste Zahl\n";
    
    	if( (cin >> number_one ))
    	{
    	++richtige_eingabe;
    	}
    
           else if( !( cin >> number_one))
           {}
    
           } 
    }
    

    Er liest hier number_one nur einmal ein und hängt dann in einer Endlosschleife in welcher er den Text "Erste Zahl" unendlich oft ausgibt , aber eben nicht von neu in cin einliest . Habe auch schon versucht bei falscher Eingabe mittels ZeroMemory den Wert zurückzusetzen , aber da passiert nur genau das selbe.Der Text wird dauerhaft ausgegeben , aber es wird nichts neues eingelesen.
    Sinn der Schleife sollte sein ,dass bei falscher eingabe wie z.B. asdasd in einen int Typ die Schleife von neu beginnt und man die Zahl erneut einlesen soll.


  • Mod

    Hier gehen drei Dinge schief:
    1. Nachdem eine Eingabe fehlgeschlagen ist, so befindet sich der Stream in einem Fehlerzustand und es schlagen alle weiteren Aktionen fehl, bis man sich darum kümmert (z.B. mit clear()).
    2. Danach sind natürlich immer noch die Zeichen auf dem metaphorischen Lochstreifen, die zum Fehlschlag geführt haben. Da muss man sich auch drum kümmern, z.B. mit ignore().
    3. In Zeile 16 steht bei dir ja wieder etwas aus dem Stream gelesen (oder wenigstens wird es versucht). Das ist bestimmt nicht die Logik, die du dir vorgestellt hast.

    So kann man das beispielsweise machen:

    #include <iostream>
    #include <cctype>
    
    using namespace std;
    
    void skip_word(istream &in)
    {
      for (char c = in.peek(); in && isgraph(c); c = in.peek())
        in.ignore(1);
    }
    
    int main()
    {
      int i;
      for (;;)
        {
          cin >> i;
          if (!cin && !cin.eof())
            {
              cout << "Das war keine Zahl\n";
              cin.clear();
              skip_word(cin);
            }
          else
            break;
        }
      cout << "Zahl gelesen: " << i << '\n';
    }
    

    Du wirst merken, dieses schon relativ komplexe Beispiel lässt noch viele Wünsche offen. Falls du vor hast, das weiter zu treiben und weitere Fehler abzufangen, lass dir gesagt sein, dass dies in die Richtung geht, ein eigenes GUI-Framework zu schreiben. Das gibt es aber schon längst und in viel besser.



  • SeppJ schrieb:

    Hier gehen drei Dinge schief:
    1. Nachdem eine Eingabe fehlgeschlagen ist, so befindet sich der Stream in einem Fehlerzustand und es schlagen alle weiteren Aktionen fehl, bis man sich darum kümmert (z.B. mit clear()).
    2. Danach sind natürlich immer noch die Zeichen auf dem metaphorischen Lochstreifen, die zum Fehlschlag geführt haben. Da muss man sich auch drum kümmern, z.B. mit ignore().
    3. In Zeile 16 steht bei dir ja wieder etwas aus dem Stream gelesen (oder wenigstens wird es versucht). Das ist bestimmt nicht die Logik, die du dir vorgestellt hast.

    So kann man das beispielsweise machen:

    #include <iostream>
    #include <cctype>
    
    using namespace std;
    
    void skip_word(istream &in)
    {
      for (char c = in.peek(); in && isgraph(c); c = in.peek())
        in.ignore(1);
    }
    
    int main()
    {
      int i;
      for (;;)
        {
          cin >> i;
          if (!cin && !cin.eof())
            {
              cout << "Das war keine Zahl\n";
              cin.clear();
              skip_word(cin);
            }
          else
            break;
        }
      cout << "Zahl gelesen: " << i << '\n';
    }
    

    Du wirst merken, dieses schon relativ komplexe Beispiel lässt noch viele Wünsche offen. Falls du vor hast, das weiter zu treiben und weitere Fehler abzufangen, lass dir gesagt sein, dass dies in die Richtung geht, ein eigenes GUI-Framework zu schreiben. Das gibt es aber schon längst und in viel besser.

    Ich danke dir 🙂
    Ich habe denke ich verstanden wie das ganze funktioniert.
    Als erstes wenn das cin fehlschlägt benutzt man die cin.clear() Funktion um soweit ich richtig verstanden habe den Eingabebuffer zu leeren. Als nächstes übergibt man den stream an die selbst geschriebene Funktion welche jedes Zeichen des Streams von Anfang bis Ende ignoriert(löscht?).
    Dadurch kann man es danach auch wieder neu einlesen ,und die if schleife wird nicht endlos ausgeführt.
    Habe ich das soweit richtig verstanden , oder ist da etwas noch falsch an dem wie ich es aufgefasst habe?


  • Mod

    Leider hast du so ziemlich alles falsch verstanden.

    DerNoob1993 schrieb:

    Ich habe denke ich verstanden wie das ganze funktioniert.
    Als erstes wenn das cin fehlschlägt benutzt man die cin.clear() Funktion um soweit ich richtig verstanden habe den Eingabebuffer zu leeren.

    Es gibt keinen Eingabepuffer.

    Als nächstes übergibt man den stream an die selbst geschriebene Funktion welche jedes Zeichen des Streams von Anfang bis Ende ignoriert(löscht?).

    Es gibt keinen Anfang. Hier wird auch nicht bis Ende gelöscht. Man weiß normalerweise nicht einmal, ob es ein Ende gibt oder wann es kommt.

    Dadurch kann man es danach auch wieder neu einlesen ,und die if schleife wird nicht endlos ausgeführt.

    Es gibt keine if-Schleifen.

    Noch einmal:
    Es wird gelesen. Es wird geprüft, ob das Lesen erfolgreich war. Falls dies der Fall war: Fertig. falls das Lesen nicht erfolgreich war: Dann befindet sich der Stream in einem Fehlerstatus (das ist quasi die Definition von nicht erfolgreichem Lesen). Dieser wird mit clear aufgehoben. Damit signalisiert man dem Stream, dass man den Fehler erkannt hat und sich darum kümmern wird. Dann wird die selbstgeschriebene Funktion aufgerufen. Diese setzt den Stream so lange zeichenweise weiter, bis ein nicht-grafisches Zeichen gefunden wird. Ansonsten würde der nächste Leseversuch an den gleichen Zeichen scheitern, die auch schon beim vorherigen Versuch zum Scheitern geführt haben.

    Wenn ich recht darüber nachdenke, wäre

    for (char c = in.peek(); in && !isspace(c); c = in.peek())
    

    besser, weil dies besser zu dem passt, was operator>> macht.



  • Ich hab keine Ahnung was SeppJ da macht, aber eigentlich nimmt man den Klassiker

    std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
    

    (Nur mal so kontextfrei, ich hab die Unterhaltung nicht verfolgt, vielleicht brauchst du seine Version)

    Es gibt keine if-Schleifen.

    Noch nicht 😉 🕶



  • SeppJ schrieb:

    Leider hast du so ziemlich alles falsch verstanden.

    DerNoob1993 schrieb:

    Ich habe denke ich verstanden wie das ganze funktioniert.
    Als erstes wenn das cin fehlschlägt benutzt man die cin.clear() Funktion um soweit ich richtig verstanden habe den Eingabebuffer zu leeren.

    Es gibt keinen Eingabepuffer.

    Als nächstes übergibt man den stream an die selbst geschriebene Funktion welche jedes Zeichen des Streams von Anfang bis Ende ignoriert(löscht?).

    Es gibt keinen Anfang. Hier wird auch nicht bis Ende gelöscht. Man weiß normalerweise nicht einmal, ob es ein Ende gibt oder wann es kommt.

    Dadurch kann man es danach auch wieder neu einlesen ,und die if schleife wird nicht endlos ausgeführt.

    Es gibt keine if-Schleifen.

    Noch einmal:
    Es wird gelesen. Es wird geprüft, ob das Lesen erfolgreich war. Falls dies der Fall war: Fertig. falls das Lesen nicht erfolgreich war: Dann befindet sich der Stream in einem Fehlerstatus (das ist quasi die Definition von nicht erfolgreichem Lesen). Dieser wird mit clear aufgehoben. Damit signalisiert man dem Stream, dass man den Fehler erkannt hat und sich darum kümmern wird. Dann wird die selbstgeschriebene Funktion aufgerufen. Diese setzt den Stream so lange zeichenweise weiter, bis ein nicht-grafisches Zeichen gefunden wird. Ansonsten würde der nächste Leseversuch an den gleichen Zeichen scheitern, die auch schon beim vorherigen Versuch zum Scheitern geführt haben.

    Wenn ich recht darüber nachdenke, wäre

    for (char c = in.peek(); in && !isspace(c); c = in.peek())
    

    besser, weil dies besser zu dem passt, was operator>> macht.

    Danke das war verständlicher für mich.
    Die Funktionen waren für mich noch zum Teil unbekannt ,aber nach deiner jetzigen Erklärung habe ich verstanden ,was die einzelnen Funktionen genau machen ,und wie das ganze zusammenhängt. Habe mir die Funktionen nur ergoogelt gehabt , und nicht genau verstanden gehabt wie das ganze zusammenhängt.

    Edit : Ja If Schleifen 😮 😃
    Naja bin halt noch Anfänger und bringe manche Fachbegriffe noch durcheinander obwohl das jetzt auch für mich schon ein ziemlicher Fail war 😃 .



  • Nexus schrieb:

    HarteWare schrieb:

    Sind Aufzählungstypen gleichbedeutend mit Charakteren, also "char" ?

    Nein. Aufzählungstypen sind enum s.

    Dann bin ich jetzt aber leicht verwirrt... Man kann mit switch() nämlich auch chars abgleichen. Fallen diese etwa in die Kategorie "integrale Werte"?

    mfg



  • Dann bin ich jetzt aber leicht verwirrt... Man kann mit switch() nämlich auch chars abgleichen. Fallen diese etwa in die Kategorie "integrale Werte"?

    Darunter fallen bool , char , char16_t , char32_t , wchar_t , short , int , long , und long long .
    P.S.: Nicht "Werte". Typen.



  • Sone schrieb:

    Darunter fallen bool , char , char16_t , char32_t , wchar_t , short , int , long , und long long .

    Darunter fallen bool , char16_t , char32_t , signed/unsigned char , signed/unsigned short , signed/unsigned int , signed/unsigned long und signed/unsigned long long .



  • fifi ftfy schrieb:

    Sone schrieb:

    Darunter fallen bool , char , char16_t , char32_t , wchar_t , short , int , long , und long long .

    Darunter fallen bool , char16_t , char32_t , signed/unsigned char , signed/unsigned short , signed/unsigned int , signed/unsigned long und signed/unsigned long long .

    Darunter fallen bool , char16_t , char32_t , signed/unsigned/plain char , signed/unsigned short , signed/unsigned int , signed/unsigned long und signed/unsigned long long .



  • out schrieb:

    fifi ftfy schrieb:

    Sone schrieb:

    Darunter fallen bool , char , char16_t , char32_t , wchar_t , short , int , long , und long long .

    Darunter fallen bool , char16_t , char32_t , signed/unsigned char , signed/unsigned short , signed/unsigned int , signed/unsigned long und signed/unsigned long long .

    Darunter fallen bool , char16_t , char32_t , signed/unsigned/plain char , signed/unsigned short , signed/unsigned int , signed/unsigned long und signed/unsigned long long .

    Darunter fallen bool , char16_t , char32_t , signed/unsigned/plain char , wchar_t , signed/unsigned short , signed/unsigned int , signed/unsigned long und signed/unsigned long long , inklusive sämtlicher cv Varianten.



  • fifi ftfy schrieb:

    Sone schrieb:

    Darunter fallen bool , char , char16_t , char32_t , wchar_t , short , int , long , und long long .

    Darunter fallen bool , char16_t , char32_t , signed/unsigned char , signed/unsigned short , signed/unsigned int , signed/unsigned long und signed/unsigned long long .

    Ich habe absichtlich die Vorzeichenbehaftung weggelassen. Weil sie hier irrelevant ist (eig. genauso irrelevant wie bspw. char32_t , aber was solls 🕶 )

    Das es separate Typen sind, ist mir aber schon klar, ne?

    inklusive sämtlicher cv Varianten.

    Na, weil ihr beiden es doch so drauf anlegt, zähl die doch mal alle auf, ich bin sicher wir haben was davon 😃



  • bool
    const bool
    volatile bool
    const volatile bool
    signed char16_t
    const signed char16_t
    volatile signed char16_t
    const volatile signed char16_t
    unsigned char16_t
    const unsigned char16_t
    volatile unsigned char16_t
    const volatile unsigned char16_t
    signed char32_t
    const signed char32_t
    volatile signed char32_t
    const volatile signed char32_t
    unsigned char32_t
    const unsigned char32_t
    volatile unsigned char32_t
    const volatile unsigned char32_t
    signed char
    const signed char
    volatile signed char
    const volatile signed char
    unsigned char
    const unsigned char
    volatile unsigned char
    const volatile unsigned char
    signed wchar_t
    const signed wchar_t
    volatile signed wchar_t
    const volatile signed wchar_t
    unsigned wchar_t
    const unsigned wchar_t
    volatile unsigned wchar_t
    const volatile unsigned wchar_t
    signed short
    const signed short
    volatile signed short
    const volatile signed short
    unsigned short
    const unsigned short
    volatile unsigned short
    const volatile unsigned short
    signed int
    const signed int
    volatile signed int
    const volatile signed int
    unsigned int
    const unsigned int
    volatile unsigned int
    const volatile unsigned int
    signed long
    const signed long
    volatile signed long
    const volatile signed long
    unsigned long
    const unsigned long
    volatile unsigned long
    const volatile unsigned long
    signed long long
    const signed long long
    volatile signed long long
    const volatile signed long long
    unsigned long long
    const unsigned long long
    volatile unsigned long long
    const volatile unsigned long long



  • unsigned bool? signed bool? 😕 gibts das echt?



  • upps, mein fehler.



  • Wofür steht nochmal volatile?

    0x0ERROR



  • 0x0ERROR schrieb:

    Wofür steht nochmal volatile?

    0x0ERROR

    N3337 [dcl.type.cv]/7

    volatile is a hint to the implementation to avoid aggressive optimization involving the object
    because the value of the object might be changed by means undetectable by an implementation. See 1.9 for
    detailed semantics. In general, the semantics of volatile are intended to be the same in C++ as they are
    in C.

    Es kann allerdings wegen as-if ignoriert werden.



  • out schrieb:

    fifi ftfy schrieb:

    Sone schrieb:

    Darunter fallen bool , char , char16_t , char32_t , wchar_t , short , int , long , und long long .

    Darunter fallen bool , char16_t , char32_t , signed/unsigned char , signed/unsigned short , signed/unsigned int , signed/unsigned long und signed/unsigned long long .

    Darunter fallen bool , char16_t , char32_t , signed/unsigned/plain char , signed/unsigned short , signed/unsigned int , signed/unsigned long und signed/unsigned long long .

    plain char ist entweder ein typedef auf signed oder auf unsigned char, deshalb fällt der weg. Gleich wie wchar_t.

    cv-Qualifiers gehören nicht wirklich zum Typ. Die kriegt man mit std::decay weg. Ernsthaft. Ist schon fast ein Getrolle was Nathan da liefert.



  • plain char ist entweder ein typedef auf signed oder auf unsigned char, deshalb fällt der weg.

    Blödsinn. Es ist kein typedef darauf, 's stimmt schon dass es sich wie eines der beiden verhält. Aber es sind drei verschiedene Typen, egal was du machst.
    Edit: Nicht so vehement.



  • fifi ftfy schrieb:

    cv-Qualifiers gehören nicht wirklich zum Typ. Die kriegt man mit std::decay weg. Ernsthaft. Ist schon fast ein Getrolle was Nathan da liefert.

    Wieso?
    Weil einmal wchar_t mit drin war und einmal nicht, habe ich hier nachgeguckt. Dann habe ich das auch so hingeschrieben und sone wollte, dass ich das alles aufschreibe.


Anmelden zum Antworten