Partage
  • Partager sur Facebook
  • Partager sur Twitter

Exercices Chaines: strlen et strcmp

Pas d'erreur de compilatio, mais le programme fonctionne pas

Sujet résolu
    1 janvier 2009 à 21:56:03

    Salut,

    Je débute en programmation et arrivé aux exercices sur les chaines de caractères je suis bloqué aux fonctions strlen et strcmp(le code que je copie ici contient aussi les fonctions strcpy et strcat qui fonctionnent bien cependant.) Elles ne donnent aucune erreur à la compilation, cependant, strlen me donne toujours comme réponse 39 caractères et strcmp me donne toujours comme réponse que les chaines sont différentes.



    #include <stdio.h>
    #include <stdlib.h>
    #include "prototypes.h"
    
    int main(int argc, char *argv[])
    
    {
        char mot[40];
        char copie[40];
        char vrai [6]={" vrai"};
        char motdeux[40];
        long longueurMot=0;
    
        printf("Ecrivez un mot \n");
        scanf("%s", mot);
        printf("Voici quelques faits sur ce mot\n");
        longueurMot= LongueurChaine(mot);
        printf("Ce mot a %ld caracteres\n", longueurMot);
        CopieChaine(copie,mot);
        printf("J'ajoute le mot vrai a la chaine\n");
        ConcatenerChaine(mot,vrai);
        printf("Retapez le meme mot ou un autre: les deux mots entres seront compares\n");
        scanf("%s", motdeux);
        CompareChaine(mot, motdeux);
        return 0;
    }
    
    long LongueurChaine(const char* mot)
    {
    
         long longueurMot=0;
         long i;
         for(i=0; i<40; i++)
    
     {
         if (mot[i]=='\0')
         longueurMot=&mot[i]-mot;
             
         
     }
    
     return longueurMot;
    }
    
    void CopieChaine( char* copie, char* mot)
    {
    copie=mot;
    printf("Le mot est %s\n",copie);
    }
    
    void ConcatenerChaine (char* mot,char* vrai)
    {
    long longueurMot=0;
    long i;
    
    longueurMot= LongueurChaine(mot);
    
    for(i=0;i<longueurMot+5;i++)
    {
        mot[i+longueurMot] = vrai[i];
    }
    printf("%s\n", mot);
    }
    
    void CompareChaine(  char* mot,  char* motdeux)
    {
      long i;
      long coefficient=0;
      
      
    
      for(i=0;i<80;i++)
      {
          if( mot[i]!=motdeux[i])
          coefficient++;
    
      }
      if (coefficient==0)
      printf("Les mots sont identiques");
    
      else
      printf("Les mots sont differents");
    
    }
    


    Comme il ne s'agit pas d'erreurs de compilation je ne trouve pas nécessaire d'inclure le .h, je l'ai vérifier et les erreurs ne s'y situent pas.

    Pour le strcmp (CompareChaine) pour me simplifier j'ai programmé la fonction pour qu'elle dise seulement si les chaines sont identiques ou non sans leur attribuer un nombre précis, quand je comprendrai mon erreur je m'y mettrai... Il est scependant toujours écrit dans le printf que les chaines sont différentes même si j'écris exactement les mêmes choses dans les deux scanf

    Pour le strlen (LongueurChaine) j'avais oublié que la fonction avait déja été corrigée dans le tutoriel,c'est pourquoi le principe de la fonction est un peu différent que l'exemple donné dans le tutoriel et que je ne puis m'y fier pour la corriger. La fonction renvoie toujours 39 caractères et je ne comprends vraiment pas pourquoi ce chiffre et pas un autre...

    Merci beaucoup pour votre aide!
    • Partager sur Facebook
    • Partager sur Twitter
      1 janvier 2009 à 23:07:05

      En fait, pour longueurChaine, tu fait une boucle qui tourne tant que i<40... c'est donc normal que le résultat soit de 39 (0 à 39 = 40 chiffres)

      Tu devrais plutot utiliser quelque chose du genre :
      /*
      Calcul le nombre de lettres du mot mystère
      */
      long LongueurChaine (const char* mot)
      {
          long i = 0;
      
          //Addictionne le nombre de lettre (i) jusqu'à la fin (\0).
          do
          {
              i++;
          } while (mot[i] != '\0');
      
          return i;
      }
      


      ou bien avec for :
      /*
      Calcul le nombre de lettres du mot mystère
      */
      long  LongueurChaine (const char* mot)
      {
          long i = 0;
      
          //Addictionne le nombre de lettre (i) jusqu'à la fin (\0)
          for (i=0; mot[i] != '\0'; i++);
      
          return i;
      }
      


      [EDIT]

      Aussi, pour copie chaine, tu ne peux pas y aller de cette façon, tu doit copier lettre par lettre le mot dans l'autre chaine.

      Je t'envoie au tuto sur les chaines de charactère, va voir comment fonctionne strcpy. http://www.siteduzero.com/tutoriel-3-1 [...] tml#ss_part_3
      • Partager sur Facebook
      • Partager sur Twitter
      Character Artist @ Framestore Montreal. http://felixcharacters.com
      Anonyme
        1 janvier 2009 à 23:40:59

        Attention, ta version while est buguée, la chiane "" commence par '\0', sauf que tu commences par lire le charactère d'après, tu nous fais un beau dépassement mémoire
        size_t myStrlen( const char* str)
        {
          size_t result = 0;
          assert( str && "must be !=NULL");
          while ( str[result] != '\0' ) { ++result; }
          return result;
        }
        


        • Partager sur Facebook
        • Partager sur Twitter
          2 janvier 2009 à 0:37:34

          Le compilateur me dit que la ligne 43 est fausse.
          Tu devrais aussi rajouter des commentaires. ;)

          Bonne chance!
          • Partager sur Facebook
          • Partager sur Twitter
            2 janvier 2009 à 3:08:36

            Grace à ta réponse FélixEnFeu,j 'ai compris mon erreur pour LongueurChaine. Ainsi,si j'ai bien compris, si je crée un tableau de 40 adresses et que j'y écrit le mot salut, toutes les adresses inutilisées seront remplacés par '\0'. La chaine continuait donc jusqua 39 puisque le 39e symbole était un '\0'. Pour ne pas trop modifier mon code, j'ai tout simplement ajouté i=40 dans le if, ainsi, dès que la condition est vraie, la boucle s'arrête, et ca marche! Cependant, je dois avouer que ton code est encore plus simple que le mien :)

            Pour le strcpy, je trouvais aussi que cela semblait un peu trop facile, mais elle fait bien une copie dans un autre tableau de char, je ne vois pas ou est le problème...Et puis j'ai réessayer et non le compilateur ne me donne aucune erreur pour la ligne 43...

            Cependant, je suis encore dans le néant pour ce qui est de CompareChaine.


            Merci pour l'aide.
            • Partager sur Facebook
            • Partager sur Twitter
              2 janvier 2009 à 5:05:20

              Tu as presque compris pour le tableau de caractère, mais pas complètement. Lorsque tu créé un tableau de type char de 40 adresses, ces 40 adresse seront "réservées" pour cette variable. Lorsque tu entre le mot "Chien" par exemple, 6 de ces adresses seront utilisée : Soit 1 pour chaque lettre, et 1 pour le \0. Toutes les autres adresses restent inutilisée, mais sont tout de même réservées pour la variable.

              Le \0 indique la fin de la chaine, pour le programme, il signifie "Stop, y'a plus rien après ici"

              Lorsque tu fait la boucle de ma fonction, le programmes lira jusqu'à ce qu'il atteigne \0 (Tout en ajoutant +1 au nombre de lettre). Voilà pourquoi ma fonction fonctionne : Ce qu'il y a ensuite ne l'intéresse pas, car tu veux la longueur du mot, et non la longueur du tableau de char[].
              • Partager sur Facebook
              • Partager sur Twitter
              Character Artist @ Framestore Montreal. http://felixcharacters.com
                2 janvier 2009 à 10:24:10

                Citation : someone2

                Grace à ta réponse FélixEnFeu,j 'ai compris mon erreur pour LongueurChaine. Ainsi,si j'ai bien compris, si je crée un tableau de 40 adresses

                On dit 'cases' ou 'éléments'.

                Citation : Pas de titre

                et que j'y écrit le mot salut, toutes les adresses cases inutilisées seront remplacés par '\0'


                Ca dépend à quel moment tu 'écris'... Si c'est au moment de la définition du tableau de char, oui :
                char s[40] = "salut";
                

                s contient : "salut\0\0\0\0\0\0\0\0\0<...>\0" (<...> simule la répétition, OK ?)
                mais maintenant, si j'écris
                strcpy(s, "hi");
                

                dans s, il y a : "hi\0ut\0\0\0\0\0\0\0\0\0<...>\0"

                Le principe avec toutes les fonctions 'chaine' est de s'arrêter au premier '\0' (ou 0) rencontré.

                Citation : Pas de titre

                Pour le strcpy, je trouvais aussi que cela semblait un peu trop facile, mais elle fait bien une copie dans un autre tableau de char, je ne vois pas ou est le problème...Et puis j'ai réessayer et non le compilateur ne me donne aucune erreur pour la ligne 43...

                Cependant, je suis encore dans le néant pour ce qui est de CompareChaine.


                Quelque soit la fonction à réaliser tout deviens plus simple si on sépare la conception du codage. avant le codage, il doit y avoir une phase de réflexion qui consiste à traduire l'énoncé (la définition de la fonc) en algorithme, c'est à dire une suite de phrases en français[1] simple et clair.

                Par exemple pour strlen(), la définition est (de mémoire)

                <<écrire une fonction qui permet de mesurer la longueur d'une chaine de caractère. Elle prend en paramètre l'adresse du premier élément de la chaine à mesurer, et elle retourne le nombre de caractères sans compter le 0 final.>>

                A partir de là, on peut déjà définir un prototype :

                nom : str_len(), car on a pas le droit d'utiliser un nom existant dans la bibliothèque du C. D'autre part, les mots commençant par str suivis d'une minuscule sont réservés (à l'évolution du langage).

                "Elle prend en paramètre l'adresse du premier élément de la chaine à mesurer"

                Une chaine est le contenu d'un tableau de char. L'adresse d'un char se met donc dans un pointeur sur char qui est fait pour : 'char *'. de plus, cette fonction ne fait que lire la chaine sans jamais la modifier. on ajoute donc un accès en lecture seule : 'char const *'
                strlen (char const *)
                


                "elle retourne le nombre de caractères"

                Elle doit donc retourner la longueur de la chaine, c'est à dire le nombre de char qui la compose. Or il existe un type en C qui est conçu pour contenir la plus grande taille possible d'un objet (ou variable), c'est size_t. C'est un type entier non-signé. Il est donc certain que quelque soit la longueur de la chaine, elle soit contenue dans un tableau ne pouvant excéder la valeur maximale d'un size_t (soit (size_t) -1). C'est donc ce type qu'il faut utiliser pour retourner la longueur :
                size_t str_len (char const *s)
                

                Ensuite, on doit réfléchir à l'algorithme qui permet de réaliser le travail demandé.

                Par exemple

                "parcourir la chaine en comptant les caractères jusqu'à trouver le 0 final."

                ce qui manque un peu de précision. C'est là qu'on commence à utiliser une formulation plus précise, plus 'informatique'. C'est le travail d'analyse. On va commencer par séparer les données des actions :

                "parcourir la chaine" : action mettant en œuvre une donnée entrante : la chaine et donc ses éléments
                "en comptant les caractères" : action mettant en œuvre un 'compteur' (donnée)
                "jusqu'à trouver le 0 final" : action de répétition avec une condition de sortie

                Le termes "parcourir ... jusqu'à" expriment à mi-mots une notion importante : la boucle de répétition.

                On peut donc affiner la description comme suit :
                à partir du premier élément
                répéter
                 lire l'élément courant
                 si ce n'est pas 0
                  incrémenter le compteur
                 fin si
                jusqu'à ce que l'élément lu soit 0
                retourner la valeur du compteur

                Comme on a affaire à un compteur, ne pas oublier de l'initialiser à 0 avant usage. L'algorithme complet devient donc :
                initialiser le compteur a 0
                à partir du premier élément
                répéter
                 lire l'élément courant
                 si ce n'est pas 0
                  incrémenter le compteur
                 fin si
                jusqu'à ce que l'élément lu soit 0
                retourner la valeur du compteur

                Je pense que tout y est.

                On peut alors traduire cet algorithme (dit 'textuel') en algorithme 'formel' à l'aide d'un 'pseudo-langage', sorte de langage universel simplifié qui permet de formaliser certains aspect passés sous silence avec l'algo textuel :
                BEGIN
                ; initialiser le compteur a 0
                 compteur := 0
                
                ; à partir du premier élément
                 i := 0
                
                ; répéter
                 REPEAT
                ;  lire l'élément courant
                  c := chaine[i]
                
                ;  si ce n'est pas 0
                  IF c <> 0
                
                ;   incrémenter le compteur
                   INC compteur
                
                ;  fin si
                  END IF
                
                ; jusqu'à ce que l'élément lu soit 0
                 UNTIL c = 0
                
                ; retourner la valeur du compteur
                 RETURN compteur
                END

                ou, sans les commentaires :
                BEGIN
                 compteur := 0
                 i := 0
                 REPEAT
                  c := chaine[i]
                  IF c <> 0
                   INC compteur
                  END IF
                 UNTIL c = 0
                 RETURN compteur
                END

                A partir de là, le travail d'analyse est terminé. On peut passer au codage en C :

                size_t str_len (char const *s)
                /* BEGIN */
                {
                
                /*  compteur := 0 */
                   size_t compteur = 0;
                
                /*  i := 0 */
                   size_t i = 0;
                
                   int c;
                
                /*  REPEAT */
                   do
                   {
                /*   c := chaine[i] */
                      c = s[i];
                
                /*   IF c <> 0 */
                      if (c != 0)
                      {
                
                /*    INC compteur */
                         compteur++;
                
                /*   END IF */
                      }
                
                /*  UNTIL c = 0 */
                    }
                    while (c != 0);
                
                /*  RETURN compteur */
                   return compteur;
                
                /* END */
                }
                

                Ce qui donne sans les commentaires :
                size_t str_len (char const *s)
                {
                   size_t compteur = 0;
                   size_t i = 0;
                
                   int c;
                
                   do
                   {
                      c = s[i];
                      if (c != 0)
                      {
                         compteur++;
                      }
                    }
                    while (c != 0);
                
                   return compteur;
                }
                

                Il ne reste plus qu'à le tester.
                test (NULL, 0);
                   test ("", 0);
                   test ("a", 1);
                   test ("ab", 2);
                   test ("ab\0c", 2);


                Le test révèle 2 défauts :

                - crash si on passe NULL. ce n'est pas exigé par la norme qui définit strlen(), donc on peut ignorer ce test. Sinon, il suffit d'ajouter une protection et de retourner 0.

                - plus grave : une boucle infinie !

                C'est un problème d'analyse. La notion de "parcourir la chaine" n'a pas été assez bien analysée, et j'ai fini par oublier qu'il fallait incrémenter aussi l'index.

                ceci fonctionne et passe les tests :

                #include <stddef.h>
                
                size_t str_len (char const *s)
                {
                   size_t compteur = 0;
                   if (s != NULL)
                   {
                      size_t i = 0;
                
                      int c;
                
                      do
                      {
                         c = s[i];
                         i++;
                         if (c != 0)
                         {
                            compteur++;
                         }
                      }
                      while (c != 0);
                   }
                   return compteur;
                }
                
                #ifdef TEST
                #include <stdio.h>
                #include <string.h>
                #include <stdlib.h>
                #include <assert.h>
                
                #define CHECK(exp, file, line)\
                do\
                {\
                   if (!(exp))\
                   {\
                      printf ("'%s' was not asserted at %s:%d\n", #exp, file, line);\
                      exit(EXIT_FAILURE);\
                   }\
                }\
                while (0)
                
                static void test_ (char const *in_s, size_t out_n, char const *file, int line)
                {
                   size_t n = str_len (in_s);
                
                   CHECK (n == out_n, file, line);
                }
                
                #define test(a, b)\
                 test_ (a, b, __FILE__, __LINE__)
                
                int main (void)
                {
                   test (NULL, 0);
                   test ("", 0);
                   test ("a", 1);
                   test ("ab", 2);
                   test ("ab\0c", 2);
                
                   puts ("P A S S E D");
                
                   return 0;
                }
                #endif
                

                Le code de test est un peu avancé...

                Maintenant qu'on a un algorithme qui fonctionne, on peut se poser la question de savoir si on doit l'optimiser et comment. Le test unitaire étant automatique, toute régression dans le comportement se traduira par une erreur à l'exécution.

                Comme on peut le constater, le code ne tombe pas du ciel. C'est le fruit d'une pensée organisée. Il n'y a rien de difficile. Il faut simplement faire les choses dans l'ordre. On voit qu'ici, le travail d'analyse a pris 80% du temps... Le codage, c'est rien. Ces 80% risquent néanmoins de tomber à 70% voire moins, si on met en œuvre une procédure de test unitaire...

                En gros, dans l'industrie, on estime la charge à

                10-20% : définition
                50-70% : analyse
                10-20% : codage
                10-30% : tests unitaires
                soit un total de 80-140%

                C'est ce genre de démarche qu'il faut appliquer pour la réalisation de n'importe quelle fonction... A toi de jouer.

                ---------------------
                [1] ou en sa langue d'expression
                • Partager sur Facebook
                • Partager sur Twitter
                Music only !
                  5 janvier 2009 à 2:25:25

                  ok merci beaucoup je vais essayer de résoudre mes problèmes avc cette méthode je vais marquer ce problème comme résolu
                  • Partager sur Facebook
                  • Partager sur Twitter
                    5 janvier 2009 à 20:43:06

                    Bon, j'ai de nouveau essayer le tout, les trois premières fonctionnent à la perfection, mais encore strcmp (CompareChaine) marche pas, et je vois vraiment pas pourquoi. Voila la fonction beaucoup modifiée depuis la dernière fois, et c'est encore le meme problème.

                    void CompareChaine(  char* mot,  char* motdeux)
                    {
                      long i;
                      long condition=0;
                      long coefficient=0;
                    
                      long longueurMot=0;
                      long longueurMotdeux=0;
                      long longueur=0;
                    
                      longueurMot=LongueurChaine(mot); //On calcule la longueur de chaque mot par une fonction maison.
                      longueurMotdeux=LongueurChaine(motdeux);
                    
                      if(longueurMot>longueurMotdeux)
                      longueur=longueurMot;
                                                       //On calcule ici ou doit s'arrêter la boucle (À la fin du plus long mot)
                      else
                      longueur=longueurMotdeux;
                    
                    
                    
                      for(i=0;i<=longueur;i++)
                      {
                        if(mot[i]<motdeux[i])
                       {                        /*On modifie condition des que deux lettres
                                                sont differentes.
                                                On calcule coefficient à part,
                                                si jamais il advenait qu'il soit égal à zéro*/
                        condition++;
                        coefficient++;
                       }
                        else if (mot[i]>motdeux[i])
                       {
                        condition++;
                        coefficient--;
                       }
                    
                      }
                      if(condition)        /*Si coefficient a ete modifie, la condition sera vraie et il sera affiche que les chaines sont differentes*/
                      printf("Les chaines sont differentes\n Elles ont %ld de coefficient de difference.", coefficient);
                    
                      else
                      printf("Les chaines sont identiques");
                    
                    }
                    


                    Ce code indique que les chaines me,me identiques sont différentes et le coefficient de différnce est différent pour chaque mot ce qui est tres étrange.
                    Merci encore
                    • Partager sur Facebook
                    • Partager sur Twitter
                      11 janvier 2009 à 4:20:16

                      Youppi, après une semaine a me casser la tete sur cette foutue fonction, j'ai finalement trouvé mon erreur, et elle était meme pas dans la fonction!

                      En effet, j'avais oublié que les variables étaient détruites après les fonctions, mais pas les pointeurs!

                      Ayant modifié la chaine entre par l'utilisateur par la fonction de la concaténation, il était normal que la fonction semblait tout a fait déréglé alors qu'elle était correctement codée.

                      J'ai donc passée une semaine a chercher un probleme ou il n'y en avait pas. Je peux finalement mettre ce problème comme résolu et passer au prochain exercice!

                      Merci encore pour l'aide
                      • Partager sur Facebook
                      • Partager sur Twitter
                        11 janvier 2009 à 11:48:54

                        Citation : someone2

                        Bon, j'ai de nouveau essayer le tout, les trois premières fonctionnent à la perfection, mais encore strcmp (CompareChaine) marche pas, et je vois vraiment pas pourquoi. Voila la fonction beaucoup modifiée depuis la dernière fois, et c'est encore le meme problème.


                        Ce code est horriblement compliqué. Il faut toujours chercher les solutions les plus simples. En général, ce sont celles qui sont le plus proche de la définition du problème. C'est pour ça qu'il est primordial de ne pas se précipiter sur le codage et de prendre du temps, au préalable, de comprendre très précisément ce qu'il faut réaliser.

                        - Quel est l'interface de la fonction strcmp() ?
                        - Quel est son comportement attendu ?

                        Une fois que tu as répondu très précisément mais de la manière la plus simple possible, à ces deux questions, tu a fais 75% du travail de programmation.

                        J'attends donc la réponse à ces 2 questions.
                        • Partager sur Facebook
                        • Partager sur Twitter
                        Music only !
                          15 mai 2015 à 15:44:00

                          salut le code que j'essais de mettre en place dois supprimer les 5 derniers caracteres de la chaine si le nombres de caractéres est superieur ou egale à 25 .de meme que la taille minimale de la chaine est de 20.

                          mais a chaque fois que je compile , si je saisis plus de 20 caracteres le compilateur cesse de fonctionner.

                          MERCI D'AVANCE

                          #include <stdio.h>

                          #include <stdlib.h>

                          int main()

                          {

                              char chaine[20];

                              int i;

                          do

                              printf("Donnez une chaine:\n");

                              gets(chaine);

                                    if(chaine[i]>=25)

                                       chaine[20]='\0';

                              printf("la nouvelle chaine est %s" , chaine);

                          while (chaine[i]<20);

                              return 0;

                          • Partager sur Facebook
                          • Partager sur Twitter
                            15 mai 2015 à 15:49:48

                            Salut,

                            Crée un nouveau sujet et utilise les balises pour mettre ton code. Personne va répondre sur un vieux sujet comme ça...

                            • Partager sur Facebook
                            • Partager sur Twitter
                              22 juin 2017 à 3:28:06

                              salut esk kkun peut m'aider svp? ecrire un pgm qui demande a l'utilisateur de taper 10 entiers strictements positifs et qui affiche leur moyenne. lorsqu'on tape une valeur negative, le pgm affiche ERREUR et demande de retaper une valeur. lorsqu'on tape 0, cela signifie que le dernier entier a ete tape. on affiche alors la moyenne. si le nombre d'entiers est egal a o, on affiche pas de moyenne
                              • Partager sur Facebook
                              • Partager sur Twitter
                                22 juin 2017 à 11:44:23

                                Thanatos1 a écrit:

                                Salut,

                                Crée un nouveau sujet et utilise les balises pour mettre ton code. Personne va répondre sur un vieux sujet comme ça...



                                • Partager sur Facebook
                                • Partager sur Twitter

                                Exercices Chaines: strlen et strcmp

                                × 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