Mein erstes C Programm - Und schon wieder ein Taschenrechner ...



  • So, nun habe ich es auch geschafft: Mein erstes C Programm ist fertig. Na ja, fast fertig. Ich hoffe, das sich niemand dran stoert, wenn ich das 'gute Stueck, jetzt hier mal zur Schau stelle.

    Dies ist, abgesehen von den ueblichen Hello World Spielereien, mein erstes C Programm ueberhaupt, also habt bitte Nachsicht und lacht nicht gar so laut. Ich weiss, es gibt noch viel dran zu tun, aber fuer den Moment ist bei mir die 'Luft raus'.

    Ich habe viel dabei gelernt und bin fast an der Tatsache gescheitert, dass es offensichtlich zu ncurses sehr wenig Literatur im Internet gibt. Aus diesem Grunde habe ich auch manche Idee auserhalb von ncurses realisiert, wie zum Beispiel das Scrollen des Rechners mit Hilfe der Pfeiltasten.

    Na ja, ich habe mal in irgendeinem schlauen Text gelesen, man solle mit kleinen Programmen anfangen und diese dann aber auch zu Ende fuehren. Das habe ich hiermit getan.

    Bei mir laeuft das Teil einwandfrei. Keine Ahnung, ob's auch auf anderen System laeuft

    Ach ja, als kleiner Tip fuer den naechsten Anfaenger: Das Programm wurde unter Linux fuer Linux gescrieben und muss mit "gcc -v -o rechner rechner.c -lncurses" compiliert werden.

    Bei dieser Gelegenheit ein ganz besonderes und herzliches Dankeschoen an das C/C++ Forum hier, ohne deren tolle Hilfe ich diese Werk nie beendet haette.

    Guenther
    Davao City, Philippines, Plaet Earth

    // rechner.c
    #include <stdlib.h>
    #include <ncurses.h>																// ncurses.h includes stdio.h
    #include <string.h>
    
    WINDOW *rechner, *display, *result, *key, *message;
    
    int main ()
    {
    
        static int firstrow = 0;
        static int firstcol = 0;
        initscr();																			// start the curses mode
        keypad(stdscr, TRUE);
        noecho();
        curs_set(0);																		// Cursor ausschalten
        cbreak();																				// Line buffering disabled. pass on everything
    
        int nResult = 0;
    
        calculator(nResult);
    
        nocbreak();
        endwin();
        return 0;
    }
    
    // -------------------------------------------------------------------------------------------------
    
    calculator(nResult)
    {
        int row = 10;
        int col = 10;
        int maxrow;
        int maxcol;
        int num = 0;
        int zeichen = 0;
        int summe = 0;
    
        int operand = 0;
        char op = ' ';
    
        bool weiter = TRUE;
        bool fertig = FALSE;
        int next = 0;
    
        while (weiter == TRUE) {
    
            getmaxyx(stdscr,maxrow,maxcol);										// get the number of rows and columns
    
            rechner = newwin(17, 24, row+0, col+0);
            box(rechner, 0, 0);
            refresh();
            wrefresh(rechner);
    
            display = newwin(3, 20, row+1, col+2);
            box(display, 0, 0);
            refresh();
            wrefresh(display);
    
    // -------------------------------------------------------------------------------------------------
    
            if (next == 1) {
                mvprintw( row+2, col+4, "%16d", num);
    
            }
            else
            {
                mvprintw( row+2,col+4, "%16d", summe );
            }
    
            mvprintw( row+2, col+20, "%c", op);
    
            mykeypad(row, col);																// Draw the calculator ....
    
            int keystroke = getch();
            int c = keystroke;
    
            switch ( keystroke ) {
    
            case 48:
                num=num*10;
                num = num+0;
                next = 1;
                break;
            case 49:
                num=num*10;
                num = num+1;
                next = 1;
                break;
            case 50:
                num=num*10;
                num = num+2;
                next = 1;
                break;
            case 51:
                num=num*10;
                num = num+3;
                next = 1;
                break;
            case 52:
                num=num*10;
                num = num+4;
                next = 1;
                break;
            case 53:
                num=num*10;
                num = num+5;
                next = 1;
                break;
            case 54:
                num=num*10;
                num = num+6;
                next = 1;
                break;
            case 55:
                num=num*10;
                num = num+7;
                next = 1;
                break;
            case 56:
                num=num*10;
                num = num+8;
                next = 1;
                break;
            case 57:
                num = num*10;
                num = num+9;
                next = 1;
                break;
    
                // Und hier schon mal die vier Grundrechenarten ...
    
            case 43:																					// addieren
                if (operand == 0) {
                    summe = num;
                }
                else if (operand == 1) {
                    summe = summe + num;
                }
                else if (operand == 2) {
                    summe = summe - num;
                }
                else if (operand == 3) {
                    summe = summe * num;
                }
                else if (operand == 4) {
                    summe = summe / num;
                }
                num = 0;
                operand = 1;
                op = '+';
                next = 0;
                break;
    
            case 45:																					// subtrahieren
                if (operand == 0) {
                    summe = num;
                }
                else if (operand == 1) {
                    summe = summe + num;
                }
                else if (operand == 2) {
                    summe = summe - num;
                }
                else if (operand == 3) {
                    summe = summe * num;
                }
                else if (operand == 4) {
                    summe = summe / num;
                }
                num = 0;
                operand = 2;
                op = '-';
                next = 0;
                break;
    
            case 42:																					// multiplizieren
                if (operand == 0) {
                    summe = num;
                }
                else if (operand == 1) {
                    summe = summe + num;
                }
                else if (operand == 2) {
                    summe = summe - num;
                }
                else if (operand == 3) {
                    summe = summe * num;
                }
                else if (operand == 4) {
                    summe = summe / num;
                }
                num = 0;
                operand = 3;
                op = '*';
                next = 0;
                break;
    
            case 47:																					// dividieren
                if (operand == 0) {
                    summe = num;
                }
                else if (operand == 1) {
                    summe = summe + num;
                }
                else if (operand == 2) {
                    summe = summe - num;
                }
                else if (operand == 3) {
                    summe = summe * num;
                }
                else if (operand == 4) {
                    summe = summe / num;
                }
                num = 0;
                operand = 4;
                op = '/';
                next = 0;
                break;
    
            case 10:																					// Enter
                if (operand == 0) {
                    summe = num;
                }
                else if (operand == 1) {
                    summe = summe + num;
                }
                else if (operand == 2) {
                    summe = summe - num;
                }
                else if (operand == 3) {
                    summe = summe * num;
                }
                else if (operand == 4) {
                    summe = summe / num;
                }
                num = 0;
                operand = 0;
                op = '=';
                next = 0;
                fertig = FALSE;
                break;
    
            case 99:																					// Aktuelle Eingabe loeschen ...
                num = 0;
                //zeichen = 0;
                break;
    
            case 260:																					// KEY_LEFT
                if (col > 0) {
                    col--;
                    clear();
                }
                break;
            case 261:																					// KEY_RIGHT
                if (col < 80) {
                    col++;
                    clear();
                }
                break;
            case 259:																					// KEY_UP
                if (row > 0) {
                    row--;
                    clear();
                }
                break;
            case 258:																					// KEY_DOWN
                if (row < 25) {
                    row++;
                    clear();
                }
                break;
            case 63:																					// Aktuelle Eingabe loeschen ...
                help();
                clear();
                break;
    
            default:
                break;
            }
    
            endwin();
    
        }
    
        return 0;
    }
    
    // ###########################################################################################################
    
    mykeypad (int row, int col)
    {
        curs_set(0);
    
        key = newwin(3, 5, row+4, col+2);
        box(key,0,0);
        refresh();
        wrefresh(key);
        mvprintw(row+5,col+4,"1");
    
        key = newwin(3, 5, row+4, col+7);
        box(key,0,0);
        refresh();
        wrefresh(key);
        mvprintw(row+5,col+9,"2");
    
        key = newwin(3, 5, row+4, col+12);
        box(key, 0, 0);
        refresh();
        wrefresh(key);
        mvprintw(row+5,col+14,"3");
    
        key = newwin(3, 5, row+4, col+17);
        box(key, 0, 0);
        refresh();
        wrefresh(key);
        mvprintw(row+5,col+19,"/");
    
        key = newwin(3, 5, row+7, col+2);
        box(key,0,0);
        refresh();
        wrefresh(key);
        mvprintw(row+8,col+4,"4");
    
        key = newwin(3, 5, row+7, col+7);
        box(key,0,0);
        refresh();
        wrefresh(key);
        mvprintw(row+8,col+9,"5");
    
        key = newwin(3, 5, row+7, col+12);
        box(key, 0, 0);
        refresh();
        wrefresh(key);
        mvprintw(row+8,col+14,"6");
    
        key = newwin(3, 5, row+7, col+17);
        box(key, 0, 0);
        refresh();
        wrefresh(key);
        mvprintw(row+8,col+19,"*");
    
        key = newwin(3, 5, row+10, col+2);
        box(key,0,0);
        refresh();
        wrefresh(key);
        mvprintw(row+11,col+4,"7");
    
        key = newwin(3, 5, row+10, col+7);
        box(key,0,0);
        refresh();
        wrefresh(key);
        mvprintw(row+11,col+9,"8");
    
        key = newwin(3, 5, row+10, col+12);
        box(key, 0, 0);
        refresh();
        wrefresh(key);
        mvprintw(row+11,col+14,"9");
    
        key = newwin(3, 5, row+10, col+17);
        box(key, 0, 0);
        refresh();
        wrefresh(key);
        mvprintw(row+11,col+19,"-");
    
        key = newwin(3, 5, row+13, col+2);
        box(key,0,0);
        refresh();
        wrefresh(key);
        mvprintw(row+14,col+4,"0");
    
        key = newwin(3, 5, row+13, col+7);
        box(key,0,0);
        refresh();
        wrefresh(key);
        mvprintw(row+14,col+9,".");
    
        key = newwin(3, 5, row+13, col+12);
        box(key, 0, 0);
        refresh();
        wrefresh(key);
        mvprintw(row+14,col+14,"?");
    
        key = newwin(3, 5, row+13, col+17);
        box(key, 0, 0);
        refresh();
        wrefresh(key);
        mvprintw(row+14,col+19,"+");
    
        return;
    }
    
    // -------------------------------------------------------------------------------------------------
    
    help() {
    
    //int scr_dump(const char *filename);
    
        int maxrow;
        int maxcol;
        int row;
        int col;
    
        getmaxyx(stdscr,maxrow,maxcol);										// get the number of rows and columns
    
        row = (maxrow/2)-5;
        col = (maxcol/2)-30;
    
    		//clear();
    
        message = newwin(13, 60, row, col);
        box(message,0,0);
        refresh();
        wrefresh(message);
    
        mvprintw(row+2, col+3, "Dies ist, abgesehen von einigen Hello World Versuchen");
    		mvprintw(row+3, col+3, "nun mein erstes C-Programm. Die Bedienung sollte keine");
    		mvprintw(row+4, col+3, "Probleme bereiten. Man tippt die Zahlen halt so ein");
    		mvprintw(row+5, col+3, "wie man spricht.");
    		mvprintw(row+6, col+3, "Als kleine Spielerei laesst sich der Rechner mit den");
    		mvprintw(row+7, col+3, "Pfeiltasten auf dem Bildschirm verschieben. Mit Ctrl-C");
    		mvprintw(row+8, col+3, "wird das Programm beendet.");
    
    		mvprintw(row+10, col+3, "Weiter mit beliebiger Taste ....");
    
        getch();
    
    }
    


  • bei den ganzen case für die tastaturabfrage wären konstanten mit sprechenden namen besser als nur zahlen.



  • Nulltens: Was ist so interessant an Taschenrechner-Programmen? 😃

    Erstens: Für die Case-Marken hätte ich lieber char-Literale ( case '0': statt case 48: verwendet)

    Zweitens: Viele Teile des Programms könntest du noch gemeinsam gruppieren, z.B. sind die case-Blöcke bei der Auswertung gruppenweise identisch (btw, du darfst auch mehr als einen Operator pro Anweisung verwenden ;)) und die mykeypad() besteht aus einer Folge von Blöcken, die sich nur in den verwendeten Parametern unterscheiden (das schreit nach einer Hilfsfunktion).



  • CStoll schrieb:

    Nulltens: Was ist so interessant an Taschenrechner-Programmen? 😃

    Du meinst weil die so voellig nutzlos sind ...

    Ja, das habe ich inzwischen auch begriffen und suche derzeit nach einer besseren Idee fuer meine naechste Uebung ...

    CStoll schrieb:

    ... mykeypad() besteht aus einer Folge von Blöcken, die sich nur in den verwendeten Parametern unterscheiden (das schreit nach einer Hilfsfunktion).

    Habe ich sofort umgesetzt und sieht jetzt so aus:

    tastatur (int row, int col)
    {
        curs_set(0);
    
        int taste[4][4] = { {'1','2','3','/'}, {'4','5','6','*'}, {'7','8','9','-'}, {'0','.','?','+'} };
        int r[4] = {4,7,10,13};
        int c[4] = {2,7,12,17};
    
        int i=0, n=0, p=0, q=0;
    
        for (i = 0; i < 16; i++)
        {
            if (i > 11)
            {
                n = 3;
                p = i-12;
            }
            else if (i > 7 & i <=11)
            {
                n = 2;
                p = i-8;
            }
            else if (i > 3 & i <= 7)
            {
                n = 1;
                p = i-4;
            }
            else if (i <= 3)
            {
                n = 0;
                p = i;
            }
    
            key = newwin( 3, 5, row+r[n], col+c[p] );
            box(key,0,0);
            refresh();
            wrefresh(key);
    
            mvprintw( row+1+r[n], col+2+c[p], "%c", taste[n][p] );
        }
    
        return;
    }
    

    Sicherlich auch so noch nicht perfekt, so sollte ich wohl in Zukunft zumindest aussagefaehigere Namen fuer meine Variablen verwenden, aber sicherlich schon besser als 16 x den nahezu gleichen Code zu schreiben.

    drüber schrieb:

    bei den ganzen case für die tastaturabfrage wären konstanten mit sprechenden namen besser als nur zahlen.

    Stimmt, habe ich auch gleich umgesetzt.

    Danke fuer die Anregungen ....



  • Die if-else-Kaskade sieht immer noch grauenhaft aus - das geht noch kürzer:

    for(i=0;i<16;++i)//ich bevorzuge Präfix-Inkrement - ist potentiell schneller
    {
      n = i%4;
      p = i/4;
      ...
    }
    


  • CStoll schrieb:

    ...Präfix-Inkrement - ist potentiell schneller

    gibt es dafür eine erklärung??



  • CStoll schrieb:

    {
      n = i%4;
      p = i/4;
      ...
    }
    

    Nun ja, ich sitze hier mit grossen Augen und kann nur noch staunen ...

    Ich habe den Code entsprechend umgebaut und es laeuft natuerlich, nur ueber das "warum" muss ich mir noch ein paar mehr Gedanken machen.

    Ganz zu schweigen davon, wie Du das mal so eben auf einen Blick erkannt hast ... 😕

    Carsten, Du bist ein Genie!!!!



  • Apeman schrieb:

    CStoll schrieb:

    ...Präfix-Inkrement - ist potentiell schneller

    gibt es dafür eine erklärung??

    für int nicht

    Apeman schrieb:

    Sagt der eine Löwe zum Anderen, als sie den Zirkusclown fressen: "Na, der schmeckt aber komisch!"

    der ist so schlecht, dass er schon wieder lustig ist.



  • Apeman schrieb:

    CStoll schrieb:

    ...Präfix-Inkrement - ist potentiell schneller

    gibt es dafür eine erklärung??

    für int nicht

    und für was sonst?

    Apeman schrieb:

    Sagt der eine Löwe zum Anderen, als sie den Zirkusclown fressen: "Na, der schmeckt aber komisch!"

    der ist so schlecht, dass er schon wieder lustig ist.

    deswegen ja 😉



  • Apeman schrieb:

    für int nicht

    und für was sonst?

    Für so 'ne andere Sprache, die mal von C abgeleitet wurde. Da trifft das häufiger zu. Aber das dürfte für Dich nicht so furchtbar interessant sein 😃

    Aber wenn man sich das Präfix-Inkrement einmal als gängige Praxis angewöhnt hat, spricht ja nichts dagegen das in anderen Sprachen auch zu verfolgen.



  • Apeman schrieb:

    CStoll schrieb:

    ...Präfix-Inkrement - ist potentiell schneller

    gibt es dafür eine erklärung??

    Für int vielleicht nicht - aber als C++ Programmer ist man es gewohnt, daß Postfix-Operatoren langsamer sein könnten (temporäre Variablen, zusätzlich nötige Kopier-Aktionen etc). Und die Präfix-Variante ist auf jeden Fall nicht langsamer.

    gboelter schrieb:

    Ich habe den Code entsprechend umgebaut und es laeuft natuerlich, nur ueber das "warum" muss ich mir noch ein paar mehr Gedanken machen.

    Du weißt, was die Operatoren % und / machen? Dann ist der Rest eigentlich recht übersichtlich.

    Ganz zu schweigen davon, wie Du das mal so eben auf einen Blick erkannt hast ... 😕

    Das macht die Erfahrung 😃



  • CStoll schrieb:

    aber als C++ Programmer ist man es gewohnt, daß Postfix-Operatoren langsamer sein könnten (temporäre Variablen, zusätzlich nötige Kopier-Aktionen etc).

    naja, C++ steckt ja bekannterweise voller merkwürdigkeiten (mal nett ausgedrückt) 😉
    aber in C sollte es doch egal sein, ob man das ++ dahinter oder davor schreibt, wenn die variable an der stelle nicht ausgewertet wird. oder gibt es da auch fälle, wobei das pre- einem post-increment vorzuziehen ist?



  • Ja, wenn man den Wert des Ausdrucks irgendwo verwenden will, macht es einen Unterschied. Aber in Fällen wie hier ist es prinzipiell egal - die Macht der Gewohnheit 😉

    (btw, ich habe nicht "ist schneller" geschrieben, sondern "ist potentiell schneller" ;))


Anmelden zum Antworten