Faire une calculatrice

  1. Introduction
  2. Code source

1. Introduction

Sur ce TP, nous allons voir comment créer une calculatrice en langage C. Notre calculatrice permettra :

  • de faire les calculs arithmétiques élémentaires (addition, soustraction, multiplication et division).
  • de calculer le produit factoriel, le logarithme népérien, le logarithme à base de 10, le carré, l’exponentielle, l’inverse, le pourcentage et la racine carrée d’un nombre.
  • de faire quelques calculs trigonométriques
  • de convertir des euros en francs comoriens

Le but de ce TP n’est pas seulement de créer une calculatrice mais surtout de mettre en pratique certaines notions que nous avons vues dès le premier cours de langage C jusqu’ici.

Et pour fermer l’introduction, voici une capture de ce que nous allons faire:
, Calculatrice en c

2. Code source

Le code source n’est constitué que de certaines notions déjà vues sur ce site. Ce qui sous-entend qu’il n’est pas nécessaire de perdre du temps à faire des explications. Mais bon, dans le code même, j’ai laissé pas mal d’explications sous forme des commentaires.

Code :

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>  
  4. #include <math.h>  
  5. #include <ctype.h>  
  6. #include <gtk/gtk.h>  
  7.   
  8. static float a = 0;  
  9. static char derncar = (char) 0;  
  10. static char prev = (char) 0;  
  11. #define BUF_SIZE 88  
  12.   
  13. /* 
  14.  * on définit un plan que nous allons utiliser pour positiooner les éléments de 
  15.  * de la calculatrice 
  16. */  
  17. typedef struct {  
  18.   
  19.     char      *Labeldubouton;  //le label  
  20.     int        ligne;         // le rangés horizontales  
  21.     int        colonne;       // les rangs verticals  
  22.     GtkWidget *bouton;     // les boutons  
  23.   
  24. } TypedeBouton;  
  25.   
  26.   
  27. /* 
  28.  * on va ranger les boutons 
  29. */  
  30. TypedeBouton ListedesBoutons [] = {  
  31.   
  32. /* 
  33.  * Ici  le rang 0 désigne la première colonne 
  34.   * les numérotations commencent par 0. La ligne 0 est occupée par la zone 
  35.   * d'affichage du résutat 
  36. */  
  37.  /*Colone numéro 0, c'est-à-dire première colonne 
  38.  *Ci-dessous les boutons du calculatrices 
  39.  */  
  40.   
  41.     {"C",   1, 0, NULL},// Deuxième ligne, première colonne  
  42.     {"7",   2, 0, NULL},// 3ème ligne, 1ère colonne  
  43.     {"4",   3, 0, NULL},// 4ème ligne, 1ère colonne  
  44.     {"1",   4, 0, NULL},// 5ème ligne, 1ère colonne  
  45.     {"+/-", 5, 0, NULL},// 6ème ligne, 1ère colonne  
  46.   
  47.   
  48.       /* 2ème colonne*/  
  49.     {"CE",  1, 1, NULL}, // 2ème ligne, 2ème colonne  
  50.     {"8",   2, 1, NULL}, // 3ème ligne, 2ème colonne  
  51.     {"5",   3, 1, NULL}, // 4ème ligne, 2ème colonne  
  52.     {"2",   4, 1, NULL}, // 5ème ligne, 2ème colonne  
  53.     {"0",   5, 1, NULL}, // 6ème ligne, 2ème colonne  
  54.   
  55.       /* 3ème colonne*/  
  56.     {"eur/kmf", 1, 2, NULL}, // 2ème ligne, 3ème colonne  
  57.     {"9",   2, 2, NULL}, // 3ème ligne, 3ème colonne  
  58.     {"6",   3, 2, NULL}, // 4ème ligne, 3ème colonne  
  59.     {"3",   4, 2, NULL}, // 5ème ligne, 3ème colonne  
  60.     {".",   5, 2, NULL}, // 6ème ligne, 3ème colonne  
  61.   
  62.   
  63.      /* 4ème colonne*/  
  64.     {"/",   1, 3, NULL},  
  65.     {"*",   2, 3, NULL},  
  66.     {"-",   3, 3, NULL},  
  67.     {"+",   4, 3, NULL},  
  68.     {"=",   5, 3, NULL},  
  69.   
  70.     /* 5ème colonne*/  
  71.     {"%",   1, 4, NULL},  
  72.     {"Rac", 2, 4, NULL},  
  73.     {"1/x", 3, 4, NULL},  
  74.     {"x^2", 4, 4, NULL},  
  75.     {"x!",  5, 4, NULL},  
  76.     /* 6ème colonne*/  
  77.     {"asin", 1, 5, NULL},  
  78.     {"acos", 2, 5, NULL},  
  79.     {"atan", 3, 5, NULL},  
  80.     {"exp",  4, 5, NULL},  
  81.     {"ln",   5, 5, NULL},  
  82.     /* 7ème colonne*/  
  83.     {"sin",   1, 6, NULL},  
  84.     {"cos",   2, 6, NULL},  
  85.     {"tan",   3, 6, NULL},  
  86.     {"pi",    4, 6, NULL},  
  87.     {"log10", 5, 6, NULL},  
  88.   
  89. };  
  90.   
  91. /* 
  92.  * --- nombre des boutons 
  93. */  
  94. int nButtons = sizeof (ListedesBoutons) /  
  95.                sizeof (TypedeBouton);  
  96.   
  97. /* --- Pour le resultat--- */  
  98. GtkWidget *label; //le label pour le résultat  
  99. GtkWidget *zoneresultat; // là où on affichera le resultat (une zone de texte)  
  100.   
  101. /* 
  102.  *pour quitter l'application 
  103. */  
  104. gint FermerApp (GtkWidget *bouton, gpointer data)  
  105. {  
  106.     gtk_main_quit ();  
  107.   
  108.     return (FALSE);  
  109. }  
  110.   
  111.   
  112. /* 
  113.  *Gestion des 0 
  114.  *On va commencer par ajouter des  0 après la virgule 
  115. */  
  116. void GestiondesZerosSansSens (char *ChiffreZero)  
  117. {  
  118.     int nIndex;  
  119.     int bDecimal = FALSE;  
  120.     int nPos = -1;  
  121.   
  122.     /* On commence par une boucle a travèrs la chaîne */  
  123.     for (nIndex = 0; nIndex < strlen (ChiffreZero); nIndex++) {  
  124.   
  125.         /* si c'est un nombre décimal*/  
  126.         if (ChiffreZero[nIndex] == '.') {  
  127.              bDecimal = TRUE;  
  128.         }  
  129.   
  130. /* 
  131. * gestions des 0 après la virgule  
  132. */  
  133.         if (bDecimal) {  
  134.   
  135.   
  136.             if (ChiffreZero[nIndex] == '0') {  
  137.                if (nPos < 0) {  
  138.                    nPos = nIndex;  
  139.                }  
  140.             } else {  
  141.                nPos = -1;  
  142.             }  
  143.         }  
  144.     }  
  145.     if (nPos > 0) {  
  146.         ChiffreZero[nPos] = (char) 0;  
  147.     }  
  148. }  
  149.   
  150.   
  151. /* 
  152. *si il y a des 0 inutiles avant le nombre 
  153. *on va les éliminer 
  154. * par exemple si on a 0002, on va seulement concerver 2 
  155. */  
  156. void CouperlesZeros (char *ChiffreZero)  
  157. {  
  158.     int nPos;  
  159.     if (ChiffreZero == NULL) return;  
  160.     for (nPos = 0; (ChiffreZero[nPos] && ChiffreZero[nPos] == '0'); nPos++) {  
  161.         if (isdigit (ChiffreZero[nPos+1])) {  
  162.             ChiffreZero[nPos] = ' ';  
  163.         }  
  164.     }  
  165. }  
  166.   
  167.   
  168. /* 
  169.  * Les opérateurs 
  170. */  
  171. int Command (char op)  
  172. {  
  173.     switch (op) {  
  174.         case '+':  
  175.         case '-':  
  176.         case '/':  
  177.         case '*':  
  178.         case '=':  
  179.             return (TRUE);  
  180.     }  
  181.     return (FALSE);  
  182. }  
  183.   
  184. int FloatingPointChar (char op)  
  185. {  
  186.   
  187.     return (isdigit (op) || op == '.');  
  188. }  
  189.   
  190.   
  191. /* 
  192.  * Gestions des événements de nos boutons 
  193. */  
  194. void key_press (GtkWidget *bouton,  
  195.                 GdkEventKey *event,  
  196.                 gpointer data)  
  197. {  
  198.     int nIndex;  
  199.   
  200.     /*  on va faire une recherche parmi les boutons */  
  201.     for (nIndex = 0; nIndex < nButtons; nIndex++) {  
  202.   
  203.         /* si c'est le premier caractère d'un bouton */  
  204.   
  205.         if (event->keyval == ListedesBoutons[nIndex].Labeldubouton[0] &&  
  206.             ListedesBoutons[nIndex].Labeldubouton[1] == (char) 0) {  
  207.   
  208.             /* on définit le focus sur ce bouton */  
  209.             gtk_widget_grab_focus (ListedesBoutons[nIndex].bouton);  
  210.   
  211.             gtk_button_clicked (GTK_BUTTON (ListedesBoutons[nIndex].bouton));  
  212.             return;  
  213.         }  
  214.     }  
  215. }  
  216.   
  217.   
  218. /* 
  219.  * On va passer au traitement si un bouton a été cliqué 
  220. */  
  221. void HandleDigit (char *str, char op)  
  222. {  
  223.     char *labelText;  
  224.     char buffer[BUF_SIZE];  
  225.     int  len;  
  226.   
  227.   
  228.     if (Command (derncar)) {  
  229.   
  230.        /* netoyer la zone */  
  231.         gtk_label_set (GTK_LABEL (label), "");  
  232.         if (derncar == '=') {  
  233.             /* vider la commande */  
  234.             derncar = (char) 0;  
  235.             prev = (char) 0;  
  236.         }  
  237.     }  
  238.   
  239.     gtk_label_get (GTK_LABEL (label), &labelText);  
  240.     strcpy (buffer, labelText);  
  241.     len = strlen (buffer);  
  242.     buffer[len] = (gchar) op;  
  243.     buffer[len+1] = (gchar) 0;  
  244.   
  245.     CouperlesZeros (buffer);  
  246.   
  247.     /* Ajout d'un nombre dans le champs */  
  248.     gtk_label_set (GTK_LABEL (label), (char *) buffer);  
  249.     gtk_entry_set_text (GTK_ENTRY(zoneresultat), buffer);  
  250.   
  251. }  
  252.   
  253.   
  254. /* 
  255.  *C'est le moment de faire les calculs 
  256. */  
  257. void OperationsNonArthmetiqueElementaire (char *str)  
  258. {  
  259.     char *labelText;  
  260.     char buffer[BUF_SIZE];  
  261.     float b;  
  262.   
  263.     /* récupérer le nombre dans le champs */  
  264.     gtk_label_get (GTK_LABEL (label), &labelText);  
  265.     b = atof (labelText);  
  266.   
  267.     /* calcul du pourcentatge */  
  268.     if (strcmp (str, "%") == 0) {  
  269.         b = b / 100;  
  270.   
  271.     /* Calcul de l'inverse d'un nombre*/  
  272.     } else if (strcmp (str, "1/x") == 0) {  
  273.   
  274.         /* on n'accepte pas 0 car 1/0 ne donne pas un nombre */  
  275.         if (b == 0) {  
  276.             /*Error (); */  
  277.             return;  
  278.         }  
  279.         b = 1 / b;  
  280.   
  281.     /*calcul de la racine carré*/  
  282.     } else if (strcmp (str, "Rac") == 0) {  
  283.         b = sqrt ((double) b);  
  284.   
  285.     /* calcul du carré d'un nombre */  
  286.     }  
  287.     else if (strcmp (str, "x^2") == 0) {  
  288.         b = b * b;  
  289.     }  
  290.      /* on donne la valeur de pi*/  
  291.    else if (strcmp (str, "pi") == 0) {  
  292.         b = 3.14159265359;  
  293.   
  294.     /* On calcul l'exponentielle d'un nombre*/  
  295.     }  
  296.      else if (strcmp (str, "exp") == 0) {  
  297.         b = exp ((double) b);  
  298.     }  
  299.     /* On calcul le cosinus d'un angle en degré*/  
  300.     else if (strcmp (str, "cos") == 0) {  
  301.         b = cos ((double) b*3.14159 / 180.0);  
  302.     }  
  303.     /* On calcul le sinus d'un angle en degré*/  
  304.   else if (strcmp (str, "sin") == 0) {  
  305.         b = sin ((double) b*3.14159 / 180.0);  
  306.     }  
  307.     /* On calcul l'arcsinus d'un angle en degré*/  
  308.     else if (strcmp (str, "asin") == 0) {  
  309.         b = asin ((double) b* 180.0 /3.14159);  
  310.     }  
  311.      /* On calcul l'arcosinus d'un angle en degré*/  
  312.     else if (strcmp (str, "acos") == 0) {  
  313.         b = acos ((double) b* 180.0 /3.14159);  
  314.     }  
  315.      /* On calcul la tangente d'un angle en degré*/  
  316.     else if (strcmp (str, "tan") == 0) {  
  317.         b = tan ((double) b*3.14159 / 180.0);  
  318.     }  
  319.       /* On calcul l'arctangente d'un angle en degré*/  
  320.      else if (strcmp (str, "atan") == 0) {  
  321.         b = atan ((double) b* 180.0 /3.14159);  
  322.     }  
  323.     /* on calcule logarithme népérien*/  
  324.      else if (strcmp (str, "ln") == 0) {  
  325.         b = log ((double) b);  
  326.     }  
  327.       /* on calcule logarithme décimal*/  
  328.       else if (strcmp (str, "log10") == 0) {  
  329.         b = log10 ((double) b);  
  330.     }  
  331.   /* on calcule le produit factoriel d'un nombre*/  
  332.       else if (strcmp (str, "x!") == 0) {  
  333.      int i = b-1;  
  334.      while (i > 1)  
  335.      {  
  336.           b = b * i;  
  337.           --i;  
  338.      }  
  339.     b = b;  
  340.     }  
  341.   
  342. /*on convertit l'euro en francs comorien*/  
  343.  else if (strcmp (str, "eur/kmf") == 0) {  
  344.  b=b*491.968;  
  345.     }  
  346.   
  347.   
  348.     sprintf (buffer, "%f", (float) b);  
  349.     GestiondesZerosSansSens (buffer);  
  350.     CouperlesZeros (buffer);  
  351.     gtk_label_set (GTK_LABEL (label), buffer);  
  352.   
  353.   
  354.   
  355. }  
  356.   
  357.   
  358. void OperationArthmetiqueElementaire ()  
  359. {  
  360.     char buffer[BUF_SIZE];  
  361.     char *labelText;  
  362.     float b;  
  363.   
  364.   
  365.     gtk_label_get (GTK_LABEL (label), &labelText);  
  366.     b = atof (labelText);  
  367.   
  368.     switch (prev) {  
  369.         case '+':  
  370.             a = a + b;  
  371.             break;  
  372.   
  373.         case '-':  
  374.             a = a - b;  
  375.             break;  
  376.   
  377.         case '*':  
  378.             a = a * b;  
  379.             break;  
  380.   
  381.         case '/':  
  382.             a = a / b;  
  383.             break;  
  384.   
  385.         case '=':  
  386.             a = b;  
  387.             break;  
  388.   
  389.         default:  
  390.             a = b;  
  391.             break;  
  392.     }  
  393.   
  394.   
  395.     sprintf (buffer, "%f", (float) a);  
  396.     GestiondesZerosSansSens (buffer);  
  397.     CouperlesZeros (buffer);  
  398.     gtk_label_set (GTK_LABEL (label), buffer);  
  399.     gtk_entry_set_text (GTK_ENTRY(zoneresultat), buffer);  
  400.   
  401.   
  402. }  
  403.   
  404.   
  405.   
  406. void bouton_clicque (GtkWidget *bouton, gpointer data)  
  407. {  
  408.     char op = *((char *) data);  
  409.     char *str;  
  410.   
  411.     /* Recuperer le label */  
  412.     str = (char *) data;  
  413.   
  414.     /* Entrer un nombre */  
  415.     if (FloatingPointChar (op) && strlen (str) == 1) {  
  416.   
  417.         HandleDigit (str, op);  
  418.   
  419.     } else {  
  420.   
  421.         /* Effacer */  
  422.         if (strcmp (str, "CE") == 0) {  
  423.             gtk_label_set (GTK_LABEL (label), "0");  
  424.             gtk_entry_set_text (GTK_ENTRY(zoneresultat), "0");  
  425.             return;  
  426.   
  427.         /* Effacer*/  
  428.         } else if (strcmp (str, "C") == 0) {  
  429.             prev = (char) 0;  
  430.             derncar = (char) 0;  
  431.             gtk_label_set (GTK_LABEL (label), "0");  
  432.             gtk_entry_set_text (GTK_ENTRY(zoneresultat), "0");  
  433.             return;  
  434.   
  435.         } else {  
  436.   
  437.   
  438.             OperationsNonArthmetiqueElementaire (str);  
  439.         }  
  440.   
  441.   
  442.         OperationArthmetiqueElementaire ();  
  443.   
  444.         prev = op;  
  445.     }  
  446.     derncar = op;  
  447. }  
  448.   
  449. /* 
  450.  * On va créer un bouton et lui assigner des gestionnaires d'événements, 
  451. */  
  452. GtkWidget *CreateButton (GtkWidget *table, char *Labeldubouton, int ligne, int colonneumn)  
  453. {  
  454.     GtkWidget *bouton;  
  455.   
  456.     /* création du bouton */  
  457.     bouton = gtk_button_new_with_label (Labeldubouton);  
  458.   
  459.     /* un signal si le bouton est cliqué */  
  460.     gtk_signal_connect (GTK_OBJECT (bouton), "clicked",  
  461.                         GTK_SIGNAL_FUNC (bouton_clicque), Labeldubouton);  
  462.   
  463.    /*on positionne le bouton*/  
  464.     gtk_table_attach (GTK_TABLE (table), bouton,  
  465.                       colonneumn, colonneumn+1,  
  466.                       ligne, ligne + 1,  
  467.                       GTK_FILL | GTK_EXPAND,  
  468.                       GTK_FILL | GTK_EXPAND,  
  469.                       5, 7);  
  470.   
  471.     /* on rend le bouton visible */  
  472.     gtk_widget_show (bouton);  
  473.   
  474.     /* retourner le bouton*/  
  475.     return (bouton);  
  476. }  
  477.   
  478.   
  479.   
  480. /* 
  481.  *On crée les boutons du calculatrice qu'on a définit au début 
  482. */  
  483. void CreerlesBoutonsduCalculatrice (GtkWidget *table)  
  484. {  
  485.     int nIndex;  
  486.   
  487.     /*parcourrir la liste des boutons*/  
  488.     for (nIndex = 0; nIndex < nButtons; nIndex++) {  
  489.   
  490.         /* creer un bouton */  
  491.         ListedesBoutons[nIndex].bouton =  
  492.                 CreateButton (table,  
  493.                               ListedesBoutons[nIndex].Labeldubouton,  
  494.                               ListedesBoutons[nIndex].ligne,  
  495.                               ListedesBoutons[nIndex].colonne);  
  496.     }  
  497. }  
  498.   
  499. /* 
  500.  *Et voila, maitenant c'est le moment de créer la fenêtre que va 
  501.  *afficher notre calculatrice 
  502. */  
  503. int main (int argc, char *argv[])  
  504. {  
  505.     GtkWidget *mafenetre;  
  506.     GtkWidget *table;  
  507.     /* L'initialisation de GTK */  
  508.     gtk_init (&argc, &argv);  
  509.   
  510.     /* Création de la fenêtre*/  
  511.     mafenetre = gtk_window_new (GTK_WINDOW_TOPLEVEL);  
  512.   
  513.     /* le titre de la fenêtre */  
  514.     gtk_window_set_title (GTK_WINDOW (mafenetre), "Samomoi calculatrice");  
  515.   
  516.     /* la taille par défaut de la fenêtre*/  
  517.     gtk_widget_set_usize (mafenetre, 390, 280);  
  518.     /*l'icone de la fenêtre*/  
  519.     gtk_window_set_icon_from_file(GTK_WINDOW(mafenetre), "icone.gif", NULL);  
  520.   
  521.     /* le signal si une clé a été cliquée*/  
  522.     gtk_signal_connect (GTK_OBJECT (mafenetre), "key_press_event",  
  523.                         GTK_SIGNAL_FUNC (key_press), NULL);  
  524.     gtk_signal_connect (GTK_OBJECT (mafenetre), "delete_event",  
  525.                         GTK_SIGNAL_FUNC (FermerApp), NULL);  
  526.     table = gtk_table_new (5, 7, TRUE);  
  527.     CreerlesBoutonsduCalculatrice (table);  
  528.     label = gtk_label_new ("0");  
  529.     zoneresultat= gtk_entry_new();  
  530.     gtk_entry_set_text (GTK_ENTRY(zoneresultat), "0");  
  531.     gtk_table_attach_defaults (GTK_TABLE (table), zoneresultat, 0, 4, 0, 1);  
  532.     gtk_container_add (GTK_CONTAINER (mafenetre), table);  
  533.     gtk_widget_show_all (mafenetre);  
  534.   
  535.   
  536.     gtk_main ();  
  537.     return (0);  
  538. }   



Une question? Cliquez ici pour la poser.

Retour sur le portail du langage C/C++