Partage
  • Partager sur Facebook
  • Partager sur Twitter

Exercices pour débutants en C (suite)

Venez vous entrainer!

    24 avril 2010 à 18:51:22

    Eh bien je te remercie candide, pour ma part, etant donne du temps dont je dispose, je ne pourrais pas m'occuper de l'exercice, qui me semble assez ardu..

    Cependant si quelqu'un suit, je tenterai de participer

    Citation

    Voilà, je suggère cet exo mais je ne le prends pas en charge, ni énoncé rigoureux ni suivi de posts ni correction, je lance juste l'idée.



    C'est dommage, pourquoi pas? manque d'envie??
    • Partager sur Facebook
    • Partager sur Twitter
      24 avril 2010 à 20:31:54

      Citation : Adroneus


      C'est dommage, pourquoi pas? manque d'envie??



      Pas vraiment mais j'ai pas trop le temps et ce serait une trop grosse charge que de s'occuper correctement des exercices.
      • Partager sur Facebook
      • Partager sur Twitter
        25 avril 2010 à 20:04:04

        Bonsoir à tous,

        Je tiens premièrement à m'excuser pour le retard du deuxième exercice du moi d'Avril (qui va devenir le premier du moi de Mai :-° ).

        Deuxièmement, l'exercice que j'avais prévu s'avère être long et difficile sur certains points (je voudrais donc en discuter avec vous avant de le proposer [voir le secret en fin de post]).
        En attendant je propose que l'on fasse l'exercice proposé par Candide (énoncé ci-dessous).

        _______________________________

        zJustificator (25 Avril au 15 Mai)



        L'énoncé est très simple : votre but est de justifié le texte soumis en entrée. (Comme précisé dans le post de Candide)
        zjustificator -c nombre_de_colonnes [-i fichier_en_entrée] [-o fichier_en_sortie]


        Je précise juste que le programme prend en entrée trois options.
        • -c suivi du nombre de colonnes (option obligatoire)
        • -i suivie du fichier à justifier (option facultative)
        • -o fichier ou on écrit la sortie (option facultative)


        Si l'option i n'est pas active on récupère le texte sur stdin.
        Si l'option o n'est pas active on écrit la sortie sur stdout.

        Un topic a été crée pour cet exercice.
        _______________________________

        Mon idée exercice est de faire un type abstrait de données string en c qui permettent de faire à peu près tout ce fait la classe QString. Cela permettra de créer quelque chose d'utile qui simplifieras l'utilisation des chaines de caractères en c

        • Partager sur Facebook
        • Partager sur Twitter
          25 avril 2010 à 20:12:20

          Pour le secret, moi je trouve ça très bien.
          Après, il faudra, peut-être laisser plus de temps.


          • Partager sur Facebook
          • Partager sur Twitter
          Zeste de Savoir, le site qui en a dans le citron !
            25 avril 2010 à 20:49:55

            Citation : GurneyH

            Pour le secret, moi je trouve ça très bien.
            Après, il faudra, peut-être laisser plus de temps.


            Aie moi suis largue :-°
            • Partager sur Facebook
            • Partager sur Twitter
              25 avril 2010 à 21:12:01

              Bien, mais a voir comment gerer ca...
              • Partager sur Facebook
              • Partager sur Twitter
                26 avril 2010 à 7:28:18

                Citation : GurneyH

                Pour le secret, moi je trouve ça très bien.
                Après, il faudra, peut-être laisser plus de temps.



                Je prévoyais de faire cet exercice sur plusieurs fois car certaines fonctions sont assez difficiles.

                Citation : darkipod

                Aie moi suis largue :-°



                Ne t'inquiète pas ce sera un exercice guidé, je ne prévois pas de larguer la liste de fonctions d'un coup sans expliquer comment s'y prendre.
                • Partager sur Facebook
                • Partager sur Twitter
                  26 avril 2010 à 19:00:59

                  Citation : Lithrein

                  <citation rid="4907200">Pour le secret, moi je trouve ça très bien.
                  Après, il faudra, peut-être laisser plus de temps.



                  Je prévoyais de faire cet exercice sur plusieurs fois car certaines fonctions sont assez difficiles.

                  Citation : darkipod

                  Aie moi suis largue :-°



                  Ne t'inquiète pas ce sera un exercice guidé, je ne prévois pas de larguer la liste de fonctions d'un coup sans expliquer comment s'y prendre.</citation
                  ouf ca me rassure :p
                  en attendant je vais commencez l'exo de Candide qui me parait relativement difficile.
                  les manips sur les fichiers c'est pas forcement facile pour moi :-°
                  • Partager sur Facebook
                  • Partager sur Twitter
                    26 avril 2010 à 19:11:38

                    @Darkipod : Si tu n'est pas à l'aise avec les fichiers, c'est justement le moment de t'entrainer et n'hésite pas à posez tes questions sur le 'topic' de l'exercice.
                    • Partager sur Facebook
                    • Partager sur Twitter
                      26 avril 2010 à 19:35:59

                      @Adroneus : Mea culpa, je me suis trompé de pseudonyme je voulais dire darkipod.
                      • Partager sur Facebook
                      • Partager sur Twitter
                        4 mai 2010 à 17:46:56

                        A la vue, du nombre de participants à l'exercice (seul BadWolf a proposé une solution), je suis un peu déçu.

                        Bien que l'exercice soit plus difficile qu'il n'y paraisse, il ne vous est pas interdit de poser des questions pour avoir des indications sur la manière de résoudre l'exercice.

                        Je m'adresse maintenant aux plus avancés, vous vouliez un exercice un peu plus dur que d'habitude, c'est l'occasion d'en profiter.

                        @Adroneus : Est-ce que tu pourrais mettre à jour le premier post du topic, s'il te plaît ?
                        • Partager sur Facebook
                        • Partager sur Twitter
                          4 mai 2010 à 18:13:51

                          Pour ma part je me suis pas encore penche sur le problème : faut que je bosse sur ma gestion du temps.
                          En ce moment mon Job me prend trop de temps et donc peu de temps pour la prog!
                          • Partager sur Facebook
                          • Partager sur Twitter
                            4 mai 2010 à 18:35:59

                            Le problème, c'est qu'il ne faut pas s'adresser qu'aux avancés.
                            • Partager sur Facebook
                            • Partager sur Twitter
                              4 mai 2010 à 18:42:19

                              Les débutants ne font pas les exos, donc quel intérêt ?

                              @Lithrein : Je ferai l'exo quand j'aurai le temps, en ce moment j'ai pas vraiment le temps. ;)
                              • Partager sur Facebook
                              • Partager sur Twitter
                                5 mai 2010 à 7:36:36

                                Fait, j'etais persuade de l'avoir fait swy, et pareil je suis dans une periode d'exams pas attendue du tout Oo mes profs se tapent des trips... donc j'ai pas beaucoup de temps la, je peux juste aller sur le SdZ 5 / 6 minutes par jour...
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  10 mai 2010 à 14:33:17

                                  Bonjour à tous,

                                  je commence tout juste mon apprentissage du C :) , et je voulais vous remercier pour tout ces exercices.

                                  A bientôt.

                                  Denebola
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    15 mai 2010 à 17:38:58

                                    Correction de zJustificator (25 Avril - 15 Mai).



                                    Cette fois ci, nous devions créer un programme capable de justifier un texte sur un nombre de colonnes que l'utilisateur a choisi. Le texte peut être passé en paramètre grâce à l'option `-i' et le fichier de sortie peut être précisé grâce à l'option `-o'. Par défaut le texte est pris sur `stdin' et affiché sur `stdout'.

                                    Traitement des options



                                    Avant de faire quoi que ce soit, notre programme doit s'occuper de "parser" les options pour avoir toutes les informations necessaires à son fonctionnement. Ce traitement pouvait être effectué de manière brute ou à l'aide de la fonction `getopt' (plus d'information sur getopt).

                                    La correction que je vous propose n'utilise pas la fonction `getopt', par contre GurneyH l'utilise dans sa solution que vous pouvez retrouver ici.


                                    On a donc pour l'instant un programme qui ressemble à ça (il n'y a rien d'extraordinaire ni de difficile, c'est pourquoi je passe cette partie sous silence) :

                                    typedef struct opt_s {
                                        FILE * istream, * ostream;
                                        int nb_col;
                                        int h_active, err;
                                        char * i_path, * o_path;
                                    } opt_t;
                                    


                                    /**
                                     * \brief Parse les options passées au programme
                                     *
                                     * @param ac  : int
                                     * @param av  : char **
                                     * @param opt : opt_t
                                     *
                                     * @return 0 en cas d'échec, autrement 1
                                     */
                                    int
                                    get_options (int ac, char * av[], opt_t * opt) {
                                        size_t i;
                                    
                                        if (ac < 2)
                                            return 0;
                                        
                                        for (i = 1 ; i < ac ; ++i) {
                                            if (av[i][0] == '-') {
                                                if (av[i][1] == 'h' || !strcmp(av[i]+1, "-help")) {
                                                    opt->h_active = 1;
                                                } else if (av[i][1] == 'c' || !strcmp(av[i]+1, "-columns")) {
                                                    ++i;
                                                    if (i >= ac) {
                                                        return 0;
                                                    }
                                                    if (sscanf(av[i], "%d", &opt->nb_col) != 1 || opt->nb_col < 1) {
                                                        puts("L'option 'c' attend un nombre entier naturel strictement positif.");
                                                        return 0;
                                                    }
                                                } else if (av[i][1] == 'i' || !strcmp(av[i]+1, "-istream")) {
                                                    ++i;
                                                    if (i >= ac) {
                                                        return 0;
                                                    }
                                                    opt->i_path = av[i];
                                                } else if (av[i][1] == 'o' || !strcmp(av[i]+1, "-ostream")) {
                                                    ++i;
                                                    if (i >= ac) {
                                                        return 0;
                                                    }
                                                    opt->o_path = av[i];
                                                } else {
                                                    opt->err = 1;
                                                }
                                            }
                                        }
                                        return 1;
                                    }
                                    


                                    /**
                                     * \brief Affiche l'usage du programme
                                     */
                                    void
                                    usage (void) {
                                        puts("justify : Justifie le texte passe en entree.                                   ");
                                        puts("justify -c nb_col [-i istream] [-o ostream]                                  \n");
                                        puts("Options :                                                                      ");
                                        puts("-c  Nombre de colonnes.                                                        ");
                                        puts("-i  fichier en entree avec le texte a justifier (par defaut l'entree standard).");
                                        puts("-o  fichier ou sera ecrit le texte justifie (par defaut la sortie standard).   ");
                                        puts("-h  Affiche ce message d'aide.                                                 ");
                                    }
                                    


                                    int
                                    main (int argc, char * argv[]) {
                                        opt_t opt = {NULL, NULL, 0, 0, 0, NULL, NULL};
                                    	
                                        if (!get_options(argc, argv, &opt) || opt.nb_col <= 0 || opt.err || opt.h_active) {
                                            usage();
                                            return opt.h_active ? EXIT_SUCCESS : EXIT_FAILURE;
                                        }
                                    
                                        return EXIT_SUCCESS;
                                    }
                                    


                                    On doit maintenant s'occuper de la redirection des flux d'entrée et de sortie en fonction des choix de l'utilisateur.

                                    On utilise pour cela une fonction pour rediriger les flux qui utilise la fonction `freopen'.
                                    /**
                                     * \brief Redirige le flux pointé par `path' sur `stream' ouvert avec le mode `mode'
                                     *
                                     * @param path   : const char *
                                     * @param mode   : const char *
                                     * @param stream : FILE *
                                     *
                                     * @return Le flot nouvellement ouvert autrement si path vaut NULL `stream'
                                     */
                                    FILE *
                                    redirect_stream(const char * path, const char * mode, FILE * stream) {
                                        FILE * _stream = NULL;
                                    
                                        if (path != NULL) {
                                            if ((_stream = freopen(path, mode, stream)) == NULL) {
                                                perror(path);
                                            }
                                        }
                                    
                                        return path == NULL ? stream : _stream;
                                    }
                                    


                                    On peut ainsi compléter notre fonction main de la façon suivante :
                                    int
                                    main (int argc, char * argv[]) {
                                        opt_t opt = {NULL, NULL, 0, 0, 0, NULL, NULL};
                                    	
                                        if (!get_options(argc, argv, &opt) || opt.nb_col <= 0 || opt.err || opt.h_active) {
                                            usage();
                                            return opt.h_active ? EXIT_SUCCESS : EXIT_FAILURE;
                                        }
                                        
                                    	/* On redirige les flux d'entrée et de sortie */
                                        if ((redirect_stream(opt.i_path, "r", stdin)) == NULL) {
                                            return EXIT_FAILURE;
                                        }
                                    	
                                        if ((redirect_stream(opt.o_path, "w", stdout)) == NULL) {
                                            return EXIT_FAILURE;
                                        }
                                    
                                        return EXIT_SUCCESS;
                                    }
                                    


                                    On arrive maintenant, à la phase clé du programme, la justification du texte :pirate: .

                                    Traitement du texte



                                    Je propose de lire les mots un à un et de les stocker dans une structure de données appelée file. (Plus d'informations sur les files) On lit donc le plus de mots qu'une ligne puisse afficher sur n colonnes en comptant le minimum d'espaces possible. Puis on écrit cette ligne sur la sortie.

                                    On traite donc l'entrée à la volée (on lit un peu puis on écrit). Une autre méthode consiste à mapper (stocker) le fichier en mémoire vive puis de le traiter. Cette autre méthode et plus rapide sur de petits fichiers mais dès que la taille des fichiers augmente (> 750 Mo) la mémoire vive en prends un coup. De plus, elle nécessite deux passages (1: mise en mémoire ; 2: Traitement).

                                    Le but n'étant pas d'implémenter le structure de données file. Je vous donne une implémentation possible.

                                    #ifndef INCLUDED_PILE_H
                                    #define INCLUDED_PILE_H
                                    
                                    #include <stdlib.h>
                                    
                                    typedef struct elem_s {
                                        struct elem_s *next;
                                        void * value;
                                    } elem_t;
                                    
                                    typedef struct queue_s {
                                        struct elem_s * hd;
                                        struct elem_s * tl;
                                        size_t len;
                                    } queue_t;
                                    
                                    /**
                                     * \brief Créer une file et la renvoie
                                     *
                                     * @return file : queue_t *
                                     */
                                    queue_t * init_queue (void);
                                    /**
                                     * @brief Vérifie si la file est vide
                                     *
                                     * @return 1 si la file est vide, autrement 0
                                     */
                                    int queue_is_empty (queue_t *);
                                    /**
                                     * \brief Ajoute un élément à la fin
                                     *
                                     * @param element : void *
                                     * @param file : queue_t *
                                     * 
                                     * @return 0 si échec, autrement 1.
                                     */
                                    int queue_push (void *, queue_t *);
                                    /**
                                     * \brief Dépile un élément au début
                                     *
                                     * @param file : queue_t *
                                     * @param element pour stocker l'élément dépilé : void **
                                     * 
                                     * @return 0 si échec, autrement 1.
                                     */
                                    int queue_pop (queue_t *, void **);
                                    /**
                                     * \brief Vide la file
                                     *
                                     * @param file : queue_t *
                                     *
                                     * @return 0 si échec, autrement 1.
                                     */
                                    int free_queue (queue_t *);
                                    
                                    #endif
                                    

                                    #include <stdio.h>
                                    #include <stdlib.h>
                                    #include "queue.h"
                                    
                                    queue_t *
                                    init_queue (void) {
                                        queue_t * queue = NULL;
                                    
                                        if ((queue = calloc(sizeof *queue, 1)) != NULL) {
                                    		queue->hd = NULL;
                                    		queue->tl = NULL;
                                    		queue->len = 0;
                                    	}
                                    
                                        return queue;
                                    }
                                    
                                    int
                                    queue_is_empty (queue_t * queue) {
                                        return queue->hd == NULL;
                                    }
                                    
                                    int
                                    queue_push (void * value, queue_t * queue) {
                                        elem_t * elem = NULL;
                                    	
                                        if ((elem = calloc(sizeof *elem, 1)) == NULL)
                                            return 0;
                                    
                                        elem->value = value;
                                        elem->next = NULL;
                                        
                                        if (queue_is_empty(queue))
                                            queue->hd = elem;
                                        else
                                            queue->tl->next = elem;
                                    	
                                        queue->tl = elem;
                                        ++queue->len;
                                    
                                        return 1;
                                    }
                                    
                                    int
                                    queue_pop (queue_t * queue, void ** elem) {
                                        elem_t * new_hd = NULL;
                                    	
                                        if (queue_is_empty(queue))
                                            return 0;
                                    
                                        *elem = queue->hd->value;
                                    	new_hd = queue->hd->next;
                                    	
                                        free(queue->hd);
                                        queue->hd = new_hd;
                                    	
                                        --queue->len;
                                        
                                       return 1;
                                    }
                                    
                                    int
                                    free_queue (queue_t * queue) {
                                        if (queue == NULL) {
                                            return 0;
                                        }
                                        
                                        if (!queue_is_empty(queue)) {
                                            while (!queue_is_empty(queue)) {
                                                elem_t * current = queue->hd;
                                                queue->hd = queue->hd->next;
                                                free(current), current = NULL;
                                            }
                                        }
                                        
                                        free(queue), queue = NULL;
                                        return 1;
                                    }
                                    



                                    Premièrement, pour lire les mots, il nous faut une fonction adaptée.

                                    #define MOT_LEN 100
                                    
                                    typedef struct word_s {
                                        size_t len;
                                        int is_end, punct; /* Fin d'un §, mot suivi d'un signe de ponctuation */
                                        char word[MOT_LEN];
                                    } word_t;
                                    
                                    /**
                                     * \brief Vérifie si `c' est un caractère d'espacement
                                     *
                                     * @param c : int
                                     *
                                     * @return 1 si `c' est un caractère d'espacement
                                     */
                                    unsigned int
                                    is_space (int c) {
                                        return c == ' '  || c == '\t' || c == '\f' || c == '\r' || c == '\v';
                                    }
                                    
                                    /**
                                     * \brief Récupère un mot sur l'entrée standard
                                     *
                                     * @return le mot lu
                                     */
                                    word_t *
                                    read_word (void) {
                                        word_t * w = NULL;
                                        int word_read = 0;
                                        
                                        if ((w = calloc(sizeof *w, 1)) == NULL) {
                                            perror("zJustificator");
                                            return NULL;
                                        }
                                        
                                        while (!word_read) {
                                            int c;
                                            
                                            while ((c = getchar()) != EOF && !is_space(c)) {
                                                    word_read = 1;
                                                    w->word[w->len++] = c;
                                                    if (c == '\n') {
                                                        w->is_end = 1;
                                                        break;
                                                    }
                                            }
                                            
                                            if (c == EOF) {
                                                if (word_read) {
                                                    w->is_end = 1;
                                                } else {
                                                    free(w), w = NULL;
                                                    return NULL;
                                                }
                                            }
                                        }
                                        
                                        if (ispunct(w->word[w->len-1])) {
                                            w->punct = 1;
                                        }
                                        
                                        return w;
                                    }
                                    


                                    La fonction stocke le mot dans une structure qui retiens diverses informations utilise sur le mot en question (suivi d'un signe de ponctuation, termine un paragraphe).

                                    Viens maintenant la partie la plus difficile, lire juste assez de mots qu'il ne faut.

                                    La solution que je propose est de lire un mot et de le stocker dans la file. Si le mot dépasse de la ligne (à trop de lettres) on le retient pour la prochaine fois grâce à une variable static. Puis, une fois que l'on a fini de lire la ligne on la renvoie.

                                    De même que pour les mots j'utilise une structure pour la ligne de manière à avoir quelques informations relatives à la ligne traitée.

                                    typedef struct line_s {
                                        queue_t * words; /* La file de mots */
                                        /* Le nombre total de lettres, de mots et de signes de ponctuations */
                                        size_t len, nb_words, nb_punct;
                                        int last; /* Elle est à la fin d'un paragraphe ? */
                                    } line_t;
                                    
                                    /**
                                     * \brief Récupère une ligne sur l'entrée pouvant être justifié sur `nb_col'
                                     *
                                     * @param nb_col : size_t
                                     *
                                     * @return line : line_t *
                                     */
                                    line_t *
                                    get_line (size_t nb_col) {
                                        static word_t * exceed = NULL;
                                        line_t * l = NULL;
                                        word_t * w = NULL;
                                        
                                        if ((l = calloc(sizeof *l, 1)) == NULL) {
                                           perror("zJustificator");
                                           return NULL;
                                        }
                                        if ((l->words = init_queue()) == NULL) {
                                            free(l), l = NULL;
                                            perror("zJustificator");
                                            return NULL;
                                        }
                                        
                                        while (l->len < nb_col && !l->last) {      
                                            w = exceed == NULL ? read_word() : exceed;
                                            exceed = NULL;
                                            if (w == NULL) break;
                                            
                                            if (l->len + w->len + l->nb_words <= nb_col) {       
                                                queue_push(w, l->words);
                                                l->len += w->len;
                                                l->nb_words++;
                                                
                                                if (w->is_end) {
                                                    l->last = 1;
                                                }
                                            } else {
                                                exceed = w;
                                                break;
                                            }
                                        }
                                        
                                        if (l->nb_words) {
                                            return l;
                                        } else {
                                            free_queue(l->words), l->words = NULL;
                                            free(l), l = NULL;
                                            return NULL;
                                        }
                                    }
                                    


                                    Il ne nous reste plus qu'à afficher la ligne récupérée, la ligne affichée est justifiée seulement si elle ne termine pas un paragraphe ce qui ce traduit par :
                                    /**
                                     * \brief Justifie une ligne sur `nb_col' colonnes
                                     *
                                     * @param nb_col : size_t
                                     */
                                    int
                                    justify_line (size_t nb_cols) {
                                        line_t * current_line = NULL;
                                        size_t i;
                                        
                                        if ((current_line = get_line(nb_cols)) == NULL)
                                            return 0;
                                    
                                        if (current_line->last) {
                                    		display_line(nb_cols, current_line, 0);
                                        } else {
                                    		display_line(nb_cols, current_line, 1);
                                            putchar('\n');
                                        }
                                    
                                        free_queue(current_line->words);
                                        free(current_line);
                                    
                                        return 1;
                                    }
                                    



                                    La fonction d'alignement est très simple, elle se contente d'afficher des espaces là où il faut. Il suffit donc de calculer le nombre d'espaces à ajouter et c'est bon.
                                    /**
                                     * \brief Affiche `nb_spaces' espaces sur la sortie standard
                                     *
                                     * @param nb_spaces : size_t
                                     */
                                    void
                                    print_spaces (size_t nb_spaces) {
                                        while (nb_spaces--)
                                            putchar(' ');
                                    }
                                    
                                    /**
                                     * \brief Affiche une ligne en la justifiant sur `nb_col' si `align' vaut1
                                     *
                                     * @param nb_cols : size_t
                                     * @param line    : line_t *
                                     * @param align   : int
                                     */
                                    void
                                    display_line (size_t nb_col, line_t * line, int align) {
                                        int nb_spaces, nb_spaces_punct, nb_spaces_extra;
                                        word_t * w = NULL;
                                        size_t i;
                                        
                                        if (align) {
                                            nb_spaces = line->nb_words > 1 ? (nb_col-line->len)/(line->nb_words-1) : 0;
                                            nb_spaces_punct = line->nb_punct ? (nb_col-nb_spaces*(line->nb_words-1))/line->nb_punct : 0;
                                            nb_spaces_extra = nb_col - line->len - nb_spaces*(line->nb_words-1) - nb_spaces_punct*line->nb_punct;
                                        }
                                        
                                        for (i = 0 ; i < line->nb_words ; ++i) {
                                               
                                            queue_pop(line->words, (void **)&w);
                                            printf("%s", w->word);
                                              
                                            if(i < line->nb_words-1) {
                                                if (!align) {
                                                    putchar(' ');
                                                } else {
                                                    print_spaces(nb_spaces);
                                                    if (nb_spaces_extra) {
                                                        if (i < line->nb_words-2) {
                                                            putchar(' ');
                                                            --nb_spaces_extra;
                                                        } else {
                                                            print_spaces(nb_spaces_extra);
                                                            nb_spaces_extra = 0;
                                                        }
                                                    }
                                                    if (w->punct) {
                                                        print_spaces(nb_spaces_punct);
                                                    }
                                                }
                                           }
                                           
                                           free(w), w = NULL;
                                        }
                                    }
                                    


                                    Pour finir on applique tout ce qui a été décrit au dessus tant qu'il y a des lignes.
                                    /**
                                     * \brief Justifie un texte sur `nb_col' colonnes
                                     *
                                     * @param nb_col : size_t
                                     */
                                    void
                                    zJustificator (size_t nb_col) {
                                        while (justify_line(nb_col))
                                    		/* Nothing */;
                                    }
                                    


                                    Et la fonction main finale :
                                    int
                                    main (int argc, char * argv[]) {
                                        opt_t opt = {NULL, NULL, 0, 0, 0, NULL, NULL};
                                    	
                                        if (!get_options(argc, argv, &opt) || opt.nb_col <= 0 || opt.err || opt.h_active) {
                                            usage();
                                            return opt.h_active ? EXIT_SUCCESS : EXIT_FAILURE;
                                        }
                                        
                                    	/* On redirige les flux d'entrée et de sortie */
                                        if ((redirect_stream(opt.i_path, "r", stdin)) == NULL) {
                                            return EXIT_FAILURE;
                                        }
                                    	
                                        if ((redirect_stream(opt.o_path, "w", stdout)) == NULL) {
                                            return EXIT_FAILURE;
                                        }
                                        
                                        zJustificator(opt.nb_col);
                                    
                                        return EXIT_SUCCESS;
                                    }
                                    


                                    La solution complète :

                                    Les fichiers queue.c et queue.h ont déjà été donnés plus haut.
                                    #include <stdio.h>
                                    #include <stdlib.h>
                                    #include <ctype.h>
                                    #include <string.h>
                                    
                                    #include "queue.h"
                                    
                                    #define MOT_LEN 100
                                    
                                    typedef struct opt_s {
                                        FILE * istream, * ostream;
                                        int nb_col;
                                        int h_active, err;
                                        char * i_path, * o_path;
                                    } opt_t;
                                    
                                    typedef struct word_s {
                                        size_t len;
                                        int is_end, punct;
                                        char word[MOT_LEN];
                                    } word_t;
                                    
                                    typedef struct line_s {
                                        queue_t * words;
                                        size_t len, nb_words, nb_punct;
                                        int last;
                                    } line_t;
                                    
                                    /**
                                     * \brief Affiche l'usage du programme
                                     */
                                    void
                                    usage (void) {
                                        puts("justify : Justifie le texte passe en entree.                                   ");
                                        puts("justify -c nb_col [-i istream] [-o ostream]                                  \n");
                                        puts("Options :                                                                      ");
                                        puts("-c  Nombre de colonnes.                                                        ");
                                        puts("-i  fichier en entree avec le texte a justifier (par defaut l'entree standard).");
                                        puts("-o  fichier ou sera ecrit le texte justifie (par defaut la sortie standard).   ");
                                        puts("-h  Affiche ce message d'aide.                                                 ");
                                    }
                                    
                                    /**
                                     * \brief Parse les options passées au programme
                                     *
                                     * @param ac  : int
                                     * @param av  : char **
                                     * @param opt : opt_t
                                     *
                                     * @return 0 en cas d'échec, 1 autrement
                                     */
                                    int
                                    get_options (int ac, char * av[], opt_t * opt) {
                                        size_t i;
                                    
                                        if (ac < 2)
                                            return 0;
                                        
                                        for (i = 1 ; i < ac ; ++i) {
                                            if (av[i][0] == '-') {
                                                if (av[i][1] == 'h' || !strcmp(av[i]+1, "-help")) {
                                                    opt->h_active = 1;
                                                } else if (av[i][1] == 'c' || !strcmp(av[i]+1, "-columns")) {
                                                    ++i;
                                                    if (i >= ac) {
                                                        return 0;
                                                    }
                                                    if (sscanf(av[i], "%d", &opt->nb_col) != 1 || opt->nb_col < 1) {
                                                        puts("L'option 'c' attend un nombre entier naturel strictement positif.");
                                                        return 0;
                                                    }
                                                } else if (av[i][1] == 'i' || !strcmp(av[i]+1, "-istream")) {
                                                    ++i;
                                                    if (i >= ac) {
                                                        return 0;
                                                    }
                                                    opt->i_path = av[i];
                                                } else if (av[i][1] == 'o' || !strcmp(av[i]+1, "-ostream")) {
                                                    ++i;
                                                    if (i >= ac) {
                                                        return 0;
                                                    }
                                                    opt->o_path = av[i];
                                                } else {
                                                    opt->err = 1;
                                                }
                                            }
                                        }
                                        return 1;
                                    }
                                    
                                    /**
                                     * \brief Affiche `nb_spaces' espaces sur la sortie standard
                                     *
                                     * @param nb_spaces : size_t
                                     */
                                    void
                                    print_spaces (size_t nb_spaces) {
                                        while (nb_spaces--)
                                            putchar(' ');
                                    }
                                    
                                    /**
                                     * \brief Vérifie si `c' est un caractère d'espacement
                                     *
                                     * @param c : int
                                     *
                                     * @return 1 si `c' est un caractère d'espacement
                                     */
                                    unsigned int
                                    is_space (int c) {
                                        return c == ' '  || c == '\t' || c == '\f' || c == '\r' || c == '\v';
                                    }
                                    
                                    /**
                                     * \brief Récupère un mot sur l'entrée standard
                                     *
                                     * @return le mot lu
                                     */
                                    word_t *
                                    read_word (void) {
                                        word_t * w = NULL;
                                        int word_read = 0;
                                        
                                        if ((w = calloc(sizeof *w, 1)) == NULL) {
                                            perror("zJustificator");
                                            return NULL;
                                        }
                                        
                                        while (!word_read) {
                                            int c;
                                            
                                            while ((c = getchar()) != EOF && !is_space(c)) {
                                                    word_read = 1;
                                                    w->word[w->len++] = c;
                                                    if (c == '\n') {
                                                        w->is_end = 1;
                                                        break;
                                                    }
                                            }
                                            
                                            if (c == EOF) {
                                                if (word_read) {
                                                    w->is_end = 1;
                                                } else {
                                                    free(w), w = NULL;
                                                    return NULL;
                                                }
                                            }
                                        }
                                        
                                        if (ispunct(w->word[w->len-1])) {
                                            w->punct = 1;
                                        }
                                        
                                        return w;
                                    }
                                    
                                    /**
                                     * \brief Récupère une ligne sur l'entrée pouvant être justifié sur `nb_col'
                                     *
                                     * @param nb_col : size_t
                                     *
                                     * @return line : line_t *
                                     */
                                    line_t *
                                    get_line (size_t nb_col) {
                                        static word_t * exceed = NULL;
                                        line_t * l = NULL;
                                        word_t * w = NULL;
                                        
                                        if ((l = calloc(sizeof *l, 1)) == NULL) {
                                           perror("zJustificator");
                                           return NULL;
                                        }
                                        if ((l->words = init_queue()) == NULL) {
                                            free(l), l = NULL;
                                            perror("zJustificator");
                                            return NULL;
                                        }
                                        
                                        while (l->len < nb_col && !l->last) {      
                                            w = exceed == NULL ? read_word() : exceed;
                                            exceed = NULL;
                                            if (w == NULL) break;
                                            
                                            if (l->len + w->len + l->nb_words <= nb_col) {       
                                                queue_push(w, l->words);
                                                l->len += w->len;
                                                l->nb_words++;
                                                
                                                if (w->is_end) {
                                                    l->last = 1;
                                                }
                                            } else {
                                                exceed = w;
                                                break;
                                            }
                                        }
                                        
                                        if (l->nb_words) {
                                            return l;
                                        } else {
                                            free_queue(l->words), l->words = NULL;
                                            free(l), l = NULL;
                                            return NULL;
                                        }
                                    }
                                    
                                    /**
                                     * \brief Affiche une ligne en la justifiant sur `nb_col' si `align' vaut1
                                     *
                                     * @param nb_cols : size_t
                                     * @param line    : line_t *
                                     * @param align   : int
                                     */
                                    void
                                    display_line (size_t nb_col, line_t * line, int align) {
                                        int nb_spaces, nb_spaces_punct, nb_spaces_extra;
                                        word_t * w = NULL;
                                        size_t i;
                                        
                                        if (align) {
                                            nb_spaces = line->nb_words > 1 ? (nb_col-line->len)/(line->nb_words-1) : 0;
                                            nb_spaces_punct = line->nb_punct ? (nb_col-nb_spaces*(line->nb_words-1))/line->nb_punct : 0;
                                            nb_spaces_extra = nb_col - line->len - nb_spaces*(line->nb_words-1) - nb_spaces_punct*line->nb_punct;
                                        }
                                        
                                        for (i = 0 ; i < line->nb_words ; ++i) {
                                               
                                            queue_pop(line->words, (void **)&w);
                                            printf("%s", w->word);
                                              
                                            if(i < line->nb_words-1) {
                                                if (!align) {
                                                    putchar(' ');
                                                } else {
                                                    print_spaces(nb_spaces);
                                                    if (nb_spaces_extra) {
                                                        if (i < line->nb_words-2) {
                                                            putchar(' ');
                                                            --nb_spaces_extra;
                                                        } else {
                                                            print_spaces(nb_spaces_extra);
                                                            nb_spaces_extra = 0;
                                                        }
                                                    }
                                                    if (w->punct) {
                                                        print_spaces(nb_spaces_punct);
                                                    }
                                                }
                                           }
                                           
                                           free(w), w = NULL;
                                        }
                                    }
                                    
                                    /**
                                     * \brief Justifie une ligne sur `nb_col' colonnes
                                     *
                                     * @param nb_col : size_t
                                     */
                                    int
                                    justify_line (size_t nb_cols) {
                                        line_t * current_line = NULL;
                                        size_t i;
                                        
                                        if ((current_line = get_line(nb_cols)) == NULL)
                                            return 0;
                                    
                                        if (current_line->last) {
                                    		display_line(nb_cols, current_line, 0);
                                        } else {
                                    		display_line(nb_cols, current_line, 1);
                                            putchar('\n');
                                        }
                                    
                                        free_queue(current_line->words);
                                        free(current_line);
                                    
                                        return 1;
                                    }
                                    
                                    /**
                                     * \brief Justifie un texte sur `nb_col' colonnes
                                     *
                                     * @param nb_col : size_t
                                     */
                                    void
                                    zJustificator (size_t nb_col) {
                                        while (justify_line(nb_col))
                                    		/* Nothing */;
                                    }
                                    
                                    /**
                                     * \brief Redirige le flux pointé par `path' sur `stream' ouvert avec le mode `mode'
                                     *
                                     * @param path   : const char *
                                     * @param mode   : const char *
                                     * @param stream : FILE *
                                     *
                                     * @return Le flot nouvellement ouvert autrement si path vaut NULL `stream'
                                     */
                                    FILE *
                                    redirect_stream(const char * path, const char * mode, FILE * stream) {
                                        FILE * _stream = NULL;
                                    
                                        if (path != NULL) {
                                            if ((_stream = freopen(path, mode, stream)) == NULL) {
                                                perror(path);
                                            }
                                        }
                                    
                                        return path == NULL ? stream : _stream;
                                    }
                                    
                                    int
                                    main (int argc, char * argv[]) {
                                        opt_t opt = {NULL, NULL, 0, 0, 0, NULL, NULL};
                                    	
                                        if (!get_options(argc, argv, &opt) || opt.nb_col <= 0 || opt.err || opt.h_active) {
                                            usage();
                                            return opt.h_active ? EXIT_SUCCESS : EXIT_FAILURE;
                                        }
                                        
                                    	/* On redirige les flux d'entrée et de sortie */
                                        if ((redirect_stream(opt.i_path, "r", stdin)) == NULL) {
                                            return EXIT_FAILURE;
                                        }
                                    	
                                        if ((redirect_stream(opt.o_path, "w", stdout)) == NULL) {
                                            return EXIT_FAILURE;
                                        }
                                        
                                        zJustificator(opt.nb_col);
                                    
                                        return EXIT_SUCCESS;
                                    }
                                    


                                    A bientôt pour le prochain exercice. Qui devrait être plus simple.

                                    Nota : Si vous avez des questions ou des remarques, n'hésitez pas !
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      15 mai 2010 à 21:10:35

                                      Bien content de voir qu'il y a des personnes pour proposer ds exercices, et des corrections.

                                      Manque plus que les participants! :-°
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                      Zeste de Savoir, le site qui en a dans le citron !
                                        16 mai 2010 à 11:25:03

                                        Bonjour.
                                        Dommage, je n'ai pas eu le temps de participer.
                                        Je vais peut-être le faire un peu plus tard.
                                        Emmflo
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          16 mai 2010 à 11:54:19

                                          Me revoilou... je participe au prochain... sur ^^

                                          un grand merci aux gens qui continuent a faire vivre ce type de topic...
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            16 mai 2010 à 13:43:17

                                            zTransforme (16 Mai - 31 Mai)



                                            Cette fois ci, l'exercice sera plus simple et portera sur les tableaux.

                                            1) Vous recevez en entrée un tableau. Après avoir reçu ce tableau, vous devez afficher les lignes à la place des colonnes et les colonnes à la place des lignes.

                                            La première ligne de l'entrée indique les dimensions du tableau, d'abord le nombre de lignes (n) puis le nombre de colonnes (n). Les lignes qui suivent décrivent les valeurs du tableau.

                                            L'énoncé certifie que n et m sont strictement positifs et sont inférieurs à 1000.

                                            Note : le texte qui suit `--` est un commentaire.

                                            -- Entrée 
                                            2 3    -- 2 lignes et 3 colonnes
                                            1 2 3
                                            4 5 6
                                            -- Sortie
                                            1 4
                                            2 5
                                            3 6


                                            2) Vous recevez un tableau en entrée. Votre programme doit faire "tourner" le tableau de 90° dans le sens des aiguilles d'une montre puis afficher le résultat en sortie.

                                            La première ligne de l'entrée indique les dimensions du tableau, d'abord le nombre de lignes (n) puis le nombre de colonnes (n). Les lignes qui suivent décrivent les valeurs du tableau.

                                            L'énoncé certifie que n et m sont strictement positifs et sont inférieurs à 1000.

                                            -- Entrée 
                                            2 3    -- 2 lignes et 3 colonnes
                                            1 2 3
                                            4 5 6
                                            -- Sortie
                                            4 1
                                            5 2
                                            6 3


                                            3) Vous définissez une valeur, par exemple 9. Votre but est d'afficher un carré de 9 de coté (dans notre exemple). Chaque case du tableau contient le numéro de sa colonne. Par contre si cette case appartient à une des diagonales du carré vous mettez un `#` à la place du numéro de la colonne. (Cet exercice est en bonus car il ne traite pas à proprement parler des tableaux).

                                            #-2-3-4-5-6-7-8-# 
                                            1-#-3-4-5-6-7-#-9 
                                            1-2-#-4-5-6-#-8-9 
                                            1-2-3-#-5-#-7-8-9 
                                            1-2-3-4-#-6-7-8-9 
                                            1-2-3-#-5-#-7-8-9 
                                            1-2-#-4-5-6-#-8-9 
                                            1-#-3-4-5-6-7-#-9 
                                            #-2-3-4-5-6-7-8-#


                                            Le sujet créé pour cet exercice est ici ;) .

                                            Indication n°1 : Vous pouvez stocker les tableaux que vous récupérez dans un tableau à deux dimensions. (Exemple : int tab[1000][1000]; )


                                            Indication n°2 : Pour récupérer un entier, utilisez de préférence cette fonction. (De cette manière vous n'aurez pas de surprise si on essaye d'entrer une lettre plutôt qu'un chiffre)


                                            /**
                                             * \brief vide le buffer clavier
                                             */
                                            void
                                            clear_stdin (void) {
                                                int c;
                                                while((c = getchar()) != '\n' && c != EOF);
                                            }
                                            
                                            /**
                                             * \brief Récupère un entier de manière sécurisée
                                             *
                                             * @param msg  : const char *
                                             * @return val : int
                                             */
                                            int
                                            get_i (const char * msg) {
                                                int val;
                                            
                                                if (msg != NULL)    /* S'il y a un message on l'affiche */
                                                    printf("%s", msg);
                                            
                                                while (scanf("%d", &val) != 1) { /* Tant que val ne contient pas un entier */
                                                    puts("Veuillez entrer un nombre entier");
                                                    clear_stdin();
                                                }
                                                clear_stdin();
                                            
                                                return val;
                                            

                                            }



                                            Bonne chance.
                                            Lithrein.
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              16 mai 2010 à 16:25:24

                                              Citation : Lithrein


                                              Cette fois ci, l'exercice sera plus simple et portera sur les tableaux.




                                              Une fois de plus je ne suis pas convaincu de l'exo qui porte trop sur des questions d'entrées/sorties (ici affichage et capture).

                                              En plus les spécifications sont assez vagues (comment les tableaux sont-ils représentés ? les tailles sont-elles fixes ?)

                                              La question 2 est trop proche de la question 1 et n'introduit pas d'élément nouveau pour l'apprentissage du C. D'une façon générale, il faut essayer de scinder le plus possible les questions d'apprentissage du C de questions d'algorithmique, même triviale.


                                              La question 3 est loin d'être convaincante, c'est une question confuse (contours de l'énoncé peu clairs) qui traite de détails de formatage (une fois de plus, des questions de sorties).



                                              Un exercice beaucoup plus direct et intéressant est par exemple : on part d'une grille remplie et on demande de vérifier qu'elle est correctement remplie. La grille peut être un grille de sudoku, un carré latin, un carré magique, etc, à vous de choisir.

                                              Encore plus simple : on donne une grille carrée de nombres et on demande d'écrire une fonction qui dit si oui ou non la grille est symétrique par rapport à sa diagonale principale, par exemple cette grille est symétrique

                                              5 12 3 7
                                              12 0 6 19
                                              3 6 4 68
                                              7 19 68 1

                                              Vous devriez faire des exercices beaucoup plus simples avec une seule question et clairement formulée (ou en tous cas avec des questions homogènes et ce n'est jamais le cas, vous chargez trop la barque et vous n'arrivez pas à vous adresser aux vrais débutants).


                                              Pour toucher votre cible, il suffit de lire les messages sur le forum et d'essayer de comprendre ce qui bloque les débutants.
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                16 mai 2010 à 17:27:24

                                                Merci pour ton intervention Candide, je prends note de tes conseils (entre autre regarder plus les problèmes des zéros).

                                                Je ne voyais pas vraiment comment faire pour faire vraiment sans les entrées/sorties surtout pour les deux première questions. Mais tu me fais remarquer que j'ai encore fais une erreur que j'essaierais de corriger la prochaines fois.

                                                Je retiens aussi les idées que tu m'as donné pour une prochaine fois.

                                                Et puisque tu trouve certains énoncés confus, cela signifie aussi que certains débutants ne les comprendrons pas donc je vais tenter de les rendre plus clairs. Et je donnerais peut-être plus de détails sur comment représenter les tableaux capturés dans le programme.
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  17 mai 2010 à 23:16:06

                                                  Citation : Lithrein

                                                  (entre autre regarder plus les problèmes des zéros).




                                                  Tiens, par exemple, la question récente et récurrente : Fonction transposée matrice (C) où l'on retrouve le problème du passage de tableau 2D à une fonction. Ton exercice, au lieu de s'intéresser à des questions d'affichage et de capture, pouvait permettre d'aborder cette question, à travers la transposée d'une matrice carrée, avec plusieurs méthodes (on modifie la matrice ou bien ou bien on renvoie une autre matrice) et à plusieurs niveaux (allocation statique versus dynamique).


                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                  Anonyme
                                                    18 mai 2010 à 18:46:42

                                                    Bonjour tout le monde,

                                                    Ces exercices sont très bien et merci à leurs concepteurs. J'ai juste une petite remarque moi je débute c'est à dire que j'en suis seulement au premier chapitre du livre : " apprendre à programmer en C". J'ai fini le premier chapitre et en suis tout juste au TP du plus ou du moins. J'avance doucement.
                                                    Bref je voulais savoir si il existe d'autres exercices pour s'entrainer et pour ceux qui ont pas tout étudié encore, je m'aperçois que les exercices proposés ici sont encore un peu trop élevé pour moi ?

                                                    Merci d'avance
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      18 mai 2010 à 18:56:28

                                                      Citation : P@rAd0x


                                                      J'ai fini le premier chapitre et en suis tout juste au TP du plus ou du moins. J'avance doucement.
                                                      Bref je voulais savoir si il existe d'autres exercices pour s'entrainer et pour ceux qui ont pas tout étudié encore,




                                                      Non, et c'est un des manques du cours : de vrais exos (pas des qcm) avec correction et commentaires pour assimiler chaque chapitre.
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                      Anonyme
                                                        19 mai 2010 à 17:36:34

                                                        Merci candide pour ta réponse. Oui c'est bien dommage car des exercices avec correction chapitre par chapitre serait bien utile. Sinon je ne sais pas si j('ai le droit de faire de la pub pour un autre site ( si non, je pense qu'un modérateur, modèrera mon message).
                                                        J'ai trouvé un site nommé France IOI, à chaque chose apprise ils proposent des exercices avec les corrections, si ça manque à certains comme moi.
                                                        En ce qui me concerne c'est extrêmement utile car le livre apprendre à programmer en c est très très bien mais les TP sont trop loin, on a besoin de tester nos connaissances bien avant et pendant la lecture.

                                                        Merci pour tout.
                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          19 mai 2010 à 17:44:04

                                                          Oui c'est vrai qu'on centrait beaucoup les exos un cran trop haut... alors qu'en faisant des exos pour les zer0s, meme ceux qui sont un peu plus avances s'apercoivent que leur maniere de faire n'est pas la bonne :-° (KISS ;) )
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                            22 mai 2010 à 19:15:33

                                                            Slt à tous, je profite du fait que vous fassiez des exos pour vous exposez mon problème, je fais un jeu de poker et il me faut une fonction pour distribuer des cartes de façon aléatoire en mode graphique, j'ai cherché partout sur le net ms je ne trouve rien et la je suis complètement bloqué, je n'arrive plus à avancer.
                                                            • Partager sur Facebook
                                                            • Partager sur Twitter

                                                            Exercices pour débutants en C (suite)

                                                            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                            • Editeur
                                                            • Markdown