Exercice langage C : Programme qui retourne le nombre de calculs qui ont été faits et la somme des prix TTC


Travail à Faire :

A. Modifiez le programme « prix HT ? prix TTC » que vous déjà écrit, pour qu’il répète  plusieurs fois les opérations :

  • Lecture au clavier d’un prix HT, calcul du prix TTC correspondant, affichage de ce prix.

Pour indiquer qu’il désire arrêter l’utilisation du programme, le client donne comme prix HT la valeur 0.

B. Modifiez le programme précédent afin qu’il affiche, lorsque l’utilisateur commande la fin du travail, le nombre de calculs qui ont été faits et la somme des prix TTC.


Solution avec boucle tant que canonique (un grand classique de la programmation structurée) :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include 

float pht, pttc;

main() {
   printf("Prix HT ? ");
    scanf("%f", &pht);

    while (pht > 0) {
        pttc = pht * (1 + 19.6 / 100); 
       printf("Prix TTC : %f\n", pttc);

       printf("Prix HT ? ");
        scanf("%f", &pht);
    }
   printf("Au revoir...");
}

 

[1] Vous rencontrerez très souvent cette situation : répéter un certain traitement jusqu'à ce qu'une certaine condition cesse d'être vraie, sans savoir à l'avance combien de fois le traitement devra être exécuté.

On peut passer un peu de temps sur cet exemple, qui a une grande importance pour la suite. Il faut se convaincre qu'il est une bonne manière de résoudre le problème posé, même s'il semble comporter des redondances inutiles. Dans certains langages, comme Pascal, c'est la seule ; en C on en a une autre.

Allons-y par étapes. Un peu de réflexion fait apparaître que la solution cherchée se composera de trois éléments :

  • lecture d'une donnée ; ici, soit un vrai prix HT, soit 0 pour indiquer la fin,
  • traitement de la donnée lue (supposée valide), ici calcul et écriture du prix TTC demandé,
  • boucle contrôlée par la condition « la donnée est-elle valide ? » (soit, ici, le prix HT est-il non nul ?).

Dans l'ordre de l'exécution on doit lire la donnée avant de la traiter. L'organisation suivante parait naturelle



tant que la donnée est valide faire Attention, ce modèle est erroné !
lire une donnée
traiter la donnée lue

Mais cela ne peut pas marcher! Deux défauts : (1) la première fois que la condition « la donnée est valide » est évaluée, le programme n'a encore rien lu et (2) la lecture est suivie par le traitement, que la donnée soit valide ou non. Dans beaucoup de situations, traiter une donnée invalide provoque des erreurs graves et est donc une conduite inacceptable.

Notez que remplacer la boucle tant que faire (while) par une boucle faire tant que (do...while) corrige le premier défaut mais pas le second : la lecture est toujours suivie du traitement :

faire Attention, ce modèle est encore erroné !
lire une donnée
traiter la donnée lue
tant que la donnée est valide

On en arrive donc à la configuration proposée, qui obéit au schéma suivant :

lire une donnée
tant que la donnée est valide faire

traiter la donnée lue
lire une donnée

Les deux défauts constatés plus haut sont corrigés. D'une part la première fois que la condition « la donnée est valide » est évaluée une donnée a déjà été lue. D'autre part, dans l'ordre de l'exécution, entre la lecture d'une donnée et son traitement se place toujours la condition précédente, assurant que seules les données valides seront traitées.

[2] Sans rien enlever à la qualité de la solution précédente, notons qu'en C l'existence de l'instruction break nous permet d'écrire des boucles dans lesquelles la condition de continuation (ou d'arrêt) n'est pas obligatoirement placée à l'entrée de la boucle, mais n'importe où à son intérieur

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include 

float pht, pttc;

main() {
    while (1) {
       printf("Prix HT ? ");
        scanf("%f", &pht);

        if (pht == 0)
            break;

        pttc = pht * (1 + 19.6 / 100); 
       printf("Prix TTC : %f\n", pttc);    
    }
   printf("Au revoir...");
}

 



On peut trouver cette solution plus naturelle. Elle corrige bien les défauts constatés plus haut, car l'évaluation de la condition est toujours précédée d'une lecture et entre la lecture et le traitement il y a toujours une validation.

Puisque, pris pour un booléen, 1 signifie vrai, l'expression while(1) veut dire « répéter indéfiniment ». En C cela peut s'écrire aussi for(;;). Nous nous sommes ramenés au schéma suivant :

répéter indéfiniment
lire une donnée
si la donnée est invalide abandonner la boucle
traiter la donnée lue

[3] N'écoutez pas les intégristes qui vous disent que l'instruction break n'est pas de la programmation structurée. Obscurantisme et oppression du prolétariat ! La programmation structurée consiste essentiellement à organiser son programme sous forme de blocs vérifiant :

  • un bloc est fait d'une suite d'instructions, chacune composée à son tour d'un ou plusieurs blocs,
  • le contrôle n'entre dans un bloc autrement qu'en passant par sa première instruction,
  • quand le contrôle quitte un bloc, il se retrouve toujours immédiatement après sa dernière instruction,

Comme on peut le voir, notre boucle ci-dessus respecte scrupuleusement ces règles.

[4] On nous demande une version de notre programme qui affiche, à la fin du travail, le nombre de calculs faits et le total des prix TTC calculés. Il nous faut introduire deux éléments très fréquents et utiles :

  • un compteur, c.-à-d. une variable entière qui vaut constamment le nombre de calculs qui ont été faits,,
  • un accumulateur, c.-à-d. une variable du type qu'il faut (ici float) qui vaut constamment la somme des prix TTC calculés.

Ce qui donne le programme :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include 

float pht, pttc, cumul;
int nombre;

main() {
    nombre = 0;
    cumul = 0;

   printf("Prix HT ? ");
    scanf("%f", &pht);
    while (pht > 0) {
        pttc = pht * (1 + 19.6 / 100); 
       printf("Prix TTC : %f\n", pttc);

        nombre = nombre + 1;
        cumul = cumul + pttc;

       printf("Prix HT ? ");
        scanf("%f", &pht);
    }
   printf("En tout %d calculs faits - Cumul des prix TTC : %f\n", nombre, cumul);    
}

 



N.B. Ce n'est pas une obligation mais, quand nous serons plus habités au langage C, les deux lignes concernant nombre et cumul nous les écrirons plutôt comme ceci :

    ...
    nombre++;
    cumul += pttc;
    ...