Exercice langage C : Les Suites

Travail à Faire:

1. Ecrivez un programme qui lit au clavier une suite ?0, ?1, ?2, … de nombres entiers positifs ou nuls et qui en affiche la moyenne. La frappe d’un nombre négatif indique la fin de la série.

2.  Ecrivez un programme qui lit au clavier une suite ?0, ?1, ?2, … de nombres entiers positifs ou nuls et qui les affiche dans l’ordre inverse de leur lecture. La frappe d’un nombre négatif indique la fin de la série. Nous avons des raisons de penser qu’il n’y aura pas plus de 100 nombres.

3.  Ecrivez un programme qui lit au clavier une suite ?0, ?1, ?2, … de nombres entiers tels que 0 ? ? ? 20 et qui calcule et affiche le nombre d’apparitions de chaque valeur dans la suite. La frappe d’un nombre négatif indique la fin de la série.


Exercice 1

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

int nombre, somme, x;
float moyenne; 

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

   printf("? ");
    scanf("%d", &x);
    while (x >= 0) {
        nombre = nombre + 1;
        somme = somme + x;

       printf("? ");
        scanf("%d", &x);
    }

    if (nombre > 0) {
       moyenne = (float) somme / nombre; 
      printf("la moyenne est : %f\n", moyenne);
    }
    else
      printf("pour calculer une moyenne il faut au moins un nombre!\n");
}

 



[1] Il ne faut pas se faire avoir par l'énoncé de l'exercice ! Ce n'est pas parce que le sujet parle d'une suite (x0, x1, x2, ...) qu'il faut nécessairement introduire un tableau X et parler de X[0]X[1]X[2], etc. En effet, compte tenu du travail à faire, les valeurs x0, x1, x2, etc. n'ont pas besoin d'exister simultanément et une unique variable simple, appelée ci-dessus x, suffit à les représenter à tour de rôle.

[2] Ce programme est un avatar du problème « traiter une suite de données sans savoir à l'avance combien il y en a ». Sa résolution à l'aide d'une boucle while a été commentée à l'occasion de l'exercice 1.

[3] Les nombres à traiter étant garantis positifs ou nuls, nous n'avons pas eu de mal à déterminer une valeur « intruse » pour indiquer la fin des données. Mais il ne faut pas croire qu'il en sera toujours ainsi ; souvent toutes les données possibles sont valides et on a du mal à trouver comment indiquer la fin de la suite (le moment venu on verra comment mettre à profit des talents cachés de la fonction scanf).

Ce programme illustre un point important mentionné à l'exercice 1 : la marque de fin des données est une donnée invalide qu'il ne faut pas traiter comme les autres. Ici, ce serait une erreur grave que de faire intervenir le nombre négatif de la fin dans le calcul de la moyenne!

[4] Notez enfin un piège subtil qui vous est tendu ici. Les nombres lus étant des entiers, nous avons déclaré de type int les variables x et somme. Tout est fait pour vous pousser à écrire

moyenne = somme / nombre; Attention, erreur !

C'est une erreur, car somme et nombre étant tous deux entiers, la division faite est le quotient par défaut : ce n'est pas ce qu'il faut pour la moyenne (le fait que le membre gauche de l'affectation, moyenne, soit une variable de type float ne rattrape rien, au moment de l'affectation les décimales sont déjà perdues).

Exercice 2

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

#define MAX 100

int table[MAX], nombre, x, i;

main() {
    nombre = 0;

   printf("? ");
    scanf("%d", &x);
    while (x >= 0) {
        if (nombre >= MAX) {
           printf("Débordement du tableau");
            break;
        }

        table[nombre] = x;
        nombre = nombre + 1;

       printf("? ");
        scanf("%d", &x);
    }

   printf("Voici le tableau à l'envers:\n");
    for (i = nombre - 1; i >= 0; i = i - 1)
       printf("%d ", table[i]);
   printf("\n");
}

Contrairement à l'exercice précédent, il nous faut ici mémoriser tous les termes de la suite pour pouvoir les afficher à l'envers, d'où la nécessité de déclarer un tableau. Deux points importants dans ce genre de situations :



  • estimer correctement une taille maximum bien adaptée aux jeux de données envisagés,
  • vérifier l'absence de débordement au fur et à mesure que le tableau se remplit.

Ici, la taille maximum nous est explicitement suggérée par l'énoncé, qui indique qu'il n'y aura pas plus de 100 nombres.

Exercice 3

[1] Pour commencer il nous faut écarter les solutions inutilement onéreuses, voire ridicules. Chef d'œuvre : lire toutes les données en comptant le nombre d'apparitions de la valeur 0, puis redemander à l'utilisateur de refrapper les données afin de compter le nombre de 1, puis les demander à nouveau pour compter les 2, et ainsi de suite (notre programme sera à la poubelle bien avant le 21ème tour!).

[2] Raffinement de la même idée : lire les données en les mémorisant dans un tableau comme à l'exercice précédent, ensuite parcourir ce tableau 21 fois : une fois pour compter le nombre de valeurs égales à 0, une autre pour compter le nombre de 1, encore une pour compter les 2, etc. Ce programme fonctionnerait correctement et, en principe, suffisamment vite du point de vue de l'utilisateur. Mais le tableau des données peut être de taille importante et il est probablement bien peu efficace de le parcourir 21 fois. De plus, comment déclarer ce tableau alors qu'on n'a aucune indication quant à sa taille ?

[3] Voici un programme qui traite les nombres donnés au vol, c'est-à-dire au moment où ils sont lus, sans avoir besoin d'y revenir dessus. Pour cela il nous faut un tableau de 21 compteurs, pour compter séparément le nombre de fois que se sont produits chacun des 21 événements possibles : x = 0, x = 1, x = 2, etc.

Étant donnée une valeur x, une manière de savoir quel compteur doit être incrémenté est une cascade de if :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
if (x == 0)
    compteur[0]++;
else if (x == 1)
    compteur[1]++;
else if (x == 2)
    compteur[2]++; 
...
etc. Or, il y a une simplification évidente

 compteur[x]++;
d'où notre programme :

 #include 

int compteur[21], x, i;

main() {
    for (i = 0; i <= 20; i++)
        compteur[i] = 0;

    printf("? ");
    scanf("%d", &x);
    while (0 <= x && x <= 20) {
        compteur[x]++;

        printf("? ");
        scanf("%d", &x);
    }

    for (i = 0; i <= 20; i++)
        if (compteur[i] > 0)
            printf("nombre de %d : %d\n", i, compteur[i]);
}