Partage
  • Partager sur Facebook
  • Partager sur Twitter

la fonction "strlen"

    11 octobre 2021 à 14:52:04

    Bonjour à tous!

    Je viens de commencer le cours sur les chaines de caracteres et j'essaie de programmer une fonction qui compte le nombre de caractere de la chaîne.

    J'ai proposé ceci:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main()
    {
        char mot[]="bonbon";
        
        printf("Le mot %s compte %d caracteres", mot, longueurChaine(mot));
    
        return 0;
    }
    
    int longueurChaine(const char mot[])
        {
            char caractereActuel = 0;
            int nombreDeCaractere = 0;
    
            while(caractereActuel != '\0')
               {
                   caractereActuel = mot[nombreDeCaractere];
                   nombreDeCaractere++;
               }
            return nombreDeCaractere;
    
    
        }

    Cependant, mon programme ne fonctionne pas et m'affiche " Le mot bonbon compte 0 caracteres"

    Est-ce que qqn peut m'expliquer s'il vous plaît ?

    Merci d'avance

    • Partager sur Facebook
    • Partager sur Twitter
      11 octobre 2021 à 15:05:38

      Ta boucle while(caractereActuel != '\0' n'est jamais exécutée, car caractereActuel vaut 0 à l'entrée de la boucle et sa valeur n'est jamais changée.
      • Partager sur Facebook
      • Partager sur Twitter
        11 octobre 2021 à 15:23:54

        effectivement en mettant caractereActuel à 1, j'ai un bon retour. Merci à toi!

        Du coup ça veut dire que '\0'c'est la même chose que ?

        • Partager sur Facebook
        • Partager sur Twitter
          11 octobre 2021 à 15:32:32

          Cela correspond à la même valeur numérique : un entier qui vaut 0.

          Lorsqu'on l'exprime sous la forme '\0' on le fait sous une forme suggérant qu'il s'agit du char terminateur de chaîne.

          C'est un peu maladroit de mettre caractereActuel à 1, car il est faux de dire que ta chaîne comprend ce caractère.

          En fait, dans ton code, tu n'as pas vraiment besoin d'une variable caractereActuel et tu peux directement mettre un test avec mot[nombreDeCaractere] dans ta condition while.

          Edit :

          renseigne toi aussi sur le type size_t, qui est plus approprié en C que le type int pour stocker la taille d'une chaîne. C'est, de fait, le type retourné par strlen() :

          https://en.cppreference.com/w/c/types/size_t

          https://www.cplusplus.com/reference/cstring/strlen/

          -
          Edité par Dlks 11 octobre 2021 à 16:23:02

          • Partager sur Facebook
          • Partager sur Twitter
            11 octobre 2021 à 16:27:38

            Il faut maintenant que tu apprennes à déboguer tout seul.

            Ici, on va se demander si 'nombreDeCaractere' est correctement incrémenté. On peut par exemple l'afficher à l'intérieur de la boucle. Si je l'avais fait, je n'aurais obtenu aucun affichage, preuve qu'il ne va jamais dans la boucle.

            Ensuite on se demande pourquoi il ne va pas dans la boucle. Pour aller dans la boucle, il y a une condition. On peut afficher la variable de la condition ('caractereActuel'). Là encore il n'affichera rien, ce qui devrait nous mettre la puce à l'oreille.

            (Oui, on peut trouver l'erreur juste en regardant le listing, parce que c'est un petit exercice simple. Mais en général ce n'est pas un regardant un listing qu'on trouve les bugs, ce serait trop beau.)

            -
            Edité par robun 11 octobre 2021 à 16:27:50

            • Partager sur Facebook
            • Partager sur Twitter
              12 octobre 2021 à 1:32:42

              Une solution consiste à utiliser une boucle do while pour rentrer au moins une fois dans la boucle
              • Partager sur Facebook
              • Partager sur Twitter
                12 octobre 2021 à 1:45:38

                Il y a plusieurs solutions.

                La plus solide et standard utilise une variable de type size_t comme indice pour parcourir la chaîne. Et à la fin, on retourne l'indice.
                Et quand on débute, le type int au lieu de size_t est très bien.

                Une solution bien différente consiste à utiliser un second pointeur pour parcourir la chaîne, et retourner la différence entre les pointeurs de fin et début de chaîne.

                PS: Utiliser un do while causera probablement un bug.

                -
                Edité par Marc Mongenet 12 octobre 2021 à 1:46:19

                • Partager sur Facebook
                • Partager sur Twitter
                  12 octobre 2021 à 2:50:16

                  Quelque chose du fgenre?
                  size_t my_strlen(char *str) {
                      char *tmp = str;
                      while(*tmp) tmp++;
                      return tmp - str;
                  }
                  • Partager sur Facebook
                  • Partager sur Twitter

                  Le Tout est souvent plus grand que la somme de ses parties.

                    12 octobre 2021 à 10:04:31

                    int longueurChaine(const char mot[])
                    {
                        int nombreDeCaractere = 0;
                    
                        while(1)
                        {
                            if(mot[nombreDeCaractere]) nombreDeCaractere++;
                            else return nombreDeCaractere;
                        }
                    }
                    • Partager sur Facebook
                    • Partager sur Twitter
                      12 octobre 2021 à 11:12:25

                      Le problème du « do while », c'est qu'on doit faire le test dans la boucle, c'est plus compliqué :

                      do
                      {
                          caractereActuel = mot[nombreDeCaractere];
                          if (caractereActuel != '\0') nombreDeCaractere++;  // ou if (caractereActuel) tout court
                      } while(caractereActuel != '\0');
                      return nombreDeCaractere;

                      Je trouve que le plus simple est la solution de Zero.c (mais j'aurais mis « while (true) »). Je ne cache pas que j'aime bien les « while (true) » (avec un break ou un return dedans), je trouve que c'est très lisible.

                      -
                      Edité par robun 12 octobre 2021 à 11:12:41

                      • Partager sur Facebook
                      • Partager sur Twitter
                        12 octobre 2021 à 14:15:51

                        Salut,

                        Puisque chacun y va de son exemple, voici le mien sur la base de ma suggestion précédente :-)

                        size_t my_strlen(const char *str) {
                            size_t len = 0;
                            while (str[len])
                                len++;
                            return len;
                        }

                        La boucle s'arrête lorsque l'on arrive sur le terminateur '\0',puisque 0, en C, signifie "faux" :-)


                        • Partager sur Facebook
                        • Partager sur Twitter
                          12 octobre 2021 à 14:25:24

                          Bonjour,

                          Pour la culture, le fun, le challenge d'essayer de comprendre tout seul ... ci-dessous une implémentation de strlen() utilisée par gnu/linux
                          https://sourceware.org/git/?p=glibc.git;a=blob;f=string/strlen.c;hb=HEAD

                          • Partager sur Facebook
                          • Partager sur Twitter
                            12 octobre 2021 à 14:50:50

                            Et peut-être aussi
                            size_t mstrlen(char str[]) {
                            	char *p=str;
                            	while(*p++);
                            	return(p-str-1);
                            }
                            
                            

                            -
                            Edité par edgarjacobs 12 octobre 2021 à 14:52:20

                            • Partager sur Facebook
                            • Partager sur Twitter

                            On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

                              12 octobre 2021 à 15:04:54

                              @edgarjacobs:
                              Ta solution ressemble à la mienne, je n'ai pas voulu faire l'incrémentation dans le while même si c'est plus "joli".
                              Pas tout le monde qui comprendra pourquoi il faut soustraire 1 à la fin.
                              • Partager sur Facebook
                              • Partager sur Twitter

                              Le Tout est souvent plus grand que la somme de ses parties.

                                12 octobre 2021 à 21:41:37

                                Merci Gam' pour ce lien intéressant ! Je n'ai pas tout compris, mais ça montre l'écart entre un exercice et une fonction « dans la vrai vie ».
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  13 octobre 2021 à 16:10:15

                                  Il faudrait démontrer que la fonction strlen "astucieuse" constitue un gain de temps effectif sur un ensemble de chaînes représentatif de l'usage qui en est fait (distribution des tailles de chaînes ?)

                                  Qui plus est, quand on en est à ce degré de recherche d'optimisation, fortement lié à une implémentation d'une architecture particulière, on écrit le truc en assembleur, pour aller chercher directement les instructions spécifiques qui vont bien, plutôt que d'espérer que le compilateur (particulier lui aussi) va deviner ce qu'on traficote et pas se prendre les pieds dans le tapis en optimisant.

                                  (Ici: traiter les octets par paquets alignés de 4 ou de 8, avec une bidouille pour voir si un paquet contient un octet nul ou pas)

                                  Dans la vraie vie, il vaut mieux s'abstenir de faire ce genre de code ::-)

                                  -
                                  Edité par michelbillaud 13 octobre 2021 à 17:38:14

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    13 octobre 2021 à 18:22:59

                                    Merci Gam' également.

                                    Cela m'a poussé à faire un peu de recherches :-)

                                    Le code du projet GNU pour la glibc parait inspiré du travail de Henry S. Warren dans son livre Hacker's Delight. Il est crédité dans la version FreeBSD de cette implémentation : https://cgit.freebsd.org/src/tree/lib/libc/string/strlen.c

                                    @michelbillaud: Dans cette version d'Apple (qui base son code sur FreeBSD) il y a un commentaire sur les mesures de performances qui serait x5 sur le matériel indiqué (un Intel T7300 qui a été produit en 2007) : https://github.com/apple/darwin-libplatform/blob/main/src/string/generic/strlen.c par rapport à une version triviale dès lors que la chaîne a une taille supérieure à un word.

                                    C'est un type d'optimisation utilisé par d'autres systèmes d'exploitation.

                                    Voilà ce que Henry S. Warren dit : https://books.google.de/books?id=VicPJYM0I5QC&lpg=PP1&hl=fr&pg=PA117#v=onepage

                                    Ce qui est présenté dans le strlen.c posté précédemment par Gam' n'est pas ce qui tourne sur nos machines Linux habituelles, sauf architectures exotiques. Par exemple pour x86_64 c'est une version en assembleur : https://github.com/lattera/glibc/blob/master/sysdeps/x86_64/strlen.S

                                    Cela utilise des instructions SIMD (Single instruction, multiple data) comme pcmpeqd : https://mudongliang.github.io/x86/html/file_module_x86_id_234.html

                                    Ils n'utilisent le code en .c que s'il n'existe pas une version assembleur pour une architecture donnée.

                                    @robun : je suis assez d'accord avec Michel, ce n'est pas exactement le type d'efforts que l'on fait "dans la vrai vie" par rapport à un code résultant d'un exercice. Il faut aussi comprendre que tous ces efforts pour optimiser une fonction qui est, a priori, simple, se justifient pour deux raisons :

                                    • parce qu'on est dans le contexte d'une fonction comme strlen() dont l'algorithme trivial est de complexité O(n) car le C ne connaît pas de réel type string (avec un vrai type string, la longueur de la chaîne pourrait être stockée)
                                    • mais surtout parce qu'on est dans le contexte de la libc et qu'on réalise, par définition, une implémentation de la libc pour une machine donnée, et que ce n'est pas grave si on aboutit à du code non portable

                                    En dehors de contextes particuliers, on devrait laisser le compilateur optimiser les choses.

                                    Edit : coquilles

                                    -
                                    Edité par Dlks 13 octobre 2021 à 18:32:25

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      13 octobre 2021 à 18:23:28

                                      J'osais espérer que ce n'était que pour des raisons pédagogiques ou expérimentales.
                                      La fonction strlen() fournie par la bibliothèque standard de C est préférable et bien optimisée.
                                      • Partager sur Facebook
                                      • Partager sur Twitter

                                      Le Tout est souvent plus grand que la somme de ses parties.

                                      la fonction "strlen"

                                      × 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