Emmanuel Delahaye C is a sharp tool |
Voilà un cas assez typique de code difficile à lire parce qu'il ne respecte pas un principe de codage simple qui veut que la portée d'un objet doit être limitée au strict nécessaire.
Je propose de réécrire ce code (la sémantique est inchangée) selon ce principe, ce qui AMA le rend immédiatement plus clair. (J'ai ajouté mes habituels manies : commentaires C90, suppression des accents et réindentation) :
Code :
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- int main (void)
- {
- float ligne[12];
- srand ((int) time (NULL)); /* initialisation de la fonction rand */
- /* entree des 12 valeurs */
- {
- FILE *fichier = fopen ("essai2.txt", "w" );
- if (fichier != NULL)
- {
- int i;
- for (i = 0; i < 12; i++)
- {
- printf ("valeur%d:", i);
- scanf ("%f", ligne + i);
- (void) getchar ();
- fprintf (fichier, "valeur%d: %.4f\n", i, ligne);
- }
- fclose (fichier);
- }
- }
- /* tirage aleatoire */
- {
- int j[6];
- {
- int test = 0;
- int t;
- for (t = 0; t < 6; t++)
- {
- while (test == 0)
- {
- j[t] = rand () % 12;
- test = 1;
- if (t > 0)
- {
- int k;
- for (k = 0; k < t; k++)
- {
- printf ("k:%d\t", k);
- printf ("t:%d\t", t);
- if (j[t] == j[k])
- {
- j[t] = rand () % 12;
- test = 0;
- }
- }
- }
- }
- }
- }
- {
- float somme = 0;
- int t;
- for (t = 0; t < 6; t++)
- {
- printf ("%d\n", j[t]);
- printf ("%.4f\n", ligne[j[t]]); /* cette ligne est surlignee quand le programme bloque */
- /* somme= somme + ligne[j[t]]; */
- /* printf("%f\n",somme); */
- }
- somme = somme / 6;
- printf ("%.4f\n", somme);
- }
- }
- (void) getchar ();
- return 0;
- }
|
Autre avantage de cet écriture, la préparation du code à un découpage en fonction...
J'ai placé un point d'arrêt en ligne 67 pour visualiser le contenu de j:
+-[_]----- Inspecting j ---4-[]-+
¦8FD6:0FC0
¦[0] 11 (0x000B) _
¦[1] 9455 (0x24EF) _
¦[2] -30009 (0x8AC7) _
¦[3] -30025 (0x8AB7) _
¦[4] 1664 (0x0680) _
¦[5] 512 (0x0200)
Ã-____________________________-Â
¦int [6] ¦
+--------------------------------+
|
Y'a un problème! (la valeur devrait être comprise entre 0 et 11)
Comme le contenu de 'j' sert d'index au tableau ligne, je comprend que ça casse! Il y a un bug dans l'algo de tirage. Pourquoi n'a-t-il pas été validé individuellement ?
En fait, c'est simple. Au premier tour, 'test' est forcé à 1 (ligne 44). Ensuite, while (test == 0) est toujours faux, et on n'écrit jamais dans j[1]-j[5], ce qui explique la trace ci-dessus...
Voici un exemple de validation (au moins visuelle) de l'algorithme:
L'interface:
Code :
- #ifndef H_TIRAGE
- #define H_TIRAGE
- /* tirage.h */
- #include <stddef.h>
- void tirage (int *a, size_t n, int max);
- #endif /* guard */
|
L'implementation:
Code :
- /* tirage.c */
- #include "tirage.h"
- #include <stdlib.h>
- #ifdef TEST
- #include <stdio.h>
- static void print (int const *a, size_t n)
- {
- size_t i;
- for (i = 0; i < n; i++)
- {
- printf ("a[%u]=%d\n", (unsigned) i, a[i]);
- }
- }
- #endif
- static doublon(int *a, size_t n, int x)
- {
- int found = 0;
- size_t i;
- for (i = 0; !found && i < n; i++)
- {
- found = a[i] == x;
- }
- return found;
- }
- void tirage (int *a, size_t n, int max)
- {
- size_t i;
- for (i = 0; i < n; i++)
- {
- if (i == 0)
- {
- a[i] = rand () % max;
- }
- else
- {
- int x;
- do
- {
- x = rand () % max;
- }
- while (doublon(a, i, x));
- a[i] = x;
- }
- }
- }
- #ifdef TEST
- int main (void)
- {
- int j[6];
- tirage (j, sizeof j / sizeof *j, 12);
- print (j, sizeof j / sizeof *j);
- return 0;
- }
- #endif
|
Pour faire le test, compiler tirage.c avec -DTEST
D:\DEV-CPP\ED\001>bc tirage.prj
a[0]=10
a[1]=2
a[2]=4
a[3]=1
a[4]=3
a[5]=7
|
Evidemment, on obtient toujours le même résultat poutr implémentation donnée (ici Borland C 3.1) On peut améliorer avec srand()...
Ensuite, dans l'applicaion, on inclus "tirage.h", et on ajoute tirage.c dans le projet. On appelle la fonction tirage avec le parametres qui vont bien.
Le travail en module indépendants et testables et indispensable si on veut écrire du code sérieusement. De plus, la modularité permet souvent la réutilisation d'objet validés, ce qui est un avantage certain que ce soit pour le développeur, son employeur ou le client final :
- développement plus rapide.
- augmentation de la fiabilité.
- amortissement des coûts de développement.
[i]Nota : le micro test que j'ai indiqué n'est qu'un embryon d'ébauche de début de test de validation unitaire... Dans la réalité, c'est beaucoup plus 'velu!'
Message édité par Emmanuel Delahaye le 18-12-2004 à 11:55:42 ---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
|