Taschenrechner: Keine Eingabe möglich



  • return val[--sp];
    

    Hier bricht er immer ab und lässt nicht zu, dass es weiter geht. Die Eingabe von Zahlen wird gar nicht berücksichtigt, was ich daran gesehen habe, dass dabei keine Reaktion innerhalb des Quellcodes geschehen ist.



  • Ok ich seh schon was das Problem ist.
    Mach dir mal Gedanken darüber was du mit sp anstellst und welchen Wert es hat, wenn du es verwendest.
    Außerdem solltest du dir mal Gedanken darüber machen wie lange lokale Variablen gültig sind ;).



  • Ich lese gerade etwas von einem rudimentären Taschenrechner .... Gibts da Beispiele für solch einen Taschenrechner im Netz ?



  • Ähm, hast du deinen Fehler jetzt schon gefunden oder brauchst du noch einen direkteren Hinweis?



  • Ne ich hab noch keine Lösung gefunden, aber ich hab eine alternative Lösung gefunden:

    #include <stdio.h> 
    
    int main () 
    { 
    
        int zahl1; 
        int zahl2; 
        int zeichen; 
    
        printf ("Bitte geben Sie Ihre erste Zahl ein: \n"); 
        scanf ("%d", &zahl1); 
        printf ("Nun waehlen Sie bitte den Zeichenerator aus -> 1:+  2:-  3:*  4:/  \n"); 
        scanf ("%d", &zeichen); 
        printf ("Bitte geben Sie Ihre zweite Zahl ein: \n"); 
        scanf ("%d", &zahl2); 
    
        switch (zeichen) 
        { 
        case 1: 
            printf ("Ihre Aufgabe lautet somit %d + %d = %d\n", zahl1, 
                zahl2, zahl1 + zahl2); 
            break; 
    
        case 2: 
            printf ("Ihre Aufgabe lautet somit %d - %d = %d\n", zahl1, 
                zahl2, zahl1 - zahl2); 
            break; 
    
        case 3: 
            printf ("Ihre Aufgabe lautet somit %d * %d = %d\n", zahl1, 
                zahl2, zahl1 * zahl2); 
            break; 
    
        case 4: 
            printf ("Ihre Aufgabe lautet somit %d / %d = %d\n", zahl1, 
                zahl2, zahl1 / zahl2); 
            break; 
        } 
    
        return 0; 
    }
    

    Damit geht es auch, aber ich setze mich gleich nochmal dran, damit die andere Lösung auch funktioniert und wenn ich Fragen habe, dann frag ich nochmal nach !



  • Ich frage mich, warum bei der Alternative, das mit 1, 2, usw. für die Operatoren verwendet wird. Da braucht man doch nur das Zeichen (%c) einlesen und das Zeichen abfragen 🙄 .
    Außerdem ist es buggy. Gib mal folgendes Beispiel ein:
    10 / 0

    Zu deiner ersten Lösung. Schau dir nochmal deine Funktionen pop() und push() an. Du verwendest dort eine LOKALE Variable (sp) und außerdem wird sie nirgendwo initialisiert! Die zweite lokale Variable (val) gibt mir auch zu denken. Ich schätze das musst du nochmal überdenken.
    Wie schon gesagt, denk nochmal nach, wie lange lokale Variablen gültig sind. Wenn du es nicht weißt, dann frag einfach nach :).



  • Ich erarbeite derzeit nochmal eine andere Lösung:

    #include <stdio.h>
    #include <ctype.h>
    
    #define MAXLINE 100
    
    double atof(char s[]);
    int getline(char line[], int max);
    
    int main(int argc, char* argv[])
    {
      double sum, atof(char []);
      char line[MAXLINE];
    
      sum = 0;
      while (getline(line, MAXLINE) > 0)
        printf("\t%g\n", sum += atof(line));
            return 0;
    }
    
    double atof(char s[])
    {
      double val, power;
      int i, sign;
      for (i = 0; isspace(s[i]); i++)
        ;
        sign = (s[i]) == '-' ? -1 : 1;
        if (s[i] == '+' || s[i] == '-')
          i++;
          for (val = 0.0; isdigit(s[i]); i++)
            val = 10.0 * val + (s[i] - '0');
          if (s[i] == '.')
            i++;
          for (power = 1.0; isdigit(s[i]); i++)
          {
            val = 10.0 * val + (s[i] - '0');
            power *= 10.0;
          }
          return sign * val / power;
    }
    
    int getline(char line[], int maxline)
     {
      int i, c;
      if(c == '\n')
      {
       line[i] = c;
       ++i;
      }
      line[i] = c;
    
      if (c == '\t')
      {
      line[i] = c;
      ++i;
      } else
      line[i] = c;
      return c;
    }
    

    Es gibt keine Fehlerangabe, aber ich bekomme beim Programmablauf einen Fehler, der auf eine Nutzung von Speicherplatz zurückzuführen ist.
    Ich benutze also einen Speicherbereich, den ich gar nicht benutzen darf ! 😮



  • Gleiches Problem wie bei pop() und push().

    Du verwendest Variablen ohne sie zu initialisieren!

    In der Funktion getline() definierst du i und c. Was steht denn deiner Meinung nach in i und c drin, wenn du sie das erste mal verwendest??



  • Nach meiner Ansicht hat es den Grund, dass der Wert von c und i in der Funktion von "getline" irgendwie nicht stimmt.
    Selbst mit dem Debugger komm ich nicht genau auf die Spur von dem Fehler und kann auch daher nicht so genau eine Aussage machen !

    ;): wir haben gleichzeitig eben geschrieben 🙂

    int getline(char line[], int maxline)
     {
      int i, c;
      c = 0;
      i = 0;
      if(c == '\n')
      {
       line[i] = c;
       ++i;
      }
      line[i] = c;
    
      if (c == '\t')
      {
      line[i] = c;
      ++i;
      } else
      line[i] = c;
      return c;
    }
    

    Diese Version beinhaltet eine Initialisierung, aber das Problem dabei ist auch, dass ich gar keine Eingabe machen kann.
    Ergo kann ich also auch keine Zahlen eingeben, die der Taschenrechner berechnen soll. Mit der Initialisierung der getline-Funktion wird eine Endlosschleife erzeugt die immer Nullen ausgibt.



  • lol?

    Ist der Code dein Ernst?

    int getline(char line[], int maxline)
    {
      int i, c;
      c = 0;
      i = 0;
    // ...
      if(c == '\n') // c ist 0!
    // ...
      if (c == '\t') // c ist 0!
    


  • Gut jetzt kannst du zumindest schon mal keine Speicherverletzung mehr kriegen. In uninitialisierten Variablen steht übrigens irgendein Zufallswert oder besser gesagt der Wert, der an der Speicherstelle steht beim Reservieren des Speichers.

    Um jetzt deine Eingabefunktion zu vollenden musst du eine Funktion aufrufen, die ein Zeichen von der Tastatur liest. Erraten was du willst, kann der Compiler nämlich noch nicht ;). Das Zeichen, dass du von der Tastatur einliest musst dann natürlich c zuweisen.

    Aja und die Funktion getline() an sich solltest du auch nochmal überarbeiten. Im Endeffekt sollte es so aussehen:

    Die Funktion liest ein Zeichen von der Tastatur ein.
    Wenn das Zeichen ein Zeilenumbruch ist, dann wird die Eingabe beendet.
    Wenn das Zeichen kein Steuerzeichen ist, dann wird es in den übergebenen Buffer geschrieben. (Das nächste Zeichen muss dann an die nächste Stelle geschrieben werden!) Dabei erhöht sich der Zeichenzähler.
    Wenn der Zeichenzähler das Maximum erreicht, wird die Eingabe beendet. (Wir wollen ja keinen Bufferoverflow verursachen ;))

    Rückgabewert ist die Anzahl der eingelesenen Zeichen.



  • So ich hab jetzt getline nochmal anders geschrieben, weil mir die Funktion auch nicht so wirklich gepasst hat.

    int getline(char line[], int maxline)
    {
     int c, i;
     for (i = 0; i < MAXLINE-1 && (c = getchar()) != EOF && c != '\n'; ++i)
     	line[i] = c;
     if (c == '\n')
     {
     line[i] = c;
     ++i;
     }
     line[i] = '\0';
     return i;
    }
    

    Ich kann nun mit diesem rudimentären Taschenrechner + und - berechnen, aber für mehr langt es derzeit noch nicht.



  • So nachdem nun der normale Taschenrechner geht, muss ich mal sehen, wie ich die sonstigen Funktionen darin einbaue.
    Funktionen, die der Taschenrechner beherrschen soll:
    - Plus, Minus
    - *, /
    - Wurzel und Quadrat
    - Sinus und Cosinus
    - Eingabe von Buchstaben



  • cHillb3rT schrieb:

    int getline(char line[], int maxline)
    {
     int c, i;
     for (i = 0; i < MAXLINE-1 && (c = getchar()) != EOF && c != '\n'; ++i)
     	line[i] = c;
     if (c == '\n')
     {
     line[i] = c;
     ++i;
     }
     line[i] = '\0';
     return i;
    }
    

    Du weißt aber schon, dass ein Unterschied zwischen maxline und MAXLINE besteht, oder??

    * und / dürften kein Problem sein. Bedenke allerdings, dass du bei / eine bestimmte Abfrage einbauen musst, sonst stürzt dir das Programm ab!

    AJ schrieb:

    Außerdem ist es buggy. Gib mal folgendes Beispiel ein:
    10 / 0

    😉



  • Ich arbeite jetzt gerade an der Version vom Anfang....
    Da hatte ich ja das Problem, das ich nicht mal Zahlen eingeben konnte... nun geht das, aber ich bekomme gesagt, dass mein "Stack" zu hoch ist.

    Wahrscheinlich hängt das mit der lokalen Variablen zusammen und nun frag ich mal in die Runde, wie genau man das Problem beheben kann bzw könnte !



  • Also ich bezweifle, dass deine paar Variablen den Stack sprengen könnten. Hast du dran was verändert? Zeig bitte mal den aktuellen Stand.



  • Das ist derzeit der Stand:

    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    
    #define MAXOP 100
    #define NUMBER '0'
    #define BUFSIZE 100
    
    int getop(char []);
    void push(double f);
    double pop(void);
    int getch(void);
    void ungetch(int);
    
    int main(int argc, char* argv[])
    {
      int type;
      double op2;
      char s[MAXOP];
      while ((type = getop(s)) != EOF)
      {
        switch(type)
        {
          case NUMBER:
            push(atof(s));
            break;
          case '+':
            push(pop() + pop());
            break;
          case '*':
            push(pop() * pop());
            break;
          case '-':
            op2 = pop();
            push(pop() - op2);
            break;
          case '/':
            op2 = pop();
            if (op2 != 0.0)
              push(pop() / op2);
            else
              printf("error: zero divisor\n");
            break;
          case '%':
            op2 = pop();
            if (op2 != 0.0)
              push(fmod(pop(), op2));
            else
              printf("error: zero divisor\n");
            break;
          case '\n':
            printf("\t%.8g\n", pop());
            break;
          default:
            printf("error: Unknown command %s\n", s);
            break;
            }
      }
      return 0;
    }
    
    void push(double f)
    {
      int sp;
      char val[MAXOP];
      if (sp < MAXOP)
        val[sp++] = f;
      else
        printf("error: stack full, can't push %g\n", f);
    }
    
    double pop(void)
    {
      int sp = 0;
      double val[MAXOP];
      if (sp > 0)
        return val[--sp];
      else
      {
        printf("error: stack empty\n");
        return 0.0;
      }
    }
    
    int getop(char s[])
    {
      int i, c;
      while ((s[0] = c = getch()) == ' ' || c == '\t')
      ;
        s[1] = '\0';
        if (!isdigit(c) && c != '.')
          return c;
          i = 0;
          if (isdigit(c))
            while (isdigit(s[++i] = c = getch()))
            ;
            if (c == '.')
              while (isdigit(s[++i] = c= getch()))
              ;
              s[i] = '\0';
              if (c != EOF)
                ungetch(c);
              return NUMBER;
    }
    
    int getch(void)
    {
      char buf[BUFSIZE];
      int bufp = 0;
      return (bufp > 0) ? buf[--bufp] : getchar();
    }
    
    void ungetch(int c)
    {
      char buf[BUFSIZE];
      int bufp = 0;
      if (bufp >= BUFSIZE)
        printf("ungetch: Too many characters\n");
      else
        buf[bufp++] = c;
    }
    


  • die getop-Funktion wurde weiter bearbeitet von mir:

    int getop(char s[])
    {
      int i, c;
      while ((s[0] = c = getch()) == ' ' || c == '\t')
      ;
        s[1] = '\0';
        i = 0;
        /* Wenn "c" kein Punkt ist, dann wird der Wert von
        c zurückgegeben und "i" auf Null gesetzt. */
        if (!isdigit(c) && c != '.' && c != '-')
          return c;
          if (c == '-')
            if (isdigit(c = getchar()) || c == '.')
              s[++i] = c;
            else
            {
              if (c != EOF)
                ungetch(c);
              return '-';
            }
          /* Man sammelt nun den ganzzahligen Teil vor einem möglichen bestehenden
          Punkt ein */
          if (isdigit(c))
            while (isdigit(s[++i] = c = getch()))
              ;
            /* Wenn "c" ein Punkt ist wird ab diesem Punkt dann der Dezimalbereich
            eingespeichert. Wenn die obere Bedingung erfüllt ist, dann ist das Ende des Wortes
            erreicht. Danach wird noch überprüft ob es auch das Ende der Eingabe ist. Wenn
            es das Ende des Wortes ist, dann wird die Konstantenvariable NUMBER zurückgegen, die
            den Wert 0 besitzt und somit wieder den Anfang eines Wortes markiert. Wenn es das
            Ende der Eingabe ist übernimmt die Funktion ungetch die Verarbeitung von "c" */
            if (c == '.')
              while (isdigit(s[++i] = c = getch()))
              ;
              s[i] = '\0';
              if (c != EOF)
                ungetch(c);
              return NUMBER;
    }
    


  • Stand nach einer Stunde programmieren:
    - Egal welche Zahl ich eingebe, es wird mir angezeigt, dass der "stack" voll ist.
    - Es wird aufgrund dieser Tatsache keine Rechenoperation durchgeführt

    Hat einer von euch eine Idee, was falsch sein kann ?!?



  • Ok, ich glaube das ist wirklich ein hartnäckiges Problem, aber nur, wenn eine der beiden folgenden Fehlermeldungen auftritt:
    error: stack empty
    error: stack full, can't push ...

    🤡 🙄

    Ich hab dir eigentlich schon hundertmal ("leicht" übertrieben) gesagt, dass deine Variablen sp und val LOKAL sind und dass sp nicht INITIALISIERT ist (mittlerweile wenigstens bei pop).
    Es kann so einfach nicht funktionieren. So wie du es vorhast, muss sp und val global sein und sp muss unbedingt mit 0 initialisiert sein!
    Die bessere Variante wäre natürlich, dass du die Variablen als Parameter übergibst, allerdings ändert das nichts daran, dass sp mit 0 initialisiert werden muss; in jedem Fall.


Anmelden zum Antworten