turgar: c-Programm & getchar()

Hallo,

ich habe hier folgendes c-Programmfragment:
  while(counter<9)
    {
        int pos=-1;
        printf("Insert position:\n");
        readChar = NULL;
        readChar = getchar();
        pos = ((int)readChar) - 48;
        ...
        counter++;
    }

Das Ganze soll Zahlen von der Eingabe lesen, die später benutzt werden.
Das Problem daran ist, dass nicht in jedem Durchlauf durch die Schleife von der Eingabe gelesen wird.
Sprich:
Die Schleife wird zwar so lange durchlaufen bis counter=9 ist, allerdings wird bei jedem zweiten Durchlauf nicht von der Eingabe gelesen, da das Programm nicht auf eine Benutzereingabe wartet und einfach über die getchar() Zeile hinweg läuft;
Funktionieren tut alles im 1., 3., 5. und soweiter Durchgang.

Hat jemand ne Idee woran das liegen könnte?

Danke.

  1. Hallo,

    ich habe hier folgendes c-Programmfragment:

    »»   while(counter<9)  
    
    >     {  
    >        [...]  
    >     }
    
    

    Hat jemand ne Idee woran das liegen könnte?

    Du Musst noch den Tastaturpuffer leeren. Dies machst du mit fflush( stdin );
    Dann kannst du eine Variable nicht 9 mal deklarieren:

    »»     while(counter<9)  
    
    >     {  
    >         int pos=-1;
    
    

    ▲▲▲
    Zudem ist dieser Schritt sinnlos, da du ihn eh wieder überschreibst, und ~~~c dazwischen diese Variable nicht verwendest:

    pos = ((int)readChar) - 48;

      
    Bei einer Fest definierten Anzahl an Durchläufen macht sich eine For-Schleife am besten:  
      
    ~~~c
    for( counter=0; counter<9; counter++ )  
    {  
        //...  
    }
    

    Zudem fehlt noch das Error-Handling. Was, wenn der User keine Zahl eingibt? Dann kann das Programm anstürzen oder zumindest Fehlerhaft arbeiten.
    Prüfe deswegen, ob der eingegebene Wert eine Zahl ist.

    MfG. Christoph Ludwig

    --
    Wo die Sprache aufhört, fängt die Musik an...
    Selfcode:  sh:) fo:) ch:° rl:( br:^ n4:} ie:{ mo:} va:) js:| de:] zu:) fl:( ss:| ls:~
    Go to this
    1. Hi,

      Du Musst noch den Tastaturpuffer leeren. Dies machst du mit fflush( stdin );

      dann muss man aber tatsächlich jedes Zeichen einzeln eingeben, dann die Eingabetaste drücken, dann das nächste. Ich bin davon ausgegangen, dass turgar die Ziffern der Reihe nach eingibt und erst zum Schluss die Eingabetaste drücken möchte - und hatte mich daher über das seltsame von ihm beschriebene Verhalten gewundert.

      Dann kannst du eine Variable nicht 9 mal deklarieren:

      »»     while(counter<9)

      »»     {
      »»         int pos=-1;

      
      >            ▲▲▲  
        
      Doch, ein C++-Compiler erlaubt das. In C++ können am Anfang jedes neuen Anweisungsblocks (also nach fast jeder öffnenden geschweiften Klammer) neue Deklarationen stehen. Das ist einer der Punkte, in denen C++ zur Schlampigkeit verleitet - in "reinem" C müsste man alle Deklarationen am Anfang des Funktionsblocks notieren.  
        
      
      > Zudem ist dieser Schritt sinnlos, da du ihn eh wieder überschreibst, und ~~~c
      
      dazwischen diese Variable nicht verwendest:  
      
      > »»     pos = ((int)readChar) - 48;
      
      

      Zumindest die Zuweisung eines Wertes ist an der Stelle sinnlos. Das gilt aber auch für die Zuweisung readChar = NULL aus turgars Originalcode. Schädlich ist das aber nicht ...

      Bei einer Fest definierten Anzahl an Durchläufen macht sich eine For-Schleife am besten:

      for( counter=0; counter<9; counter++ )

      {
          //...
      }

        
      \*unterschreib\*  
        
      
      > Zudem fehlt noch das Error-Handling. Was, wenn der User keine Zahl eingibt? Dann kann das Programm anstürzen oder zumindest Fehlerhaft arbeiten.  
      > Prüfe deswegen, ob der eingegebene Wert eine Zahl ist.  
        
      Du meinst Ziffer, nicht Zahl.  
      Ansonsten: ACK.  
      Was die fehlende Fehlerbehandlung für Folgen hat, können wir aber nicht abschätzen, da wir nicht wissen, was mit dem Wert von pos noch passiert.  
        
      So long,  
       Martin  
      
      -- 
      Die letzten Worte der Challenger-Crew:  
      Lasst doch mal die Frau ans Steuer!
      
      1. Hallo,

        dann muss man aber tatsächlich jedes Zeichen einzeln eingeben, dann die Eingabetaste drücken, dann das nächste. Ich bin davon ausgegangen, dass turgar die Ziffern der Reihe nach eingibt und erst zum Schluss die Eingabetaste drücken möchte - und hatte mich daher über das seltsame von ihm beschriebene Verhalten gewundert.

        na das gibt für mich ja überhaupt keinen Sinn...
        Somit entsteht für mich der Anschein, er will _eine_ zahl eingeben.
        Da kann er auch gleich ein String einlesen und atoi() anwenden ...
        Desweiteren wäre dann auch 9x die Ausgabe sinnlos.

        Doch, ein C++-Compiler erlaubt das. In C++ können am Anfang jedes neuen Anweisungsblocks (also nach fast jeder öffnenden geschweiften Klammer) neue Deklarationen stehen. Das ist einer der Punkte, in denen C++ zur Schlampigkeit verleitet - in "reinem" C müsste man alle Deklarationen am Anfang des Funktionsblocks notieren.

        Deswegen schreib ich lieber in C ;)
        In C++ sehe ich nur den Vorteil der OOP ... ansonsten verleitet es nur zu Faultheit!

        Zumindest die Zuweisung eines Wertes ist an der Stelle sinnlos. Das gilt aber auch für die Zuweisung readChar = NULL aus turgars Originalcode. Schädlich ist das aber nicht ...

        stimmt ... die Zeile hatte ich vergessen. Das ist der gleiche Fall wie bei "pos": In die Variable etwas speichern und ohne jegliche Verwendung danach wieder überschreiben ... überflüssig.

        Du meinst Ziffer, nicht Zahl.

        Jagut, bei mir das selbe *g*

        Ansonsten: ACK.
        Was die fehlende Fehlerbehandlung für Folgen hat, können wir aber nicht abschätzen, da wir nicht wissen, was mit dem Wert von pos noch passiert.

        In diesem Fall ist es aber notwendig. Da er die Zahlen sicher nicht umsonst einliest. Ansonsten könnte er gleich seinen Code markieren und auf "Enft" drücken ;)
        Ich finde aber, das das Error-Handling neben der Funktionalität das wichtigste eines Programmes ist. Man kann nie wissen, was z.b. ein DAU eingibt...

        MfG. Christoph Ludwig

        --
        Wo die Sprache aufhört, fängt die Musik an...
        Selfcode:  sh:) fo:) ch:° rl:( br:^ n4:} ie:{ mo:} va:) js:| de:] zu:) fl:( ss:| ls:~
        Go to this
      2. Moin.

        »» Dann kannst du eine Variable nicht 9 mal deklarieren:
        »» ~~~c

        »»     while(counter<9)

        »» »»     {
        »» »»         int pos=-1;

        
        > »»            ▲▲▲  
        >   
        > Doch, ein C++-Compiler erlaubt das [...]  
          
        Das ist keine C++-Eigenheit: Variablen mit Block-scope gibt's auch schon in C89.  
          
        Christoph
        
    2. Vielen Dank für die Hilfe!

      Was die Fehlerbehandlung und den Grund für den Counter angeht:
      Die verbergen sich hinter den drei Punkten.
      Mit dem überschreiben der Variablen hast du Recht, allerdings war das nur zu debug-Zwecken.

      Ich hab jetzt den fflush eingefügt, allerdings hat er keine Änderung bewirkt.

      Könntest du das evtl. nochmals genauer erläutern?

      1. Hallo,

        Ich hab jetzt den fflush eingefügt, allerdings hat er keine Änderung bewirkt.

        sollte aber...

        Könntest du das evtl. nochmals genauer erläutern?

        Hier mal ein (getestetes, funktionierendes) Beispiel:

          
        #include <stdio.h>  
          
        int main()  
        {  
        	//Hier legst du alle Variablen an. Diese Deklaration darfst du bei C-Programmen nur einmal machen.  
            char readChar;  
            int  pos      =  0;  
            int  counter  =  0;  
          
            //Hier folgt eine definierte Schleife. Diese Schleife läuft, sofern du "counter" nicht in ihr verwendest nur 9 mal durch.  
            for( counter=0; counter<9; counter++ )  
            {  
                printf( "Insert Position: " );  
          
                //Hier liest du ein Zeichen ein und speicherst es in readChar. Castest du die Variable nach Integer, so steht hier der ASCII-Wert  
                //Gleichzeitig gibt getchar den eingegebenen Wert aus.  
                readChar = getchar();  
          
                //Nun die Ausgabe der Variable. Hier siehst du außerdem, das "readChar" automatisch  
                //nach Integer gecastet wird. Somit ergibt z.b. "2" - 48  -->  50-48=2.  
                printf( " [%i]\n", ( readChar - 48 ) );  
          
                //Zur Sicherheit immer noch den Tastaturpuffer leeren. Nun können wirklich keine Zeichen mehr eingelesen werden  
                //die sich noch im Puffer verstecken ;)  
                fflush( stdin );  
            }  
          
            //Die Ausgabe dient dazu, das der User weis: "Hier ist Stopp" ... (bzw. ich, weil ich nicht nachzähle, wie oft ich eingebe ;)  )  
            printf( "\n\nEND" );  
          
            //Damit das Programm nicht sofort beendet, musst du es anhalten. Dafür gibt es drei Methoden:  
            //system("pause");  <-- Schreibt den Text "Drücken Sie eine Taste zum Beenden" und wartet auf Tastendruck( finde ich wegen der eigenständigen Ausgabe nicht schön  
            //sleep(5000);      <-- Hier wird bis zum beenden 5 Sekunden gewartet. Dann bricht es unwilkürlich ab.  
            getch(); //         <-- Finde ich als beste Methode, da hier keine Ausgabe erfolgt und der Benutzer entscheiden kann, wann er beendet  
          
            //Rückgabewert an das Betriebssystem  
            return 0;  
        }  
          
        
        

        Ich hoffe, die Inline-Doku reicht ;)

        MfG. Christoph Ludwig

        --
        Wo die Sprache aufhört, fängt die Musik an...
        Selfcode:  sh:) fo:) ch:° rl:( br:^ n4:} ie:{ mo:} va:) js:| de:] zu:) fl:( ss:| ls:~
        Go to this
        1. Die Art der Dokumentation ist klasse und war einiges an Aufwand.
          Danke hierfür!

          Ich geb dir auch in so gut wie allen Punkten Recht, allerdings bewirkt der fflush()-Aufruf leider nichts.

          Das Result bleibt nach wie vor das Gleiche.

          Hier mal zur Verdeutlichung eine gekürzte Ausgabe:
          Insert position:
          1
                 [... hier steht der Rest der Ausgabe ...]
          Insert position:
          Insert position:

          So und nun habe ich leider den Fall, das nach meiner gesamten Ausgabe zunächst wieder um eine Eingabe gebeten wird, diese aber nicht abgewartet wird.
          Also läuft das Programm erneut bis zur Eingabe-Aufforderung.

          Der Grund dafür scheint die Eingabe von Enter zu sein.
          Gebe ich "123\n" ein läuft das Ganze entsprechend mehrmals hintereinander ab.

          Ich bräuchte also etwas um den Gesamten puffer zu leeren (hier scheint der flush nicht auszureichen).

          1. Hallo,

            Also ich kann dein Problem nicht nachvollziehen. Dies ist meine Ausgabe der Konsole, mit dem Programm, welches ich vorhin gepostet habe( ich hab 9 einstellige Ziffern ausgegeben )

            Insert Position: 1
             [1]
            Insert Position: 2
             [2]
            Insert Position: 3
             [3]
            Insert Position: 4
             [4]
            Insert Position: 5
             [5]
            Insert Position: 6
             [6]
            Insert Position: 7
             [7]
            Insert Position: 8
             [8]
            Insert Position: 9
             [9]

            END

            Nun eine Ausgabe, wenn ich mehrstellige Ziffern eingebe(, was natürlich fehlschlägt wenn man mal überlegt, dass es nicht getString sondern ausgeschrieben getCharacter( --> lese _ein_ Zeichen) heist ):

            Insert Position: 123
             [1]
            Insert Position: 456
             [4]
            Insert Position: 789
             [7]
            Insert Position: 963
             [9]
            Insert Position: 852
             [8]
            Insert Position: 741
             [7]
            Insert Position: 987
             [9]
            Insert Position: 654
             [6]
            Insert Position: 321
             [3]

            END

            Beschreibe dein Problem genauer. Zeige, was du willst und was du wegen welchem Code nicht erreichst.

            MfG. Christoph Ludwig

            --
            Wo die Sprache aufhört, fängt die Musik an...
            Selfcode:  sh:) fo:) ch:° rl:( br:^ n4:} ie:{ mo:} va:) js:| de:] zu:) fl:( ss:| ls:~
            Go to this
            1. Bei mir sieht das nach wie vor anders aus...

              Ich habe jetzt mal folgendes zum Debuggen mit dazu genommen:
              printf("readChar = %c\n", readChar);
                      printf("Insert position:\n");
                      readChar = getchar();
                      pos = ((int)readChar) - 48;

              Die erste printf-Zeile zeigt mir immer das gegenwärtige Zeichen in readChar an.

              Bei einer Eingabe von 123\n erhalte ich dabei:
              Insert position:
              123
                      [...]
              readChar = 1
              Insert position:
                     [...]
              readChar = 2
              Insert position:
                     [...]
              readChar = 3
              Insert position:
              wrong input!
              pos was -38
              readChar =

              Deshalb verstehe ich das Ganze so, als würde bei jedem Programmdurchlauf lediglich ein Zeichen aus dem Puffer konsumiert werden.
              Siehe beispielsweise den letzten Durchgang der die Eingabe von return konsumiert.
              Bevor nicht alle Zeichen verbraucht sind werde ich nicht nach einer weiteren Eingabe gefragt und bin blos noch Zuschauer...

              Dazu noch eine weitere Frage:
              Welchen compiler nutzt du?
              Ich habe hier den gcc unter Debian.

              1. Hallo,

                Dazu noch eine weitere Frage:
                Welchen compiler nutzt du?
                Ich habe hier den gcc unter Debian.

                Ich nutze Dev C++ von Borland.
                aber wie gesagt ... da das Programm bei mir funktioniert, kann ich dein Problem nicht nachvollziehen ...
                Kopier mal den genauen Quelltext, den ich dir gepostet habe, und kompilier ihn .. danach kopier mal die Ausgabe der Konsole hier rein( rechts Klick -> alles kopieren --> Mit [Enter] in die zwischenablage )
                Dann hab ich mal nen Vergleich.

                MfG. Christoph Ludwig

                --
                Wo die Sprache aufhört, fängt die Musik an...
                Selfcode:  sh:) fo:) ch:° rl:( br:^ n4:} ie:{ mo:} va:) js:| de:] zu:) fl:( ss:| ls:~
                Go to this
                1. Ich habe nun an dem windows-xp Rechner eines Bekannten compilert (unter visiual studio).

                  Dort läuft mein Code einwandfrei durch.

                  Desweiteren habe ich mir noch die Dokumentationen über den gcc und posix angesehen.
                  So wie's aussieht ist der gcc in dieser Hinsicht einfach etwas "strenger".

                  Auf jeden Fall läuft das Ganze.
                  Wie ich es allerdings auf die Linux Kiste portieren soll ist mir im Moment noch ein Rätsel...