Changes between Version 25 and Version 26 of CaoCourseTme2


Ignore:
Timestamp:
Feb 17, 2007, 12:34:40 PM (18 years ago)
Author:
franck
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • CaoCourseTme2

    v25 v26  
    9595  * La fonction add() prend en paramètre le couple (clé, valeur). Si l'élément existe, elle change sa valeur, sinon elle créé l'élément.
    9696
    97 = Questions sur le code fourni=
     97= Questions sur le code fourni =
    9898
    9999== Le Makefile ==
     
    115115== Le programme main ==
    116116
    117 Les questions suivantes portent sur le programme principal [wiki:CaoCourseTme2Main main()]
    118 
    119  *  A quoi servent les lignes les 2 premières lignes et la dernière ?
    120  *  Pourquoi inclure {{{stdio.h}}} ici ?
    121 
    122 {{{
    123 #ifndef _MAIN_H_
    124 #define _MAIN_H_
    125  
    126 #include <stdio.h>
    127  
    128 struct mainarg_s
    129 {
    130     FILE *INFILE;
    131     FILE *OUTPUTFILE;
    132     char VERBOSE;
    133 };
    134 extern struct mainarg_s MAINARG;
    135 
    136 #endif
    137 }}}
    138 
    139 '''Fichier main.c'''
     117Les questions suivantes portent sur le programme principal attachment:main.c
    140118
    141119 *  A quoi sert chaque include ?
     
    153131 *  Que faut-il faire pour transformer ce programme en filtre ?
    154132
    155 {{{
    156 include <stdlib.h>
    157 #include <stdio.h>
    158 #include <getopt.h>
    159 #include "main.h"
    160 #include "count.h"
    161 #include "hte.h"
    162 }}}
    163 {{{
    164 struct mainarg_s MAINARG;
    165 }}}
    166 {{{
    167 void usage (char *command)
    168 {
    169     printf ("\nStatistique Diverses\n");
    170     printf ("Usage  : %s [-v] [-o OutFile] InFile\n", command);
    171     printf ("-v          verbose mode\n");
    172     printf ("-o OutFile  output file (stdout by default)\n\n");
    173     exit (EXIT_FAILURE);
    174 }
    175 }}}
    176 {{{
    177 void getarg (int argc, char **argv)
    178 {
    179     extern char *optarg;
    180     extern int optind;
    181     char option;
     133et sur le fichier de prototype associé attachment:main.h
    182134
    183     MAINARG.OUTPUTFILE = NULL;
    184     while ((option = getopt (argc, argv, "vo:")) != EOF)
    185         switch (option)
    186         {
    187         case 'v':
    188             MAINARG.VERBOSE = 1;
    189             fprintf (stderr, "Verbose mode\n");
    190             break;
    191 
    192         case 'o':
    193             if (MAINARG.VERBOSE)
    194                 fprintf (stderr, "Fichier de sortie : %s\n", optarg);
    195 
    196             MAINARG.OUTPUTFILE = fopen (optarg, "w");
    197             if (MAINARG.OUTPUTFILE == NULL)
    198             {
    199                 fprintf (stderr, "%s: %s: \n", argv[0], optarg);
    200                 perror ("fopen");
    201                 exit (EXIT_FAILURE);
    202             }
    203             break;
    204 
    205         case '?':
    206         default:
    207             usage (argv[0]);
    208         }
    209     if ((optind + 1) != argc)
    210     {   
    211         usage (argv[0]);
    212     }   
    213     else
    214     {   
    215         if (MAINARG.VERBOSE)
    216             fprintf (stderr, "Fichier d'entrée : %s\n", argv[optind]);
    217 
    218         MAINARG.INFILE = fopen (argv[optind], "r");
    219         if (MAINARG.INFILE == NULL)
    220         {
    221             fprintf (stderr, "%s: %s ", argv[0], argv[optind]);
    222             perror ("fopen");
    223             exit (EXIT_FAILURE);
    224         }
    225         if (MAINARG.OUTPUTFILE == NULL)
    226             MAINARG.OUTPUTFILE = stdout;
    227     }   
    228 }
    229 }}}
    230 {{{
    231 int main (int argc, char **argv)
    232 {
    233     getarg (argc, argv);
    234     count (MAINARG.INFILE);
    235     fclose (MAINARG.OUTPUTFILE);
    236     return EXIT_SUCCESS;
    237 }
    238 }}}
     135 *  A quoi servent les lignes les 2 premières lignes et la dernière ?
     136 *  Pourquoi inclure {{{stdio.h}}} ici ?
    239137
    240138== Les fonctions de bases de la tables de hachage ==
    241139
    242 '''Fichier hte.h'''
     140Questions sur les déclaration du fichier attachment:hte.h
    243141
    244142 *  Les types {{{hte_item_t}}} et {{{hte_data_t}}} sont des structures dont le contenu n'est pas défini ici.
    245     Leur contenu n'est pas défini non plus dans le fichier {{{hte.c}}}, en revanche il est défini dans les fichiers {{{dico.c}}}, {{{dejavu.c}}} et {{{namealloc.c}}}
     143    Leur contenu n'est pas défini non plus dans le fichier {{{hte.c}}}, en revanche il est défini dans les fichiers
     144    {{{dico.c}}}, {{{dejavu.c}}} et {{{namealloc.c}}}
    246145    Quelle est alors la contrainte d'usage de ces types dans le fichier {{{hte.c}}} ?
    247146    Quel est l'intérêt de cette écriture ?
    248147 *  Dans la définition des prototypes de fonctions, le nom des paramètre est-il nécessaire ? si non pour les mettre ?
    249148 
    250 {{{
    251 #ifndef _HTE_H_
    252 #define _HTE_H_
    253 
    254 #include <stdlib.h>
    255 
    256 /*
    257  * Les deux structures ci-dessous ne sont pas définies ici
    258  * elles seront redéfinies dans chaque fichier
    259  */
    260 typedef struct hte_item_s hte_item_t;
    261 typedef struct hte_data_s hte_data_t;
    262 
    263 /*
    264  * structure définissant la table de hachage
    265  * On y trouve le nombre de liste de liste et
    266  * un pointeur vers le tableau de liste
    267  */
    268 typedef struct hte_root_s
    269 {
    270     size_t NB_LIST;             /* nombre de liste d'ITEM du dictionnaire */
    271     hte_item_t **LIST;          /* pointeur sur un tableau de liste d'ITEM */
    272 } hte_root_t;
    273 }}}
    274 {{{
    275 /*
    276  * Calcul de l'index de hachage de Donald Knuth
    277  * Elle produit un nombre entier à partir d'une chaine de caractères.
    278  */
    279 extern unsigned hte_hash (char *key);
    280 }}}
    281 {{{
    282 /*
    283  * hte_create fabrique une table de hachage vide
    284  * parametres:
    285  *      nb_item = nombre d'item maximum prévu dans la table de hachage
    286  */
    287 extern hte_root_t *hte_create (size_t nb_item);
    288 }}}
    289 {{{
    290 /*
    291  * hte_add ajoute l'item (key,data)
    292  * parametres:
    293  *      root = pointeur sur la table de hachage
    294  *      key  = pointeur sur une chaine de caractères (la clé)
    295  *      data = donnée associée à key
    296  * comportement:
    297  *      La clé key passée en parametre est comparée à celles présentes dans
    298  *      la table. Si la clé n'est pas trouvée alors un nouvel item est créé
    299  *      avec le couple (key,data). La clé key est en fait duppliquée.
    300  *      Si la clé est trouvée, le champ DATA de l'item présent dans la
    301  *      table est remplacé par le paramètre data de la fonction.
    302  * retour:
    303  *      Si l'item n'a pu etre créé faute d'espace, on sort du programme.
    304  */
    305 extern void hte_add (hte_root_t * root, char *key, hte_data_t * data);
    306 }}}
    307 {{{
    308 /*
    309  * hte_get recherche item, et en cas d'absence l'ajoute
    310  * parametres:
    311  *      root = pointeur pour la table de hachage
    312  *      key  = pointeur sur une chaine de caractères (la clé)
    313  * comportement:
    314  *      La clé passée en parametre est comparé a celles présentes dans la
    315  *      table de hachage.
    316  * retour:
    317  *      Si la clé est trouvée alors la fonction retourne le champ data
    318  *      sinon la fonction rend NULL.
    319  */
    320 extern hte_data_t *hte_get (hte_root_t * root, char *key);
    321 }}}
    322 {{{
    323 /*
    324  * namealloc permet de garantir l'unicité des chaines de caractères
    325  * parametres:
    326  *      name = chaine de caractères
    327  * comportement:
    328  *      name est recherché dans la table,
    329  *      s'il est absent on ajoute une copie de name dans la table
    330  * retour:
    331  *      un pointeur sur la copie de la table
    332  */
    333 char *namealloc (char *name);
    334 
    335 /* nombre maximum de noms dans la table */
    336 #define MAX_NAMEALLOC 1000
    337 }}}
    338 {{{
    339 /*
    340  * dejavu permet de savoir si un nom a déjà été vu
    341  * parametres:
    342  *      name = chaine de caractères
    343  * comportement:
    344  *      name est recherché dans la table,
    345  *      s'il est absent on ajoute une copie de name dans la table
    346  * retour:
    347  *      rend 1 s'il était déjà présent sinon 0
    348  */
    349 unsigned dejavu (char *name);
    350 
    351 /* nombre maximum de noms dans la table */
    352 #define MAX_DEJAVU 1000
    353 
    354 #endif
    355 }}}
    356 
    357 '''Fichier hte.c'''
     149et sur les fichiers de créations des tables attachment:hte.c
    358150
    359151 *  Faîte un dessin représentatif de la valeur de la variable locale {{{root}}} de la fonction {{{hte_create}}} si {{{nb_list==10}}} juste avant l'appel return.
    360152 *  La fonction {{{hte_hash}}} peut-elle provoquer une erreur de segment ? Comment y remedier proprement ?
    361153 *  Dans la fonction {{{hte_create}}} comment fait-on pour tester le retour de {{{malloc}}} ? à quoi celà sert-il ?
    362 
    363 {{{
    364 #include <stdio.h>
    365 #include <string.h>
    366 #include <stdlib.h>
    367 #include "hte.h"
    368 }}}
    369 {{{
    370 /*
    371  * Calcul de l'index de hachage de Donald Knuth
    372  * Elle produit un nombre entier à partir d'une chaine de caractères.
    373  */
    374 unsigned hte_hash (char *key)
    375 {
    376     char *c = key;
    377     unsigned h;
    378     for (h = 0; *c; c++)
    379     {
    380         h += (h ^ (h >> 1)) + 314159 * (unsigned char) *c;
    381         while (h >= 516595003)
    382             h -= 516595003;
    383     }
    384     return h;
    385 }
    386 }}}
    387 {{{
    388 /*
    389  * Création d'un dictionnaire vide
    390  */
    391 hte_root_t *hte_create (size_t nb_item)
    392 {
    393     hte_root_t *root;
    394     unsigned i, nb_list;
    395     static unsigned primes[] = { /*suite croissante de nombres premiers */
    396         101, 149, 223, 347, 499, 727, 1163, 1697, 2503, 3989, 5839, 8543,
    397         12503, 20143, 29483, 43151, 63179, 92503, 101747, 148961, 218107,
    398         319313, 514243, 752891, 1212551, 1613873, 2599153, 3805463,
    399         5571523, 8157241, 11943011, -1
    400     };
    401 
    402     /* détermination de la taille réelle du dictionnaire */
    403     for (i = 0; primes[i] < nb_item; i++);
    404     nb_list = primes[i];
    405     if (nb_item != -1)
    406     {
    407         /* allocation et initialisation du dictionnaire */
    408         if ((root = malloc (sizeof (hte_root_t))))
    409         {
    410             root->NB_LIST = nb_list;
    411             if ((root->LIST = calloc (nb_list, sizeof (hte_item_t *))))
    412                 return root;
    413         }
    414     }
    415     fprintf (stderr, "hte_create: not enough memory\n");
    416     exit (1);
    417 }
    418 }}}
    419 
    420 == Le service ''dejavu'' ==
    421 
    422 '''Fichier dejavu.c'''
    423 
    424  *  Pourquoi définit on la structure {{{hte_item_s}}} ici ?
    425  *  Dans la structure {{{hte_item_s}}} le champ KEY est un tableau de taille indéfinie.
    426     Quel différence y aurait-il avec une définition du type {{{char *KEY}}} ?
    427  *  La variable {{{root_namealloc}}} est static. Qu'est-ce que cela veut dire ?
    428  *  Donner les autres usages du mots clé static en langage C.
    429  *  A quoi sert la fonction {{{perror}}} ?
    430 
    431 {{{
    432 #include "hte.h"
    433 #include <stdio.h>
    434 #include <string.h>
    435 #include <stdlib.h>
    436 }}}
    437 {{{
    438 /*
    439  * structure définissant un item du dictionnaire
    440  * Un item est formé d'un couple (clé,valeur) plus un pointeur
    441  * permettant de chainer les items ayant le meme index de hachage
    442  */
    443 struct hte_item_s
    444 {
    445     struct hte_item_s *NEXT;    /* pointeur sur l'item suivant */
    446     char KEY[];                 /* tableau flexible contenant la clé */
    447 };
    448 }}}
    449 {{{
    450 unsigned dejavu (char *key)
    451 {
    452     unsigned index;
    453     hte_item_t *curr;
    454     static hte_root_t *root_namealloc;
    455 
    456     if (key)
    457     {   
    458         /* création du dictionnaire la première fois */
    459         if (root_namealloc == NULL)
    460             root_namealloc = hte_create (MAX_NAMEALLOC);
    461 
    462         /* calcul de l'index pour trouver la liste ou devrait être l'item */
    463         index = hte_hash (key) % root_namealloc->NB_LIST;
    464 
    465         /* recherche et l'item dans sa liste et sortie si trouvé */
    466         for (curr = root_namealloc->LIST[index]; curr; curr = curr->NEXT)
    467             if (strcmp (curr->KEY, key) == 0)
    468                 return 1;
    469 
    470         /* création d'une nouvelle entrée */
    471         curr = malloc (sizeof (struct hte_item_t *) + strlen (key) + 1);
    472         if (curr)
    473         {
    474             strcpy (curr->KEY, key);
    475             curr->NEXT = root_namealloc->LIST[index];
    476             root_namealloc->LIST[index] = curr;
    477             return 0;
    478         }
    479     }   
    480     perror ("dejavu");
    481     exit (1);
    482 }
    483 }}}
    484154
    485155== Le service ''dictionnaire'' ==
     
    489159 *  Le type {{{hte_data_t}}} n'est pas défini ici. Est-ce grave ? Où devra-t-il être défini ?
    490160 *  Pourquoi teste-on key ici ?
    491  
    492 {{{
    493 #include <stdio.h>
    494 #include <string.h>
    495 #include <stdlib.h>
    496 #include "hte.h"
    497 }}}
    498 {{{
    499 /*
    500  * structure définissant un item du dictionnaire
    501  * Un item est formé d'un couple (clé,valeur) plus un pointeur
    502  * permettant de chainer les items ayant le meme index de hachage
    503  */
    504 struct hte_item_s
    505 {
    506     struct hte_item_s *NEXT;    /* pointeur sur l'item suivant */
    507     hte_data_t *DATA;           /* valeur associée à l'item */
    508     char KEY[];                 /* tableau flexible contenant la clé */
    509 };
    510 }}}
    511 {{{
    512 /*
    513  * Recherche d'un item de clé key dans le dictionaire root
    514  */
    515 hte_data_t *hte_get (hte_root_t * root, char *key)
    516 {
    517     int index;
    518     hte_item_t *curr;
    519 
    520     if (key)
    521     {
    522         /* calcul de l'index pour trouver la liste ou devrait être l'item */
    523         index = hte_hash (key) % root->NB_LIST;
    524 
    525         /* recherche et l'item dans sa liste et sortie si trouvé */
    526         for (curr = root->LIST[index]; curr; curr = curr->NEXT)
    527             if (strcmp (key, curr->KEY) == 0)
    528                 return curr->DATA;
    529 
    530         return NULL;
    531     }
    532     perror ("hte_get");
    533     exit (1);
    534 }
    535 }}}
    536 {{{
    537 /*
    538  * Recherche d'un item de clé key dans le dictionnaire root
    539  * avec création en cas d'absence
    540  * et affectation d'une nouvelle donnée data
    541  */
    542 void hte_add (hte_root_t * root, char *key, hte_data_t * data)
    543 {
    544     int index;
    545     hte_item_t *curr;
    546 
    547     if (key)
    548     {
    549         /* calcul de l'index pour trouver la liste ou devrait être l'item */
    550         index = hte_hash (key) % root->NB_LIST;
    551 
    552         /* recherche et l'item dans sa liste et sortie si trouvé */
    553         for (curr = root->LIST[index]; curr; curr = curr->NEXT)
    554         {
    555             if (strcmp (curr->KEY, key) == 0)
    556             {
    557                 curr->DATA = data;
    558                 return;
    559             }
    560         }
    561 
    562         /* création d'une nouvelle entrée */
    563         curr = malloc (sizeof (struct hte_item_t *) + sizeof (void *) + strlen (key) + 1);
    564         if (curr)
    565         {
    566             strcpy (curr->KEY, key);
    567             curr->NEXT = root->LIST[index];
    568             root->LIST[index] = curr;
    569             curr->DATA = data;
    570             return;
    571         }
    572     }
    573     perror ("hte_add");
    574     exit (1);
    575 }
    576 }}}
    577 
    578 
     161 *  Pourquoi définit on la structure {{{hte_item_s}}} ici ?
     162 *  Dans la structure {{{hte_item_s}}} le champ KEY est un tableau de taille indéfinie.
     163    Quel différence y aurait-il avec une définition du type {{{char *KEY}}} ?
     164 *  La variable ....... est static. Qu'est-ce que cela veut dire ?
     165 *  Donner les autres usages du mots clé static en langage C.
     166 *  A quoi sert la fonction {{{perror}}} ?