Partage
  • Partager sur Facebook
  • Partager sur Twitter

zIdentificator

Exercice de niveau intermédiaire

    27 mai 2010 à 1:18:43

    Bonjour,

    Dans le langage C, on utilise des noms pour définir des variables, des fonctions, des structures, les tags des structures, etc. Les caractères qui constituent ces noms ne doivent pas être choisis sans précaution. Par exemple, les noms dans les déclarations suivantes sont valides :


    int toto42, toto_42, _toto, _42toto_, goto_toto;
    


    mais ceux-ci ne le sont pas :

    int 42_toto, __toto, to-to, _Toto;
    


    et celui-là non plus :

    int goto;
    


    Un nom de variable dans le jargon ça se dit un identificateur.

    zIdentificator



    Je vous propose donc d'écrire un code C qui soit capable de dire oui ou non si une chaîne de caractères est un identificateur valide du langage C [les règles précises sont rappelées ci-dessous].


    Prototype


    Plus précisément, vous devez écrire une fonction zIdentificator dont le prototype sera à votre guise :

    ou bien int zIdentificator(char *id)
    ou bien (moins simple) int zIdentificator(const char *id)

    et qui renverra

    1 si la chaîne id désigne un identificateur valide et
    0 dans le cas contraire.


    On aura besoin d'un tableau de chaînes représentant les mots-clés du langage C (liste rappelée ci-dessous). Ce tableau sera déclaré, avec un "scope" laissé à votre choix, de la façon suivante :

    char *motsClefs[] = {
      "auto",
      "break",
    /* etc.*/
    }
    

    ou si vous voulez compliquer de la façon suivante :

    const char *motsClefs[] = {
      "auto",
      "break",
    /* etc.*/
    }
    


    (voire en utilisant le spécificateur static ).

    Test et affichage


    Il faudra insérer la fonction zIdentificator dans un programme complet contenant une batterie de tests.


    Les chaînes de test seront placées directement dans le code source (de préférence dans un tableau de chaînes statiques) et non pas capturées via une fonction d'entrée comme scanf ou fgets (autrement dit, vous êtes priés de laisser le bling-bling au vestiaire ;) ).



    Un test produira un affichage du genre suivant

    toto       : 1

    ou encore
    __toto     : 0


    Identificateurs valides : règles


    Rappel. -- Un identificateur valide du langage C est une suite non vide de caractères parmi

    *) les 26 caractères alphabétiques minuscules
    *) les 26 caractères alphabétiques majuscules
    *) les 10 chiffres décimaux
    *) le caractère souligné :
    _


    Un identificateur valide est soumis à chacune des 3 contraintes suivantes :

    i) il ne commence pas par un chiffre
    (par exemple 42toto est interdit)

    ii) ses deux premiers caractères NE devront(*) PAS être de l'une de deux formes suivantes
    a) _ suivi de _
    b) _ suivi d'un caractère majuscule.
    (par exemple __toto ou _Toto devront être évités)

    iii) il est différent de n'importe lequel des 37 mots-clés du langage C99 dont voici la liste :


    auto
    break
    case
    char
    const
    continue
    default
    do
    double
    else
    enum
    extern
    float
    for
    goto
    if
    inline
    int
    long
    register
    restrict
    return
    short
    signed
    sizeof
    static
    struct
    switch
    typedef
    union
    unsigned
    void
    volatile
    while
    _Bool
    _Complex
    _Imaginary



    (*) Curieusement, même avec une option sévère comme

    -W -Wall -std=c99 -pedantic


    gcc accepte sans rien dire un identificateur tel que __toto .
    Pourtant la Norme dit bien :


    Citation : C99

    7.1.3 Reserved identifiers
    1 (...)
    — All identifiers that begin with an underscore and either an uppercase letter or another
    underscore are always reserved for any use.



    Commentaires à propos de l'exercice


    Sans être difficile, cet exercice n'est sans doute pas destiné aux débutants. En plus, le thème ne leur paraîtra peut-être pas très ludique. Il faut être à l'aise avec les pointeurs, avoir déjà utilisé des tableaux de pointeurs (pour les mots-clés, les tests). On essaiera d'écrire du code portable et en particulier on utilisera les fonctions ad hoc déclarées dans l'entête <ctype.h>. L'algorithmique des contraintes n'est pas totalement triviale à écrire si on ne veut pas être lourd et pas trop inefficace. On essaiera de respecter les standards reconnus de codage et de donner du code accessible.


    Je propose cet exercice pour ouvrir une discussion qui peut-être intéressante mais je ne m'engage pas à un suivi particulier des codes proposés ni même une correction (bien que j'ai écrit le code avant de vous proposer l'exo).

    • Partager sur Facebook
    • Partager sur Twitter
      27 mai 2010 à 2:18:05

      Citation : candide

      ii) ses deux premiers caractères NE peuvent PAS être de l'une de deux formes suivantes


      Parcequ'il y en a qui vont peut-être essayer de compiler un code avec ces conditions, je remplacerais le verbe "pouvoir" par "devoir" étant donné que la contrainte est purement normative.
      • Partager sur Facebook
      • Partager sur Twitter
        27 mai 2010 à 3:16:13

        Citation : nepser

        Citation : candide

        ii) ses deux premiers caractères NE peuvent PAS être de l'une de deux formes suivantes


        Parcequ'il y en a qui vont peut-être essayer de compiler un code avec ces conditions, je remplacerais le verbe "pouvoir" par "devoir" étant donné que la contrainte est purement normative.



        Ok, je vois ce que tu veux dire. Il est en effet possible d'écrire une variable telle que __toto42 alors qu'il n'est pas possible d'écrire une variable telle que 42toto . Par contre, je pensais que gcc mettait au moins un warning si on lui passait du -Wextra -W alors que ce n'est pas du tout le cas. Et j'ai regardé la doc de gcc et je n'ai pas trouvé trace d'une option permettant cet avertissement. Curieux quand même. Bon je vais reformuler.Merci de ton observation.
        • Partager sur Facebook
        • Partager sur Twitter
          27 mai 2010 à 4:16:49

          Voilà mon essai :
          #include <stdio.h>
          #include <ctype.h>
          #include <string.h>
          
          static const char *keywords[] = {
                  "auto",
                  "break",
                  "case",
                  "char",
                  "const",
                  "continue",
                  "default",
                  "do",
                  "double",
                  "else",
                  "enum",
                  "extern",
                  "float",
                  "for",
                  "goto",
                  "if",
                  "inline",
                  "int",
                  "long",
                  "register",
                  "restrict",
                  "return",
                  "short",
                  "signed",
                  "sizeof",
                  "static",
                  "struct",
                  "switch",
                  "typedef",
                  "union",
                  "unsigned",
                  "void",
                  "volatile",
                  "while",
                  "_Bool",
                  "_Complex",
                  "_Imaginary",
                  0
          };
          
          static int is_keyword(const char *);
          
          static int
          zIdentificator(const char *id)
          {
                  int i, valid = 1;
                  int len = strlen(id);
          
                  /* Contrainte i) */
                  if (isdigit(id[0]))
                          valid = 0;
          
                  /* Contrainte ii) */
                  if (id[0] == '_' && (id[1] == '_' || isupper(id[1])))
                          valid = 0;
          
                  /* Contrainte iii) */
                  if (is_keyword(id))
                          valid = 0;
          
                  for (i = 0; i < len && valid; i++)
                          /* Utilisation d'un caractère ilégal */
                          if (!isalnum(id[i]) && id[i] != '_')
                                  valid = 0;       
          
                  return valid;
          }
          
          static int
          is_keyword(const char *id)
          {
                  int i;
          
                  for (i = 0; keywords[i]; i++)
                          if (!strcmp(id, keywords[i]))
                                  return 1;
                  return 0;
          }
          
          int
          main(void)
          {
                  int i;
                  static const char *test_strings[] = {
                          "42toto",
                          "__toto",
                          "_Toto",
                          "continue",
                          "foo",
                          0
                  };
                  
                  for (i = 0; test_strings[i]; i++)
                          printf("%-15s : %d\n", test_strings[i], zIdentificator(test_strings[i]));
          
                  return 0;
          }
          

          ./out 
          42toto          : 0
          __toto          : 0
          _Toto           : 0
          continue        : 0
          foo             : 1
          • Partager sur Facebook
          • Partager sur Twitter
            27 mai 2010 à 4:39:28

            #include <stdio.h>
            #include <stdlib.h>
            #include <ctype.h>
            #include <string.h>
            
            static const char *keywords[] =
            {
                "auto", "break", "case", "char", "const", "continue", "default",
                "do", "double", "else", "enum", "extern", "float", "for", "goto",
                "if", "inline", "int", "long", "register", "restrict", "return",
                "short", "signed", "sizeof", "static", "struct", "switch",
                "typedef", "union", "unsigned", "void", "volatile", "while",
                "_Bool", "_Complex", "_Imaginary"
            };
            
            
            int zIdentificator(const char *id)
            {
                int i;
                const char *str = id;
            
                if(isdigit(*id) || (*id == '_' && (*(id+1) == '_' || isupper(*(id+1)))))
                    return 0;
            
                while(*str)
                {
                    if(*str != '_' && !isalnum(*str))
                        return 0;
                    str++;
                }
            
                for(i = 0; i < 37; i++)
                    if(!strcmp(id, keywords[i]))
                        return 0;
                
                return 1;
            }
            
            
            int main(void)
            {
                int i;
                const char *id[] = {"a", "toto42", "toto_42", "_toto", "_42toto_", "goto_toto", "42_toto", "__toto", "to-to", "_Toto"};
            
                for(i = 0; i < 10; i++)
                    printf("%s: %d\n", id[i], zIdentificator(id[i]));
            
                return EXIT_SUCCESS;
            }
            


            Hop :p
            Le code est volontairement "condensé" et donc assez sale, je code plus proprement normalement, mais c'est plus marrant pour ce genre d'exercice. Je pense que ça fonctionne à part ça.
            • Partager sur Facebook
            • Partager sur Twitter
              27 mai 2010 à 6:16:07

              Bonjour :)

              Un autre essai, je vois que je suis le seul, pour l'instant, à m'être servi de bsearch pour vérifier la présence d'un mot réservé du langage. vu le nombre de mots c'est peu important.

              #include <stdio.h>
              #include <stdlib.h>
              #include <string.h>
              #include <ctype.h>
              
              #define NELEM(t)(sizeof (t) / sizeof (*t))
              
              /* Fonction de comparaison de chaînes */
              int cmpStr(void const *a, void const *b)
              {
                  char const *const *pa = a;
                  char const *const *pb = b;
              
                  return strcmp(*pa, *pb);
              }
              
              /* Retourne 1 si src est un mot clef, 0 sinon */
              int isKeyword ( char const *src )
              {
                  static char const *s_keywords[] =
                  {
                      "auto", "break", "case", "char", "const", "continue", "default", "do",
                      "double", "else", "enum", "extern", "float", "for", "goto", "if", "inline",
                      "int", "long", "register", "restrict", "return", "short", "signed",
                      "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned",
                      "void", "volatile", "while", "_Bool", "_Complex", "_Imaginary",
                  };
              
                  char *p = bsearch(&src, s_keywords, NELEM(s_keywords),
                                    sizeof *s_keywords, cmpStr);
                  return p != NULL;
              }
              
              /* Retourne 1 si src est un identifiant valide, 0 sinon */
              int zIdentificator ( char const *src )
              {
                  int ret = 0;
                  if ( src && *src )
                  {
                      if ( !isdigit ( src[0] )
                              && ( src[0] != '_' || ( src[1] != '_' && !isupper ( src[1] ) ) ) )
                      {
                          char const *p = src;
              
                          ret = 1;
                          while ( isalnum ( *p ) || *p == '_' )
                              *p++;
              
                          ret = *p ? 0 : !isKeyword ( src );
                      }
                  }
                  return ret;
              }
              
              
              
              int main ( void )
              {
                  size_t i;
                  int err = 0;
                  static struct test
                  {
                      char const *s_identificator;
                      int expected;
                  }s[] =
                  {
                      {"toto_42"      , 1},
                      {"_toto"        , 1},
                      {"_42toto_"     , 1},
                      {"goto_toto"    , 1},
                      {"42_toto"      , 0},
                      {"__toto"       , 0},
                      {"to-to"        , 0},
                      {"_ Toto"       , 0},
                      {"_Toto"        , 0},
                      {"goto"         , 0},
                      {"_Imaginary"   , 0},
                      {"with space"   , 0},
                      {""             , 0},
                      {NULL           , 0}
                  };
              
                  for ( i = 0; i < NELEM ( s ) && !err; i++ )
                  {
                      int res = zIdentificator ( s[i].s_identificator );
                      if ( res != s[i].expected )
                      {
                          printf ( "%s -> %d expected %d\n",
                                   s[i].s_identificator, res, s[i].expected );
                          err = 1;
                      }
                  }
              
                  puts ( err ? "KO" : "OK" );
              
                  return EXIT_SUCCESS;
              }
              

              • Partager sur Facebook
              • Partager sur Twitter
              Zeste de Savoir, le site qui en a dans le citron !
                27 mai 2010 à 9:11:58

                L'usage veut que l'on ait un argument des fonctions de ctype.h du bon type.


                -> mob
                Ton zIdentificator peut être amélioré pour être plus efficace. Tu passes tous mes tests sauf 1. Sinon, j''aime bien ta façon de finir le parcours de l'examen de la liste des mots-clefs. Avec un pointeur plutôt qu'un indice ce serait encore plus "C".

                -> zbm
                Ton zIdentificator me parait correct. Mais il y a un de mes tests que tu ne passes pas. Je pense que ta boucle while pourrait s'écrire sans le if dans son corps ce qui a la réputation de ralentir l'exécution. Pour le test du mot-clef, je trouve dommage d'utiliser la constante magique 37.

                -> Gurney
                Ton zIdentifactor me semble très bien, t'as juste un warning à corriger et ta ligne 45 (ret=1) n'est pas utile. Ta ligne 49 est bien vue. Tu passes tous mes tests. Concernant le bsearch, ce ne sera pas portable puisque l'ordre alphabétique doit être corrélé avec l'ordre des caractères du jeu d'exécution. L'alternative c'est une table de hachage (?).

                • Partager sur Facebook
                • Partager sur Twitter
                  27 mai 2010 à 10:25:55

                  Citation : candide


                  gcc accepte sans rien dire un identificateur tel que __toto .
                  Pourtant la Norme dit bien :

                  Citation : C99

                  7.1.3 Reserved identifiers
                  1 (...)
                  — All identifiers that begin with an underscore and either an uppercase letter or another
                  underscore are always reserved for any use.



                  Le fait qu'ils soient réservés ne signifie pas que le compilateur doit les rejeter. Au contraire, ils sont réservés pour être utilisés, mais pas par le programmeur. Ils sont à disposition pour l'environnement de développement. Pour émettre des avertissement, le compilateur devrait sans doute contenir de la logique pour distinguer le code qui vient du programmeur, du code qui vient de l'environnement. Et cela serait sans doute un peu boiteux.
                  • Partager sur Facebook
                  • Partager sur Twitter
                    27 mai 2010 à 11:11:22

                    Citation : candide


                    t'as juste un warning à corriger et ta ligne 45 (ret=1) n'est pas utile


                    Quel warnning, stp(je n'ai rien avec mes options)? par contre c'est vrai que ret = 1 est inutile. :-°

                    Pour le bsearch, c'est vrai également. En pratique on ne l'utilises pas sur des chaînes de caractères, alors?
                    • Partager sur Facebook
                    • Partager sur Twitter
                    Zeste de Savoir, le site qui en a dans le citron !
                      27 mai 2010 à 12:29:15

                      Citation : GurneyH


                      Quel warnning, stp(je n'ai rien avec mes options)?



                      candide@~/zIdentificator$ alias c99
                      alias c99='gcc -W -Wall -std=c99 -pedantic -o x'
                      candide@~/zIdentificator$ c99 gurney.c 
                      gurney.c: In function ‘zIdentificator’:
                      gurney.c:47: warning: value computed is not used
                      candide@~/zIdentificator$



                      Citation : GurneyH


                      Pour le bsearch, c'est vrai également. En pratique on ne l'utilises pas sur des chaînes de caractères, alors?



                      J'en sais rien à vrai dire. D'après mes consultations de codes-sources, bsearch est peu utilisé en général (parce que déjà, à mon avis, la fonction est mal foutue). Néanmoins, j'ai le code source d'un cross-compilateur Z80 qui utilise un bsearch pour chercher des identificateurs.
                      • Partager sur Facebook
                      • Partager sur Twitter
                        27 mai 2010 à 12:59:29

                        Citation : candide

                        -> mob
                        Ton zIdentificator peut être amélioré pour être plus efficace. Tu passes tous mes tests sauf 1. Sinon, j''aime bien ta façon de finir le parcours de l'examen de la liste des mots-clefs. Avec un pointeur plutôt qu'un indice ce serait encore plus "C".


                        Quel test ? Histoire que je puisse corriger.

                        Pour l'amélioration des performances, j'aimerais bien une indication. Je n'ai pas codé avec les performances en tête et de toutes façons je pense que ce n'est pas très important ici, mais je ne vois quand même pas comment améliorer le code de ce côté là, et j'aimerais donc bien savoir.
                        • Partager sur Facebook
                        • Partager sur Twitter
                          27 mai 2010 à 13:27:20

                          @ mob : Par exemple, tu peux faire l’économie de l’appel à strlen, pour éviter de parcourir deux fois la chaîne (une première fois par strlen, une seconde fois toi-même). Dans ce cas, tu boucles non pas sur un indice tant que celui-ci est inférieur à la longueur de la chaîne, mais directement sur les caractères de la chaîne jusqu’à ce que tu arrives sur le zéro terminal.

                          Autre chose, dès qu’une contrainte n’est pas satisfaite, ce n’est pas la peine de tester les suivantes.

                          Par ailleurs, tu peux supprimer _Bool, _Complex et _Imaginary de la liste des mots-clefs, puisqu’un tel identificateur serait déjà rejeté par la contrainte n°2.
                          • Partager sur Facebook
                          • Partager sur Twitter
                            27 mai 2010 à 13:35:31

                            Citation : GoutteGD


                            Par ailleurs, tu peux supprimer _Bool, _Complex et _Imaginary de la liste des mots-clefs, puisqu’un tel identificateur serait déjà rejeté par la contrainte n°2.


                            Bien vu!

                            edit:
                            alias c99='gcc -W -Wall -std=c99 -pedantic -o x'
                            je ne comprend plus, dans mes options, j'ai déjà -Wall -Wextra -pedantic, et... rien o_O
                            Pourtant ce warning est bien légitime, j'ai un gros doute là, -W n'est pas déprécié?
                            • Partager sur Facebook
                            • Partager sur Twitter
                            Zeste de Savoir, le site qui en a dans le citron !
                              27 mai 2010 à 13:38:54

                              Citation : gouttegd

                              @ mob : Par exemple, tu peux faire l’économie de l’appel à strlen, pour éviter de parcourir deux fois la chaîne (une première fois par strlen, une seconde fois toi-même). Dans ce cas, tu boucles non pas sur un indice tant que celui-ci est inférieur à la longueur de la chaîne, mais directement sur les caractères de la chaîne jusqu’à ce que tu arrives sur le zéro terminal.

                              Autre chose, dès qu’une contrainte n’est pas satisfaite, ce n’est pas la peine de tester les suivantes.

                              Par ailleurs, tu peux supprimer _Bool, _Complex et _Imaginary de la liste des mots-clefs, puisqu’un tel identificateur serait déjà rejeté par la contrainte n°2.


                              Hum effectivement. J'attends que Candide m'indique le test que je ne passe pas pour corriger mon code et prendre en compte ces remarques :).
                              • Partager sur Facebook
                              • Partager sur Twitter
                                27 mai 2010 à 14:42:03

                                Citation : mob

                                Hum effectivement. J'attends que Candide m'indique le test que je ne passe pas pour corriger mon code et prendre en compte ces remarques :).


                                Peut-être la chaine vide? C'est un classique.
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  27 mai 2010 à 17:00:35

                                  Citation : gouttegd

                                  @ mob : Par exemple, tu peux faire l’économie de l’appel à strlen, pour éviter de parcourir deux fois la chaîne (une première fois par strlen, une seconde fois toi-même). Dans ce cas, tu boucles non pas sur un indice tant que celui-ci est inférieur à la longueur de la chaîne, mais directement sur les caractères de la chaîne jusqu’à ce que tu arrives sur le zéro terminal.

                                  Autre chose, dès qu’une contrainte n’est pas satisfaite, ce n’est pas la peine de tester les suivantes.



                                  Oui, c'est à cela que je pensais.

                                  Citation : gouttegd


                                  Par ailleurs, tu peux supprimer _Bool, _Complex et _Imaginary de la liste des mots-clefs, puisqu’un tel identificateur serait déjà rejeté par la contrainte n°2.



                                  Oui, je l'avais vu mais je trouve curieux de les retirer de la liste.

                                  Citation : GurneyH


                                  edit:

                                  alias c99='gcc -W -Wall -std=c99 -pedantic -o x'

                                  je ne comprend plus, dans mes options, j'ai déjà -Wall -Wextra -pedantic, et... rien o_O
                                  Pourtant ce warning est bien légitime, j'ai un gros doute là, -W n'est pas déprécié?



                                  Je crois que maintenant c'est plutôt -Wextra.

                                  Citation : Marc Mongenet


                                  Peut-être la chaine vide?



                                  Exactement.
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    28 mai 2010 à 7:41:49

                                    Voilà un code qui prend en compte les remarques de gouttegd et qui considère que la chaîne vide est un identificateur incorrect.
                                    #include <stdio.h>
                                    #include <ctype.h>
                                    #include <string.h>
                                    
                                    static const char *keywords[] = {
                                            "auto", "break", "case", "char", "const", 
                                            "continue", "default", "do", "double", "else", 
                                            "enum", "extern", "float", "for", "goto", "if", 
                                            "inline", "int", "long", "register", "restrict", 
                                            "return", "short", "signed", "sizeof", "static", 
                                            "struct", "switch", "typedef", "union", 
                                            "unsigned", "void", "volatile", "while", 0
                                    };
                                    
                                    static int is_keyword(const char *);
                                    
                                    static int
                                    zIdentificator(const char *id)
                                    {
                                            /* Chaine vide ? */
                                            if (!*id)
                                                    return 0;
                                            
                                            /* Contrainte i) */
                                            if (isdigit(id[0]))
                                                    return 0;
                                    
                                            /* Contrainte ii) */
                                            if (id[0] == '_' && (id[1] == '_' || isupper(id[1])))
                                                    return 0;
                                    
                                            /* Contrainte iii) */
                                            if (is_keyword(id))
                                                    return 0;
                                    
                                            do
                                                    /* Utilisation d'un caractère ilégal */
                                                    if (!isalnum(*id) && *id != '_')
                                                            return 0;
                                            while (*++id);
                                                    
                                            return 1;
                                    }
                                    
                                    static int
                                    is_keyword(const char *id)
                                    {
                                            int i;
                                    
                                            for (i = 0; keywords[i]; i++)
                                            {
                                                    if (!strcmp(id, keywords[i]))
                                                            return 1;
                                            }
                                            return 0;
                                    }
                                    
                                    int
                                    main(void)
                                    {
                                            int i;
                                            static const char *test_strings[] = {
                                                    "42toto",
                                                    "__toto",
                                                    "_Toto",
                                                    "continue",
                                                    "foo",
                                                    "",
                                                    0
                                            };
                                            
                                            for (i = 0; test_strings[i]; i++)
                                                    printf("%-15s : %d\n", test_strings[i], zIdentificator(test_strings[i]));
                                    
                                            return 0;
                                    }
                                    
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      12 juin 2010 à 12:55:05

                                      J'avais pas vu ce topic, Adroneus tu peux l'"épingler" dans les exos stp. :)
                                      Voilà mon code :

                                      #include <stdio.h>
                                      #include <stdlib.h>
                                      #include <string.h>
                                      #include <ctype.h>
                                      
                                      #define N_KEY 38
                                      
                                      char * keywords[N_KEY] = {
                                        "auto", "break", "case", "char", "const", "continue", "default",
                                        "do", "double", "else", "enum", "extern", "float", "for", "goto",
                                        "if", "inline", "int", "long", "register", "restrict", "return",
                                        "short", "signed", "sizeof", "static", "struct", "switch",
                                        "typedef", "union", "unsigned", "void", "volatile", "while",
                                        "_Bool", "_Complex", "_Imaginary", ""
                                      };
                                      
                                      int zIdentificator(char * s) {
                                        int i;
                                        
                                        for (i = 0; i < N_KEY; i++)
                                          if (strcmp(s, keywords[i]) == 0)
                                            return 0;
                                        
                                        if (isnumber(*s))
                                          return 0;
                                        
                                        if (*s == '_') {
                                          if (*(s+1) == '_' || isupper(*(s+1)))
                                              return 0;
                                          else
                                            s++;
                                        }
                                        
                                        for ( ; *s; s++)
                                          if (!isalnum(*s) && *s != '_')
                                            return 0;
                                        
                                        return 1;
                                      }
                                      
                                      #define N 6
                                      
                                      int main(void) {
                                        char * s[N] = {
                                          "toto", "__toto", "42toto", "_Complex", "_Toto", "EL_GRINGO"
                                        };
                                        int i;
                                        
                                        for (i = 0; i < N; i++)
                                          printf("%-10s: %d\n", s[i], zIdentificator(s[i]));
                                        return EXIT_SUCCESS;
                                      }
                                      
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        12 juin 2010 à 15:50:23

                                        Citation : Pouet_forever


                                        Voilà mon code :




                                        pouet.c: In function ‘zIdentificator’:
                                        pouet.c:24: warning: implicit declaration of function ‘isnumber’
                                        /tmp/ccuu52IH.o: In function `zIdentificator':
                                        pouet.c:(.text+0x4d): undefined reference to `isnumber'
                                        collect2: ld returned 1 exit status
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          12 juin 2010 à 16:06:01

                                          int isnumber(int c) {
                                            return c >= '0' && c <= '9';
                                          }
                                          
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            12 juin 2010 à 16:08:49

                                            Pourquoi pas isdigit, alors que tu inclues <ctype.h>? o_O
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                            Zeste de Savoir, le site qui en a dans le citron !
                                              12 juin 2010 à 21:34:10

                                              Citation : Pouet_forever

                                              int isnumber(int c) {
                                                return c >= '0' && c <= '9';
                                              }
                                              


                                              Cela rectifié, tu passes tous mes tests :


                                              toto       : 1
                                              toto42     : 1                                                                                                
                                              Toto       : 1
                                              c          : 1
                                              to         : 1                                                                                                
                                              _          : 1                                                                                                
                                              _t         : 1
                                              _toto      : 1                                                                                                
                                              _bool      : 1                                                                                                
                                              _4         : 1
                                              _42_toto   : 1
                                                         : 0                                                                                                
                                              4          : 0
                                              42         : 0
                                              4_         : 0
                                              to-to      : 0
                                              __         : 0
                                              __toto     : 0                                                                                                
                                              _Toto      : 0
                                              _____      : 0
                                              goto       : 0
                                              return     : 0
                                              _Bool      : 0
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                13 juin 2010 à 12:33:09

                                                Je poste mon code, il n'est pas très condensé, j'attends vos remarques :)
                                                #include <stdio.h>
                                                #include <stdlib.h>
                                                #include <string.h>
                                                #include <ctype.h>
                                                
                                                #define NB_MOTS_CLEFS 37
                                                
                                                const char *motsClefs[] = {
                                                    "auto","break","case","char","const","continue","default","do","double",
                                                    "else","enum","extern","float","for","goto","if","inline","int","long",
                                                    "register","restrict","return","short","signed","sizeof","static","struct",
                                                    "switch","typedef","union","unsigned","void","volatile","while","_Bool",
                                                    "_Complex","_Imaginary"
                                                };
                                                
                                                int zIdentificator(const char *id)
                                                {
                                                    int i;
                                                
                                                    if (id == NULL)
                                                	return 0;
                                                
                                                    if (id[0] == '\0')
                                                	return 0;
                                                
                                                    if (isdigit(id[0]))
                                                	return 0;
                                                
                                                    if (id[0] == '_' && (id[1] == '_' || isupper(id[1])))
                                                	return 0;
                                                
                                                    for (i=0; id[i] != '\0'; i++)
                                                	if (!isalnum(id[i]) && (id[i] != '_'))
                                                	    return 0;
                                                
                                                    for (i=0; i<NB_MOTS_CLEFS; i++)
                                                	if (!strcmp(id, motsClefs[i]))
                                                	    return 0;
                                                
                                                    return 1;
                                                }
                                                
                                                void test_zIdentificator(const char *id)
                                                {
                                                    printf("%s\t: %d\n", id, (zIdentificator(id)) ? 1 : 0);
                                                }
                                                
                                                int main(int argc, char *argv[])
                                                {
                                                    const char *chaine_test[] = {"toto", "toto42", "Toto", "c", "to", "_", "_t", "_toto", "_bool", "_4", "_42_toto", "", "4", "42", "4_", "to-to", "__", "__toto", "_Toto", "____", "goto", "return", "_Bool"};
                                                    int i;
                                                
                                                    for (i=0; i<23; i++)
                                                	test_zIdentificator(chaine_test[i]);
                                                
                                                    return 0;
                                                }
                                                

                                                Et les tests :
                                                toto     : 1
                                                toto42   : 1
                                                Toto     : 1
                                                c        : 1
                                                to       : 1
                                                _        : 1
                                                _t       : 1
                                                _toto    : 1
                                                _bool    : 1
                                                _4       : 1
                                                _42_toto : 1
                                                         : 0
                                                4        : 0
                                                42       : 0
                                                4_       : 0
                                                to-to    : 0
                                                __       : 0
                                                __toto   : 0
                                                _Toto    : 0
                                                ____     : 0
                                                goto     : 0
                                                return   : 0
                                                _Bool    : 0
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  13 juin 2010 à 12:40:14

                                                  A quoi te sert NB_MOTS_CLEFS ? Tu ne n'utilises pas. :)
                                                  Tes 2 macros sont fausses. Tu exclus 0, 9, A, et Z. L'opérateur ternaire n'est pas nécessaire. :)
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    13 juin 2010 à 12:45:10

                                                    Citation : Pouet_forever

                                                    A quoi te sert NB_MOTS_CLEFS ? Tu ne n'utilises pas. :)
                                                    Tes 2 macros sont fausses. Tu exclus 0, 9, A, et Z. L'opérateur ternaire n'est pas nécessaire. :)


                                                    NB_MOTS_CLEFS c'était pour la boucle for (je l'ai remplacé). :-°
                                                    J'avais pas vu pour les maccros effectivement :euh:
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      13 juin 2010 à 14:04:06

                                                      j'ai fait ma batterie de tests sur ton code et c'est bon.
                                                      Juste, tu es dans le même cas que Pouet, si on passe NULL -> crash...
                                                      M'enfin c'est le cas de pas mal de fonctions de la libc(toutes?).

                                                      Sinon, pourquoi recoder les fonctions de ctype.h et strcmp?

                                                      Et pour finir, on voit tout de même qu'il y a de la place pour les exercices(pas forcément pour débutants), le tout c'est de trouver les bons. ;)
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                      Zeste de Savoir, le site qui en a dans le citron !
                                                        13 juin 2010 à 14:24:59

                                                        Citation : GurneyH

                                                        j'ai fait ma batterie de tests sur ton code et c'est bon.
                                                        Juste, tu es dans le même cas que Pouet, si on passe NULL -> crash...
                                                        M'enfin c'est le cas de pas mal de fonctions de la libc(toutes?).


                                                        Effectivement je vais rajouter un petit test :-°

                                                        Citation : GurneyH

                                                        Sinon, pourquoi recoder les fonctions de ctype.h et strcmp?


                                                        Entrainement :p C'est vrai que ça rajoute un peu de code mais bon :D

                                                        Edit : Modif du code avec ctype ^^
                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                        Anonyme
                                                          13 juin 2010 à 15:00:53

                                                          Salut salut !

                                                          Voici ma version:
                                                          #include <stdio.h>
                                                          #include <stdlib.h>
                                                          #include <string.h>
                                                          #include <ctype.h>
                                                          
                                                          int zIdentificator(char *word) {
                                                          	static const char *keywords[] = {
                                                          		"auto", "break", "case", "char", "const", "continue", "default",
                                                          		"do", "double", "else", "enum", "extern", "float", "for", "goto",
                                                          		"if", "inline", "int", "long", "register", "restrict", "return",
                                                          		"short", "signed", "sizeof", "static", "struct", "switch",
                                                          		"typedef", "union", "unsigned", "void", "volatile", "while",
                                                          		"_Bool", "_Complex", "_Imaginary"
                                                          	};
                                                          	int i;
                                                          	int j;
                                                          
                                                          	if(word == NULL)
                                                          		return 0;
                                                          
                                                          	if(*word >= '!' && *word < 'A')
                                                          		return 0;
                                                          
                                                          	else if(*word == '_' && word[1] == '_')
                                                          		return 0;
                                                          
                                                          	else if(*word == '_' && isupper(word[1]))
                                                          		return 0;
                                                          
                                                          	for(i = 0, j = 1 ; i < 36 && j ; i++) {
                                                          		j = strcmp(keywords[i], word);
                                                          	}
                                                          	if(!j)
                                                          		return 0;
                                                          
                                                          	for(i = 0 ; word[i] != '\0' ; i++)
                                                          	{
                                                          		if(word[i] == ' '
                                                          			|| (word[i] >= '!' && word[i] < '0')
                                                          			|| (word[i] > '9' && word[i] < 'A')
                                                          			|| (word[i] > 'Z' && word[i] < '_')
                                                          			|| word[i] == '`')
                                                          			return 0;
                                                          	}
                                                          
                                                          	return 1;
                                                          }
                                                          
                                                          int main() {
                                                          	char *words[] = {"a",
                                                          						  "toto42",
                                                          						  "toto_42",
                                                          						  "_toto",
                                                          						  "HelloWorld",
                                                          						  "Hello World",
                                                          						  "_42toto_",
                                                          						  "goto_toto",
                                                          						  "42_toto",
                                                          						  "__toto",
                                                          						  "to-to",
                                                          						  "_Toto",
                                                          						  "break",
                                                          						  "+toto",
                                                          						  " ",
                                                          						  NULL
                                                          						 };
                                                          	int i;
                                                          	for(i = 0 ; i < 16 ; i++) {
                                                          		if(zIdentificator(words[i]))
                                                          			printf("%s \t [valide]\n", words[i]);
                                                          		else if(words[i] != NULL)
                                                          			printf("%s \t [invalide]\n", words[i]);
                                                          		else
                                                          			puts("Pointeur NULL");
                                                          	}
                                                          	return 0;
                                                          }
                                                          


                                                          Hum... aucun commentaire à ajouter :) Ca se lite assez facilement je pense, par contre c'est peut-être un peu naïfe comme procédé non ?

                                                          Edit: un oubli.
                                                          Edit2: tout symbole qui n'a rien à faire là.
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                            13 juin 2010 à 16:43:28

                                                            Citation : GurneyH

                                                            Juste, tu es dans le même cas que Pouet, si on passe NULL -> crash...
                                                            M'enfin c'est le cas de pas mal de fonctions de la libc(toutes?).


                                                            A part free, je n'en vois pas non plus qui teste NULL.
                                                            Il faut dire que ce test est plus une perte de temps qu'autre chose... En effet, parmi tous les cas possibles d'adresse invalide (adresse de mémoire non allouée, désallouée, allouée pour autre chose...), NULL n'est qu'un cas.
                                                            • Partager sur Facebook
                                                            • Partager sur Twitter

                                                            zIdentificator

                                                            × 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