Partage
  • Partager sur Facebook
  • Partager sur Twitter

zWc

    10 avril 2010 à 20:58:59

    :p Super même si j arrive pas au bout je persévère .
    • Partager sur Facebook
    • Partager sur Twitter
      14 avril 2010 à 15:25:07

      Bon, je m'ennuyais un peu ce matin, alors j'ai codé un p'tit truc.
      C'est sans doute pas parfait, et peut-être parfois peu idiomatique (ça fait longtemps que j'ai pas fait de C).

      A priori, ça imite à peu près le comportement de wc (du moins, la partie spécifiée), avec les options -l, -c, -w (--lines, --chars qui est le --bytes de wc, --words en version longue), et fonctionnant sur plusieurs fichiers.
      J'affiche la sortie avec un format "à la wc" (lignes - mots - caractères), mais sans padding correct.
      A propos de la gestion du retour à la ligne, j'ai considéré que seul le '\n' était compté comme retour à la ligne, et pas le '\r'.

      Ah oui, aussi, j'ai commenté un peu, mais je pense que globalement c'est suffisement compréhensible pour ne pas nécéssiter plus de commentaires.

      Bon, assez de blabla, voici le code (désolé si c'est un peu tard par rapport aux dates de l'exercice).

      #include <stdio.h>
      #include <stdlib.h>
      
      #define HELP printf("Usage : %s [-l | --lines] [-w | --words]  [-c | --chars] [FILES]\n", argv[0]);
      #define TRY_HELP fprintf(stderr, "Faites `%s -h' ou `%s --help' pour plus d'informations.\n", argv[0], argv[0]);
      
      enum {
        COUNT_CHARS = 1 << 0,
        COUNT_WORDS = 1 << 1,
        COUNT_LINES = 1 << 2
      };
      
      struct counter {
        size_t chars,
               words,
               lines;
      };
      
      /* Teste l'égalité entre deux chaines */
      char equals(char *s, char *t) {
        while (*s) {
          if (*s != *t) {
            return 0;
          }
          ++s;
          ++t;
        }
        return !*t;
      }
      
      /* Affiche le comptage de mot, en accord avec les flags */
      void display(size_t chars, size_t words, size_t lines, char *filename, char flags) {
        if (flags & COUNT_LINES) {
          printf("%d ", lines);
        }
        if (flags & COUNT_WORDS) {
          printf("%d ", words);
        }
        if (flags & COUNT_CHARS) {
          printf("%d ", chars);
        }
        if (filename) {
          printf("%s ", filename);
        }
        putchar('\n');
      }
      
      /* Compte caractères, mots et lignes dans le fichier filename, et affiche le résultat */
      void read_file(char *filename, struct counter *global, unsigned char flags) {
        FILE *file;
        char must_close = 0; /* stdin ne sera pas fermé, tout autre fichier le sera */
        size_t chars = 0,
               words = 0,
               lines = 0;
        char inWord = 0;
        char c;
        
        if (!filename || equals(filename, "-")) {
          file = stdin;
        } else {
          file = fopen(filename, "r");
          if (!file) {
            fprintf(stderr, "Erreur : fichier inexistant (%s)\n", filename);
            return;
          } else {
            must_close = 1;
          }
        }
      
        while ((c = getc(file)) != EOF) {
          ++chars;
          if (c == '\n') {
            ++lines;
          }
          if (c == '\n' || c == ' ' || c == '\t' || c == '\r') {
            if (inWord) {
              inWord = 0;
              ++words;
            }
          } else if (!inWord) {
            inWord = 1;
          }
        }
      
        /* Pourrait être fait plus tard, mais je préfère fermer le fichier dès que je n'en ai plus besoin */
        if (must_close) {
          fclose(file);
        }
      
        if (inWord) {
          ++words;
        }
      
        global->chars += chars;
        global->words += words;
        global->lines += lines;
      
        display(chars, words, lines, filename, flags);
      }
      
      int main(int argc, char *argv[]) {
        int i;
        unsigned char flags = 0;
        char *opt;
        char take_all = 0; /* Après un --, on considère tout comme un fichier */
        unsigned char files = 0; /* Compteur de fichiers */
        struct counter count = {0, 0, 0};
      
        for (i = 1; i < argc; ++i) {
          opt = argv[i];
          if (*opt == '-' && *(opt + 1)) { /* Il s'agit d'une option (- = stdin) */
            ++opt;
            if (*opt == '-') { /* Option longue */
              ++opt;
              if (!*opt) { /* -- = fin des options */
                break;
              } else if (equals(opt, "chars")) {
                flags |= COUNT_CHARS;
              } else if (equals(opt, "words")) {
                flags |= COUNT_WORDS;
              } else if (equals(opt, "lines")) {
                flags |= COUNT_LINES;
              } else if (equals(opt, "help")) {
                HELP;
                return EXIT_SUCCESS;
              } else {
                fprintf(stderr, "Option non reconnue : '--%s'\n", opt);
                TRY_HELP;
                return EXIT_FAILURE;
              }
            } else { /* Option courte */
              while (*opt) {
                switch (*opt) {
                  case 'c': flags |= COUNT_CHARS; break;
                  case 'w': flags |= COUNT_WORDS; break;
                  case 'l': flags |= COUNT_LINES; break;
                  case 'h':
                    HELP;
                    return EXIT_SUCCESS;
                  default:
                    fprintf(stderr, "Option invalide -- '%c'\n", *opt);
                    TRY_HELP;
                    return EXIT_FAILURE;
                  break;
                } /* end switch */
                ++opt;
              } /* end while */
            } /* end if */
          } /* end if */
        } /* end for */
      
        if (!flags) {
          flags = COUNT_CHARS | COUNT_WORDS | COUNT_LINES;
        }
      
        for (i = 1; i < argc; ++i) {
          if (take_all || *argv[i] != '-') { /* C'est un fichier */
            read_file(argv[i], &count, flags);
            ++files;
          } else { /* Ce n'est pas un fichier */
            if (equals(argv[i], "--")) { /* -- : mode take_all */
              take_all = 1;
            }
          }
        }
      
        if (!files) {
          read_file(NULL, &count, flags);
        } else if (files > 1) { /* Si plus d'un fichier, on affiche le total */
          display(count.chars, count.words, count.lines, "total", flags);
        }
      
        return EXIT_SUCCESS;
      }
      
      • Partager sur Facebook
      • Partager sur Twitter
        17 avril 2010 à 16:18:08

        Bon bah voilà mon mien (un peu tard certes, mais la correction n'est pas encore là !) :

        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
        #include <ctype.h>
        
        #ifndef isascii
        # define isascii(c)    1
        #endif
        
        #define ISBLANK(c) (isascii(c) && isblank(c))
        #define ISALNUM(c) (isascii(c) && isalnum(c))
        
        #define SHORT_OPT   0
        #define LONG_OPT    1
        
        typedef char bool;
        
        typedef struct opt_ss {
        	bool car;
        	bool line;
        	bool word;
        	bool help;
        	bool errno;
        } opt_s;
        
        typedef struct res_count_ss {
        	unsigned line;
        	unsigned car;
        	unsigned word;
        } res_count_s;
        
        void get_opt(char * arg, opt_s * opt, bool stat) {
        	while (*arg) {
        		switch (*arg) {
        			case 'c':
        				if ((stat == LONG_OPT && strcmp("char", arg) == 0) ||
        					stat == SHORT_OPT)
        					opt->car = 1;
        				break;
        			case 'l':
        				if ((stat == LONG_OPT && strcmp("line", arg) == 0) ||
        					stat == SHORT_OPT)
        					opt->line = 1;
        				break;
        			case 'w':
        				if ((stat == LONG_OPT && strcmp("word", arg) == 0) ||
        					stat == SHORT_OPT)
        					opt->word = 1;
        				break;
        			case 'h':
        				if ((stat == LONG_OPT && strcmp("help", arg) == 0) ||
        					stat == SHORT_OPT)
        					opt->help = 1;
        				break;
        			default:
        				opt->errno = 1;
        				break;
        		}
        		if (stat == LONG_OPT)
        			return;
        		arg++;
        	}
        }
        
        void get_args(int ac, char *av[], opt_s * opt, char const * (*name_f)) {
        	int i;
        	
        	for (i = 1; i < ac; i++) {
        		if (av[i][0] == '-') {
        			if (av[i][1] == '-')
        				get_opt(av[i]+2, opt, LONG_OPT);
        			else
        				get_opt(av[i]+1, opt, SHORT_OPT);
        		}
        		else if (*name_f == NULL)
        			*name_f = av[i];
        		else {
        			fputs("Erreur: Plusieurs fichiers passes en argument.\n", stderr);
        			opt->errno = 1;
        			return;
        		}
        	}
        	
        	if (ac <= 1 || (ac == 2 && name_f != NULL)) {
        		opt->car = 1;
        		opt->line = 1;
        		opt->word = 1;
        		return;
        	}
        }
        
        
        void usage(FILE * f) {
        	fputs("usage: zwc [-w | -l | -c | -h] [fichier]\n", f);
        }
        
        res_count_s count(FILE * f) {
        	res_count_s res = { 1, 0, 0 };
        	int c;
        	bool isword = 0;
        	
        	while ((c = fgetc(f)) != EOF) {
        		if ((ISBLANK(c) || c == '\n') && isword) {
        			isword = 0;
        			res.word++;
        		}	
        		else if (ISALNUM(c))
        			isword = 1;
        		
        		if (c == '\n') {
        			res.line++;
        			continue;
        		}
        		res.car++;
        	}
        	
        	if (isword)
        		res.word++;
        	
        	return res;
        }
        
        #define ESSE(s)  (&"s"[(s) <= 1])
        
        void print_opt(opt_s opt, res_count_s res) {
        	if (opt.help)
        		usage(stdout);
        	if (opt.line)
        		printf("%u ligne%s\n", res.line, ESSE(res.line));
        	if (opt.word)
        		printf("%u mot%s\n", res.word, ESSE(res.word));
        	if (opt.car)
        		printf("%u caractere%s\n", res.car, ESSE(res.car));
        }
        
        FILE * check_file(char const * name) {
        	FILE * f;
        	if (name == NULL)
        		f = stdin;
        	else {
        		f = fopen(name, "r");
        		if (f == NULL)
        			perror(name);
        	}
        	return f;
        }
        
        void zwc(int ac, char *av[]) {
        	FILE * f = NULL;
        	char const * name_f = NULL;
        	opt_s opt = { 0, 0, 0, 0, 0 };
        	res_count_s res;
        	
        	get_args(ac, av, &opt, &name_f);
        	
        	if (opt.errno) {
        		usage(stderr);
        		return;
        	}
        	
        	f = check_file(name_f);
        	if (f == NULL)
        		return;
        	
        	res = count(f);
        	print_opt(opt, res);
        }
        
        int	main(int ac, char *av[]) {
        	zwc(ac, av);
        	return EXIT_SUCCESS;
        }
        

        Dites moi ce que vous en pensez. :)
        • Partager sur Facebook
        • Partager sur Twitter
          17 avril 2010 à 16:51:28

          Citation : Pouet_forever


          Dites moi ce que vous en pensez. :)




          $ gcc -W -Wall -std=c99 -pedantic -o x wc_pouet.c 
          wc_pouet.c: In function ‘count’:
          wc_pouet.c:110: warning: implicit declaration of function ‘isascii’
          wc_pouet.c: In function ‘zwc’:
          wc_pouet.c:155: warning: missing initializer
          wc_pouet.c:155: warning: (near initialization for ‘opt.line’)
          • Partager sur Facebook
          • Partager sur Twitter
            17 avril 2010 à 16:55:46

            Bizarre pour le isascii, il est bien dans ctype.h. :euh:
            Pour l'autre, on s'en fou. :p
            • Partager sur Facebook
            • Partager sur Twitter
              17 avril 2010 à 18:48:30

              Pour isascii

              Citation


              C99, BSD 4.3. C89 spécifie toutes ces fonctions sauf isascii() et
              isblank(). isascii() est une extension BSD et aussi une extension SVr4.
              isblank() est conforme à POSIX.1-2001 et C99 7.4.1.3. POSIX.1-2008
              marque isalpa() comme étant obsolète.



              Sinon, j'ai juste parcouru, c'est pas mal ça
              #define ESSE(s)  (&"s"[(s) <= 1])
              
              :)

              Sinon, tu dois encore pouvoir factoriser car tes fonctions get_short_opt et get_long_opt sont très similaires finalement.
              • Partager sur Facebook
              • Partager sur Twitter
              Zeste de Savoir, le site qui en a dans le citron !
                17 avril 2010 à 21:10:58

                Citation : Pouet_forever

                Bizarre pour le isascii, il est bien dans ctype.h. :euh:



                Les options de compilation ^^
                • Partager sur Facebook
                • Partager sur Twitter
                  18 avril 2010 à 1:38:56

                  Je connais les options de compilation. :p
                  J'en ai même plus que ceux que tu as mis, mais chez moi le isascii fonctionne très bien. ;)

                  Pour les fonctions, c'est vrai j'aurais pu factoriser, mais au départ j'avais pas du tout géré ça comme ça et finalement bah ... c'est pareil. ^^
                  Je met à jour le code. :)
                  • Partager sur Facebook
                  • Partager sur Twitter
                    18 avril 2010 à 3:16:15

                    Citation : Pouet_forever


                    J'en ai même plus que ceux que tu as mis,



                    Le but n'est pas d'en avoir plus mais d'avoir les bonnes et de ne pas embrouiller les zéros.


                    Citation : Pouet_forever


                    le isascii fonctionne très bien. ;)



                    Je n'en doute pas mais moi je fais du C portable à moins de ne pouvoir faire autrement. As-tu mis l'option std=c99 ?

                    EDIT : je viens de compiler ton nouveau code. Ben c'est pas encore ça :

                    $ gcc -g -W -Wall -std=c99 -pedantic -o x wc_pouet.c 
                    $ wc wc_pouet.c 
                     169  454 3690 wc_pouet.c
                    $ ./x wc_pouet.c 
                    $


                    L'utilisateur "normal" s'attend à un comportement comparable à celui de wc. Ici, l'utilisateur reste en carafe. Sais-tu qu'un petit exemple aide l'utilisateur néophyte à comprendre rapidement comment on interface ton programme ?
                    • Partager sur Facebook
                    • Partager sur Twitter
                      18 avril 2010 à 11:40:24

                      Ce que je voulais dire par là c'est que si j'avais eu un warning je l'aurais corrigé ...
                      Oui, je compile avec le c99.

                      Pour wc, on aura pas les mêmes résultats parce qu'on ne prend pas les mêmes caractères en compte, donc ont peut l'utiliser peut-être pour donner un ordre d'idée mais pas pour comparer les résultats.
                      A part les options 'longues' le reste est conforme à l'exercice demandé, donc aucun intérêt.

                      Le code est corrigé. :)
                      • Partager sur Facebook
                      • Partager sur Twitter
                        18 avril 2010 à 14:25:57

                        Citation : Pouet_forever

                        Ce que je voulais dire par là c'est que si j'avais eu un warning je l'aurais corrigé ...



                        Bon, on a du mal à se comprendre tous les deux.


                        Tu me dis que tu mets plus d'options de compilation que moi. Très bien. Simplement, on a un petit paradoxe : Ton code n'est pas standard et poutant tu n'as pas de warning, c'est donc que le lien que je t'ai fourni ci-dessus te sera peut-être utile pour régler correctement ton compilateur.


                        A moins que tu aies décidé de ne pas écrire du C standard. Aucun problème, il suffit juste de prévenir les gens à qui tu demandes de te donner leur avis. Mais cela a pour conséquence que par exemple, tu ne pourras être compilé sur VC++ ou d'autres implémentations : pour une fonction aussi basique que wc, cela me parait dommage.



                        Citation : Pouet_forever


                        Oui, je compile avec le c99.



                        Là encore, tu fais preuve d'imprécision et tu ne cherches pas à comprendre ce que je te dis. Je ne te demande pas de me dire si tu compiles en C99, je te posais la question de savoir si tu places l'option de compilation -std=c99 ce qui n'est pas la même chose.

                        Citation : Pouet_forever


                        Pour wc, on aura pas les mêmes résultats parce qu'on ne prend pas les mêmes caractères en compte,



                        A bon, quelles sont les différences ? Vous n'avez pas la même définition du terme word ?



                        Citation : Pouet_forever


                        A part les options 'longues' le reste est conforme à l'exercice demandé, donc aucun intérêt.



                        ????????
                        Aucun intérêt : quoi ?


                        Citation : Pouet_forever


                        Le code est corrigé. :)



                        Bon déjà, il y a quelque chose qui sort :

                        $ ./x wc_pouet.c 
                        173 lignes
                        338 mots
                        3590 caracteres
                        $ wc wc_pouet.c 
                         172  465 3762 wc_pouet.c
                        $


                        Curieuse cette différence entre le nombre de lignes.


                        Bon, je ne suis pas du tout convaincu par ton code que je trouve manquer de simplicité voire ampoulé et en plus pour donner un résultat cahotique.

                        wc est un programme super classique, voici l'implémentation limpide de KR 2: c'est court, direct, simple, sans bavure, facile à comprendre et ... ça donne les bons résultats :


                        #include <stdio.h>
                        #define IN 1                    /* inside a word */
                        #define OUT 0                   /* outside a word */
                        /* count lines, words, and characters in input */
                        int main(void)
                        {
                          int c, nl, nw, nc, state;
                        
                          state = OUT;
                          nl = nw = nc = 0;
                          while ((c = getchar()) != EOF)
                            {
                              ++nc;
                              if (c == '\n')
                                ++nl;
                              if (c == ' ' || c == '\n' || c == '\t')
                                state = OUT;
                              else if (state == OUT)
                                {
                                  state = IN;
                                  ++nw;
                                }
                            }
                          printf("%d %d %d\n", nl, nw, nc);
                        }
                        


                        $ c99 wc_pouet.c ; ./x wc_pouet.c
                        173 lignes
                        338 mots
                        3590 caracteres
                        $ c99 wc_kr2.c ; ./x < wc_pouet.c
                        172 465 3762
                        $ wc wc_pouet.c
                         172  465 3762 wc_pouet.c
                        $





                        • Partager sur Facebook
                        • Partager sur Twitter
                          18 avril 2010 à 14:43:46

                          Ca sert vraiment à rien de parler avec toi, tu polémique pour tout, tu critiques tout le monde sans jamais donner de vraies solutions, et à chaque fois qu'on te répond tu fais celui qui ne comprend rien.
                          Perso ça me gave donc je te répondrai plus ou alors je vais aller direct au clash...

                          Juste pour info :

                          $ wc main.c 
                               172     465    2986 main.c
                          • Partager sur Facebook
                          • Partager sur Twitter
                            18 avril 2010 à 14:59:11

                            Citation : Pouet_forever

                            Ca sert vraiment à rien de parler avec toi


                            Si si, ça peut servir. Tiens, candide, ce serait sympa de demander à c.l.c quel est le résultat standard de putchar(0).
                            • Partager sur Facebook
                            • Partager sur Twitter
                              18 avril 2010 à 15:17:06

                              Citation : Pouet_forever

                              Ca sert vraiment à rien de parler avec toi, tu polémique pour tout, tu critiques tout le monde sans jamais donner de vraies solutions, et à chaque fois qu'on te répond tu fais celui qui ne comprend rien.



                              Ce que je comprends c'est que ton code fait de manière non standard, compliquée, laborieuse, longue et ... incorrecte ce que le code de K&R fait en 25 lignes de code, compréhensibles par un débutant et donnant un résultat correct. Et te renvoyant au K&R, je t'ai donné une VRAIE solution, ça fait 20 ans qu'elle est connue.

                              Donc, oui, si j'ai un conseil à te donner :
                              -- lis crayon à la main le K&R et tu comprendras que programmer correctement, c'est programmer simplement,
                              -- lis crayon à la main le livre de Kernighan et Pike, The practice of programming. Trois mots-clés sont dans la préface : simplicity, clarity, generality. Tu pourras aussi jeter un coup d'oeil sur ce qu'ils disent concernant le préprocesseur.


                              Citation : Marc Mongenet

                              Tiens, candide, ce serait sympa de demander à c.l.c quel est le résultat standard de putchar(0).



                              Quelque chose t'empêche de poser la question toi-même ?
                              • Partager sur Facebook
                              • Partager sur Twitter

                              zWc

                              × 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