compiler Fehler?

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Benutzeravatar
marmeladebomber
Beiträge: 1002
Registriert: 09.11.2002 23:34:58
Wohnort: Österreich/Tirol

compiler Fehler?

Beitrag von marmeladebomber » 04.12.2003 15:19:48

Folgendes Problem:
Dies ist ein kleiner Taschenrechner, geschrieben in C. Warum wird hier bei der ersten Eingabe der erste Buchstabe verschluckt?

Die erste Operation zb:
12+12=
Ergebnis = 14
Nochmal das gleiche:
12+12=
Ergebnis = 24

Könnt ihr euch das Erklären?
Ich verwende den gcc 3.2.3

Anbei der C-Code

Christoph

Code: Alles auswählen

#include <stdio.h>
#include <ctype.h>

#define FALSE 0
#define TRUE !FALSE


void main ()
{
  int fertig; //Schleifenende
  char c;
  double ergebnis; //Ergebnis, wird durch die Operationen verändert
  double zwergebnis; //Zwischenspeicher der für den zweiten Operand benutzt wird

  
  ergebnis = FALSE;
  zwergebnis = FALSE;
   
  printf("***************************\nq zum beenden\nc um Speicher zu löschen\nmögliche Operatoren:\n+ - */\n");
  printf("***************************\nEingabe nach diesem Muster:\nx+y=\n***************************\n");
           
  fertig = FALSE;
  while (!fertig)
  {
    //scanf("%c", &c);
    c = (char)toupper(getchar());
    
    switch (c)
    {
      case '+': //Addieren
         scanf("%lf", &zwergebnis);
         //fflush(stdin);
         ergebnis += zwergebnis;
      break;

      case '-':  //Subtrahieren
         scanf("%lf", &zwergebnis);
         ergebnis -= zwergebnis;
      break;

      case '*':  //Multiplizieren
         scanf("%lf", &zwergebnis);
         ergebnis *= zwergebnis;
      break;

      case '/':  //Dividieren
         scanf("%lf", &zwergebnis);
         ergebnis /= zwergebnis;
      break;

      case '=':  //Ergebnis ausgeben
        printf("ergebnis \t%.3lf\n", ergebnis);
      break;

      case 'F':  //zwergebnis ausgeben
        printf("zwergebnis \t%.3lf\n", zwergebnis);
      break;      
                        
      case 'Q': //Programm beenden
      case 'X':
        return (0);
      break;

      case'C': //clear ergebnis
        ergebnis = FALSE;
        zwergebnis = FALSE;
      break;

      default:
         scanf("%lf", &ergebnis);
      break;

      fertig = TRUE; //Schleifenende
    }  //Ende switch
  } //Ende von while
  return (0);
}

Benutzeravatar
blackm
Moderator und Co-Admin
Beiträge: 5921
Registriert: 02.06.2002 15:03:17
Lizenz eigener Beiträge: MIT Lizenz

Beitrag von blackm » 04.12.2003 16:36:06

Hab das mal in ein passenderes Forum verschoben...
Schöne Grüße

Martin

Neu im Forum? --> https://wiki.debianforum.de/debianforum ... tensregeln
Log- und Konfigurationsdatein? --> pastebin.php
Forum unterstützen? --> https://wiki.debianforum.de/debianforum.de/Spenden

Benutzeravatar
spiffi
Beiträge: 1128
Registriert: 09.08.2003 19:02:27

Beitrag von spiffi » 04.12.2003 17:19:12

Das ist kein Eingabefehler, sondern ein Programmierfehler.
Entgegen dem, was Du wahrscheinlich vermutet hast, kommt der Aufruf von getchar erst nach der Eingabe einer durch Return abgeschlossenen Zeile zurück.

Was passiert, ist folgendes:
Dein Programm läuft bis zur Zeile
c = (char)toupper(getchar());
durch und wartet nun auf Deine Eingabe.

Du gibst
10+20=<RETURN>
ein. Nachdem Du <RETURN> gedrückt hast, kehrt der Aufruf von getchar zurück, und liefert das erste Zeichen der Eingabe.
Somit ist c='1' und im Eingabestrom verbleibt "0+20=\n".
Der switch('1') läuft in den default-Zweig.
scanf("%lf", &ergebnis) liest nun aus dem Eingabestrom den nächsten double-Wert aus.
Das ist in diesem Falle die 0. scanf entfernt also die 0 aus dem Eingabestrom, der danach so aussieht: "+20=\n"
Es folgt der nächste Schleifendurchlauf und der nächste Aufruf von getchar.
Damit haben wir c='+', im Eingabestrom verbleiben "20=\n"
Der switch läuft in den case '+'.
Hier wird dem Eingabestrom der zweite double-Wert entnommen.
zwergebnis=20.0, im Eingabestrom verbleibt "=\n".
Der nächste Durchlauf geht in den case '=', das Ergebnis wird ausgegeben. Im Eingabestrom verbleibt "\n".
Der nächste Aufruf von getchar liefert nun genau dieses "\n" zurück, der darauffolgende switch('\n') springt in den default,
Dort wird per scanf die nächste double-Zahl aus dem Eingabedatenstrom gelesen. Doch der Datenstrom ist leer, wir haben das abschließende <Return> ja schon mit dem Aufruf von getchar konsumiert.
Also blockt der Aufruf von scanf, bis wieder Daten im Eingabestrom stehen.
Und dies passiert genau dann, wenn Du die nächste Zeile eingegeben und mit Return abgeschlossen hast.

Benutzeravatar
marmeladebomber
Beiträge: 1002
Registriert: 09.11.2002 23:34:58
Wohnort: Österreich/Tirol

Beitrag von marmeladebomber » 04.12.2003 20:37:48

ahh! ich verstehe!

Wie würdest am elegantesten dies lösen/umgehen?

Christoph
der gerade seine ersten Schritte in C macht

Benutzeravatar
spiffi
Beiträge: 1128
Registriert: 09.08.2003 19:02:27

Beitrag von spiffi » 04.12.2003 23:17:15

Code: Alles auswählen

default:
   if( (c == '.') || (isdigit(c)) ) {
      ungetc(c, stdin);
      scanf( "%lf", &ergebnis );
   }
   break;
Desweiteren kannst Du Dir die ganze Klamotte mit der Variable fertig sparen. Die Zeile

Code: Alles auswählen

fertig=TRUE;
wird ohnehin nie erreicht.
Stattdessen kannst Du die Schleife über while(1) laufen lassen.

Dann noch ein paar kleine Schönheitsfehler:
main gibt immer ein int zurück. Also int main() statt void main().
return ist ein Schlüsselwort, keine Funktion. Die Klammern um den Rückgabewert bei return kannst Du Dir also sparen.

Benutzeravatar
marmeladebomber
Beiträge: 1002
Registriert: 09.11.2002 23:34:58
Wohnort: Österreich/Tirol

Beitrag von marmeladebomber » 05.12.2003 16:46:44

Danke! Hat mir sehr geholfen!

Antworten