C Code Korrekturlesen bitte, besonders Menüstruktur! einfacher "Taschenrechner"



  • Hallo,

    ich bin grade dabei mir C so ein wenig selbstständig beizubiegen und würde euch gerne bitten mal mein kleines Programm Korrektur zu lesen. Bitte schaut euch besonders mal die Menüstruktur an, ich habe sie ohne while-schleife etc gemacht, und es funktioniert alles wunderbar (zumindest hab ich keinen fehler gefunden..)
    Falls euch IRGENDWAS auffällt, bitte einfach ALLES anmerken! Bin über jede Antwort glücklich! Vielen Dank im Voraus!

    Grüße

    Hier der Code:

    #include <stdio.h>
    #include <stdlib.h>
    
    double addition();
    double subtraktion();
    double multiplikation();
    double division();
    void weiterrechnen();
    
    int main()
    {
        int auswahl = 0;
    
     printf("Taschenrechner by M.B Version 1.0\n\n\n");
     printf("Hallo, was wollen Sie tun?\n\n [1] Addition\n\n [2] Subtraktion\n\n"); 
     printf(" [3] Multiplikation\n\n [4] Division\n\n");
     printf("Ihre Wahl: ");
    
     scanf("%i",&auswahl);
     getchar();
    
     switch(auswahl) {
                     case 1 : addition();
                              break;
                     case 2 : subtraktion();
                              break;
                     case 3 : multiplikation();
                              break;
                     case 4 : division();
                              break;
                     default : printf("Falsche Eingabe\n\n");
                     }
    
      system("PAUSE");	
      return 0;
    }
    
    double addition() {
    
           double a=0, b=0;
           char weiter;
    
           printf("\nBitte geben Sie die Zahlen ein (ohne '+'): ");
           scanf("%lf%lf",&a,&b);
           getchar();
    
           printf("Ihr ergebnis lautet: %lf \n\n", a+b);
    
           weiterrechnen ();
    
           system("PAUSE");
           return 0;
           }
    
    double subtraktion() {
    
           double a=0,b=0;
    
           printf("\nBitte geben Sie die Zahlen ein (ohne '-'): ");
           scanf("%lf%lf",&a,&b);
           getchar();
    
           printf("Ihr Ergebnis lautet: %lf \n\n", a-b);
    
           system("PAUSE");
           return 0;
            }
    
    double multiplikation() {
    
           double a=0,b=0;
    
           printf("\nBitte geben Sie die Zahlen ein (ohne '*'): ");
           scanf("%lf%lf",&a,&b);
           getchar();
    
           printf("Ihr Ergebnis lautet: %lf \n\n", a*b);
    
           weiterrechnen ();
    
           system("PAUSE");
           return 0;
            }
    
    double division() {
    
           double a=0,b=0;
    
           printf("\nBitte geben Sie die Zahlen ein (ohne '/'): ");
           scanf("%lf%lf",&a,&b);
           getchar();
    
           printf("Ihr Ergebnis lautet: %lf \n\n", a/b);
    
           weiterrechnen ();
    
           system("PAUSE");
           return 0;
            }
    
    void weiterrechnen() {
    
         char weiter;
    
         printf("Wollen Sie weiterrechnen? [j] / [n]: \n");
    
         scanf("%c",&weiter);
         getchar();
    
         switch (weiter) {
    
                           case 'j' : main();
                           break;
                           case 'J' : main();
                           break;
                           case 'n' : printf("Auf Wiedersehen!\n");
                           break;
                           case 'N' : printf("Auf Wiedersehen!\n\n");
                           break;
                           default : printf("Falsche Eingabe!\n\n");
                                     weiterrechnen();
                           } 
         }
    


  • Bitte schaut euch besonders mal die Menüstruktur an, ich habe sie ohne while-schleife etc gemacht, und es funktioniert alles wunderbar

    Schlechte Idee. weiterrechnen() rekursiert wieder und wieder bis der Speicher ausgeht. Eine Schleife wäre viel schlauer.
    🙂



  • erstmal herzlichen Dank für die schnelle Antwort!

    Meinst du weiterrechnen() rekursiert immer deshalb weiter, weil ich es im letzten switch case bei default wieder aufrufen lasse? oder warum rekursiert es?



  • Deine Funktionen rufen sich munter gegenseitig auf. main() beginnt, ruft eine der vier Rechenfunktionen auf. Die ruft dann weiterrechnen() auf, weiterrechnen() ruft sich selbst oder main() auf. Und das ganze ohne definitives Ende. Das kostet für jeden neuen Aufruf zusätzlichen Speicher, und der geht bekanntlich irgendwann mal aus.

    Es gibt Sprachen, die solche Sachen problemlos mit konstantem Speicherverbrauch erledigen, aber C gehört nicht dazu (tail calls sind das Stichwort). Der gcc kann tail call optimizations als Erweiterung, aber ANSI (it its wisdom) will davon nichts wissen.
    🙂



  • ahh, ich glaube ich verstehe. sprich die funktionen die aufgerufen wurden, beenden sich einfach nicht wieder? ist es dsa was du meinst? gibts dafür denn keinen befehl der dann einfach sagt, diese funktion ist fertig abgearbeitet und ende?



  • Nö, wie denn auch? Die müssen doch abwarten, bis die Funktionen fertig sind, die sie selbst aufgerufen haben, und das nimmt in deinem Fall erst dann ein Ende, wenn man sagt, dass man nicht mehr weiterrechnen mag. Irgendwann fliegt dir das Ding dann um die Ohren.
    🙂

    Sprachen, in denen man das so sagen könnte, sind zB Lua und Scheme.

    Schreib das nächste mal vor den Code [cpp] und danach [/cpp]



  • ah, herzlichen Dank, jetzt hab ichs verstanden. gut, dann tüftel ich mal weiter 😃

    edit: danke für den Hinweis mit [cpp] [/cpp !!



  • So, ich habe den Code jetzt nochmal ganz anders aufgezogen und würde gerne wissen ob das jetzt besser ist bzw. was verbesserungswürdig ist. Vielen Dank im Voraus!

    Anmerkung: "Subtraktion" ist absolut identisch vom Aufbau etc. wie "Addition"

    #include <stdio.h>
    #include <stdlib.h>
    
    int Hauptmenue();
    int Addition();
    int Subtraktion();
    
    int main()
    {
      int status = 1 ;
    
      printf("Taschenrechner Version 2\n\n");
    
      while (status != 0)
      {
            status = Hauptmenue();
            } 
    
      system("PAUSE");	
      return 0;
    }
    
    int Hauptmenue()
    {
        char auswahl;
    
        printf("Hallo, bitte waehlen Sie eine Funktion:\n\n");
        printf("[a] - Addition\n");
        printf("[b] - Subtraktion\n\n");
        printf("[c] - Beenden\n\n");
        printf("Ihr Auswahl: ");
    
        scanf("%c",&auswahl);
        getchar();
    
        if (auswahl == 'a')
        {
                    Addition();
                    }
                    else if(auswahl == 'b')
                    {
                         Subtraktion();
                         }
                         else if (auswahl == 'c')
                         {
                              printf("Auf Wiedersehen\n\n");
                              return 0;
                              }
                              else 
                              {
                                   printf("Falsche Eingabe\n\n");
                                   return 0;
                                   }
        return 1;
    
    }
    
    int Addition()
    {
        int zahl1=0, zahl2=0;
        char weiter;
    
        printf("Bitte geben Sie die beiden Zahlen ein:\n");
    
        printf("Zahl_1 = ");
        scanf("%i",&zahl1);
        getchar();
    
        printf("\nZahl_2 = ");
        scanf("%i",&zahl2);
        getchar();
    
        printf("\nIhr Ergebnis: %i\n",zahl1+zahl2);
    
        printf("Wollen Sie weiterrechnen [j] \\ [n]: ");
        scanf("%c",&weiter);
        getchar();
    
        if (weiter == 'j' || weiter == 'J')
        {
                   return;
                   }
                   else if (weiter == 'n' || weiter == 'N')
                   {
                        printf("\nSchade, auf Wiedersehen!\n");
                        return 0;
                        }
                        else
                        {
                            printf("Falsche Eingabe!");
                            return 0;
                            }
    }
    
    int Subtraktion()
    {
        int zahl1=0, zahl2=0;
        char weiter;
    
        printf("Bitte geben Sie die beiden Zahlen ein:\n");
    
        printf("Zahl_1 = ");
        scanf("%i",&zahl1);
        getchar();
    
        printf("\nZahl_2 = ");
        scanf("%i",&zahl2);
        getchar();
    
        printf("\nIhr Ergebnis: %i\n",zahl1-zahl2);
    
        printf("Wollen Sie weiterrechnen [j] \\ [n]: ");
        scanf("%c",&weiter);
        getchar();
    
        if (weiter == 'j' || weiter == 'J')
        {
                   return;
                   }
                   else if (weiter == 'n' || weiter == 'N')
                   {
                        printf("\nSchade, auf Wiedersehen!\n");
                        return 0;
                        }
                        else
                        {
                            printf("Falsche Eingabe!");
                            return 0;
                            }
    }
    


  • Anmerkung: "Subtraktion" ist absolut identisch vom Aufbau etc. wie "Addition"

    Solche Redundanzen sind schrecklich. Nichts zweimal schreiben!

    while (status != 0)
      {
            status = Hauptmenue();
            }
    

    Das ist besser als die Rekursionen.

    Deine Einrückung ist übrigens sehr seltsam.



  • Inwiefern hab ich Redundanzen?! Oder meintest du einfach nur die Aussage von mir? Wenn du es auf den Code bezogen meinst, bitte näher erläutern 😉

    if (weiter == 'j' || weiter == 'J')
        {
                   return;
                   }
                   else if (weiter == 'n' || weiter == 'N')
                   {
                        printf("\nSchade, auf Wiedersehen!\n");
                        return 0;
                        }
                        else
                        {
                            printf("Falsche Eingabe!");
                            return 0;
                            }
    

    kann ich das so mit der If-Else if Abfrage lassen? Oder gibts da eine "schönere" Lösung...(gibts mit Sicherheit 😃 )
    wie sollte ich es besser Einrücken? Welche "Richtlinien" gibts da? Wie gesagt, ich biege mir das ganze selbst bei und hab sonst keinen zum Fragen...



  • Inwiefern hab ich Redundanzen?!

    Du hast zwei Funktionen, die sich nur durch ein '+' und ein '-' unterscheiden. Den grössten Teil des gemeinsamen Codes könnten sich die beiden teilen, das wäre kürzer und im Nachhinein leichter zu verändern.

    wie sollte ich es besser Einrücken?

    Meine IDE hat es gerade so gemacht:

    if (weiter == 'j' || weiter == 'J')
        {
            return;
        }
        else if (weiter == 'n' || weiter == 'N')
        {
            printf("\nSchade, auf Wiedersehen!\n");
            return 0;
        }
        else
        {
            printf("Falsche Eingabe!");
            return 0;
        }
    

    Das ist einer der üblichen Stile.

    Wie gesagt, ich biege mir das ganze selbst bei und hab sonst keinen zum Fragen...

    Macht nichts, hier sind genug Menschen.
    🙂



  • herzlichen Dank! 🙂
    aber das mit IF kann ich so veranstalten?



  • Die oben gezeigte Einrückung wäre in der Tat sehr zu empfehlen. Das mit den Redundanzen stimmt natürlich auch, aber hier noch ein Tipp, wie du sie am besten Auflösen kannst: Eine recht gute Faustregel ist, dass eine Funktion immer nur genau eine Sache machen soll. Wenn eine Funktion zwei Dinge macht, müssten es eigentlich zwei Funktionen sein.

    Beispiel:
    Deine Funktion Addition() macht im Grunde drei Dinge:
    1.) Werte einlesen
    2.) Die eigentliche Rechnung durchführen
    3.) Benutzer fragen, ob er weiterrechnen will

    Wenn du es schaffst, diese drei Schritte sinnvoll in einzelne Funktionen zu packen, löst sich das Redundanz-Problem zeitgleich von selbst.



  • chmbw schrieb:

    aber das mit IF kann ich so veranstalten?

    Whitespace (unsichtbare Zeichen) haben in C keinerlei Bedeutung (ausser um Token zu trennen, wie bei i = a + ++b; ). Du kannst einrücken und formatieren wie du willst.

    Mikrooptimirer schrieb:

    Wenn du es schaffst, diese drei Schritte sinnvoll in einzelne Funktionen zu packen, löst sich das Redundanz-Problem zeitgleich von selbst.

    Das klingt sinnvoll.
    🙂



  • Hallo

    noch ein kleiner Tip

    schau dir mal switch an (statt der vielen IFs)

    Mfg
    Klaus



  • herzlichen Dank für die vielen Infos!
    ich werde mich gleich mal frisch ans Werk machen und das Ergebnis dann posten 🙂



  • Hallo,

    hat zwar ein bisschen gedauert, aber jetzt hab ich meinen Code für den "Taschenrechner" nochmal überarbeitet bekommen, hoffe die Einrückungen sind jetzt besser als beim letzten Code 😉 :

    #include <stdio.h>
    #include <stdlib.h>
    
    int Hauptmenue();
    int Subtrahieren();
    int Addieren();
    int Wahl1();
    int Weiter();
    
    int main(int argc, char *argv[])
    {
      int status=1;
    
      printf("\tTaschenRechner Version 3.0\n\n");
    
      while (status != 0)
      {
            status = Hauptmenue();
      }  
    
     system("PAUSE");	
      return 0;
    }
    
    int Hauptmenue()
    {
        char wahl;
    
        printf("Hallo, welche Rechenoperation wollen Sie ausfuehren?\n\n");
        printf("****************************************************\n\n");
        printf("\t[a] - Addition\n");
        printf("\t[b] - Subtrakion\n");
        printf("**************************\n");
        printf("\t[c] - Beenden\n\n");
        printf("Ihre Wahl: ");
    
        scanf("%c",&wahl);
        getchar();
    
        switch (wahl)
        {
               case 'A' :
               case 'a' : Addieren(); 
                          break;
               case 'B' :
               case 'b' : Subtrahieren();
                          break;
               case 'C' :
               case 'c' : printf("Auf wiedersehen!\n");
                          return 0;
                          break;
               default  : printf("Falsche Eingabe!\n");
                          return;                        
        }          
    
        if ( Weiter() == 0)
        {
             return 0;
        }
    
    }                  
    
    int Weiter()
    {
        char weiter;
    
        printf("Weiterrechnen?\n\n");
        scanf("%c",&weiter);
        getchar();
    
        if (weiter == 'J' || weiter == 'j')
        {
           return 1;
        }
        else
        {
            return 0;
        }
    }
    
    int Wahl1(int *a, int *b)
    {     
        int z1=0,z2=0;
    
        printf("Bitte Zahl eingeben: \n\n");
    
        scanf("%i %i",&z1,&z2);
        getchar();
    
        *a = z1;
        *b = z2;
    }
    
    int Addieren()
    {
        int a=0, b=0;
    
        Wahl1(&a,&b);
        printf("a=%d und b=%d\n\n",a,b);
        printf("Ihr Ergebnis: %i \n\n",a + b);
    
        return 0;
    }                      
    
    int Subtrahieren()
    {
        int a=0, b=0;
    
        Wahl1(&a,&b);
        printf("a=%d und b=%d\n\n",a,b);
        printf("Ihr Ergebnis: %i \n\n",a - b);
    
        return 0;
    }
    

    Das Problem beim letzten Code waren die ganzen Rekursionen, die vielen IFs etc. und ich wollte versuchen möglichst eine Funktion pro "Funktion" bzw. Aufgabe. zu erstellen. Freu mich über jegliche Art konstruktiver Kritik!!! 🙂
    Danke im Voraus!

    Grüße



  • // statt
    scanf("%c",&wahl);
    // schreib doch einfach:
    wahl = getchar();
    
    // statt
        if (weiter == 'J' || weiter == 'j')
        {
           return 1;
        }
        else
        {
            return 0;
        }
        // schreib einfach:
        return weiter == 'J' || weiter == 'j';
        // (denk mal in Ruhe drüber nach)
    

    Wahl1() geht auch noch einfacher:

    int Wahl1(int *a, int *b)
    {    
        int z1=0,z2=0;
    
        printf("Bitte Zahl eingeben: \n\n");
    
        scanf("%i %i", a, b);
        getchar();
        // hier entweder ein 'return', oder Wahl1() muss 'void' statt 'int' sein
    }
    
    case 'c':
                   printf("Auf wiedersehen!\n");
                   return 0;
                   break;    // <-- das ist nutzlos, weil's nach dem 'return'
                             //     nicht erreicht werden kann
    

    Das Problem beim letzten Code waren die ganzen Rekursionen, die vielen IFs etc. und ich wollte versuchen möglichst eine Funktion pro "Funktion" bzw. Aufgabe. zu erstellen.

    Ich hab sofort alles verstanden. Das ist oft das wichtigste. 🙂
    Rekursion ist übrigens ein sehr nützliches Werkzeug. In C muss man zwar ein wenig vorsichtig damit sein, aber lass dir auf keinen Fall das rekursive Denken austreiben.



  • Ich ja, jetzt kannst du langsam damit anfangen, nachzusehen, was mit dem Ding passiert, wenn man völlig unsinnige Eingaben macht.
    🙂



  • Den Aufruf von Weiter() solltest du bei deiner while-Schleife machen, das ist ja auch der Ort, an dem du die Entscheidung brauchst: Dann kannst du einfach "while(Weiter())" schreiben. Addieren() und Subtrahieren() haben immer noch gleichen Code - unterscheiden sich nur im Rechenoperator. Addiere() sollte also wirklich nur so aussehen:

    int Addiere(int a, int b)
    {
        return a + b;
    }
    

    Den Code zur Ein- / Ausgabe verfrachtest du dann am besten in eine eigene Funktion Rechne() in der du auch die switch-Abfrage machst. Statt im switch Funktionen aufzurufen, kannst du natürlich die Rechnung direkt durchführen, ganz wie du willst. Rechne() könnte leicht eine relativ große Funktion werden, also überlege dir was du da vllt. wieder in eigene Funktionen packen könntest - betrachte dabei die einzelnen Schritte der Funktion und was für sich eine abgetrennte Aufgabe darstellt.


Anmelden zum Antworten