IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

extraction d'une sous-chaine dans une chaine


Sujet :

C

  1. #1
    Rédacteur/Modérateur

    Avatar de User
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    8 348
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 8 348
    Points : 19 596
    Points
    19 596
    Billets dans le blog
    65
    Par défaut extraction d'une sous-chaine dans une chaine
    Bonsoir,

    J'utilise la fonction str_sub prise dans le tuto de ce site. Cette fonction permet d'extraire une sous-chaîne de s comprise entre l'indice start et end.

    voici mon code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    #include <stdio.h>
    #include <stdlib.h>
     
    char *str_sub (const char *, unsigned int, unsigned int);
     
     
    int main()
    {
    char * ch1= "bonjour monsieur" ;
     
    printf(str_sub (ch1,3,6)); 
     
    return 0;
     
    }
     
    char *str_sub (const char *s, unsigned int start, unsigned int end)
    {
       char *new_s = NULL;
     
       if (s != NULL && start < end)
       {
    /* (1)*/
          new_s = malloc (sizeof (*new_s) * (end - start + 2));
          if (new_s != NULL)
          {
             int i;
     
    /* (2) */
             for (i = start; i <= end; i++)
             {
    /* (3) */
                new_s[i-start] = s[i];
             }
          }
          else
          {
             fprintf (stderr, "Memoire insuffisante\n");
             exit (EXIT_FAILURE);
          }
       }
       return new_s;
    }
    Ca devrait m'afficher "jour"

    or ca m'affiche "jour=&o.."


    Quelqu'un pour m'aider ???

    User

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 379
    Points : 41 573
    Points
    41 573
    Par défaut
    Il manque le caractère nul de fin de chaîne.

    De plus, ton main() contient une fuite de mémoire.

  3. #3
    Rédacteur/Modérateur

    Avatar de User
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    8 348
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 8 348
    Points : 19 596
    Points
    19 596
    Billets dans le blog
    65
    Par défaut
    tu veux dire un truc du genre:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    ch2=str_sub (ch1,3,6);
     
    ch2[7]='\0';
     
    printf(ch2);
    par contre je ne vois pas ce que tu entends par fuite de mémoire dans le main ???

    Excuse moi mais je débute le c (je viens de Delphi...)

    Merci !

  4. #4
    Expert éminent sénior

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 66
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Points : 17 916
    Points
    17 916
    Billets dans le blog
    2
    Par défaut
    il veut dire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
            for (i = start; i <= end; i++)
             {
    /* (3) */
                new_s[i-start] = s[i];
             }
     
             new[end-start] = '\0' ;
    et pour la fuite, c'est que tu fais une alloc dans la routine et que tu ne liberes pas avant de sortir du main...

  5. #5
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 379
    Points : 41 573
    Points
    41 573
    Par défaut
    Tu oublies de faire un free() dans le main().

  6. #6
    Rédacteur/Modérateur

    Avatar de User
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    8 348
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 8 348
    Points : 19 596
    Points
    19 596
    Billets dans le blog
    65
    Par défaut
    Merci a tous les deux !

    souviron, tu veux dire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    new_s[end-start+1] = '\0';

    en tous ca c'est vraiment pas évident toutes ces manips quand on ne connais pas le c, surtout pour les chaines.

    Encore merci à vous deux !

  7. #7
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par User Voir le message
    J'utilise la fonction str_sub prise dans le tuto de ce site. Cette fonction permet d'extraire une sous-chaîne de s comprise entre l'indice start et end.
    <...>
    Ca devrait m'afficher "jour"

    or ca m'affiche "jour=&o.."
    Bah, oui, ce code est faux. Il manque le 0 final. En fait, il faut savoir plusieurs choses :

    1 - une chaine est une tableau ce char initialisé avec des valeurs de caractères (1-255) et terminé par un 0.

    2 - le bloc de données retourné par malloc() n'est pas initialisé. Il contient n'importe quoi.

    En conséquence, le code présenté a un comportement indéterminé, car il copie un certain nombre de caractères (la sous-chaine), mais il oublie de placer le 0 final. Si par hasard (ce qui m'est arrivé et ce qui est probablement arrivé au codeur original de cette fonction), un 0 se trouve dans le bloc alloué au bon endroit, on a l'impression que le comportement est normal, alors qu'il est juste indéterminé.

    Cet exemple parfait montre l'extrême dangerosité du comportement indéterminé car il peut apparaitre comme normal, ce qui interdit sa détection infaillible à l'exécution. Seuls une connaissance du langage et un contrôle visuel permettent de repérer ce bug.

    Il existe cependant une astuce qui peut réduire l'incertitude (au moins, pendant la phase de mise au point), c'est de remplir le bloc alloué d'une valeur 'étrange', mais définie (ici, des '?'), et d'observer le comportement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    char *str_sub (const char *s, size_t start, size_t end)
    {
       char *new_s = NULL;
     
       if (s != NULL && start < end && end)
       {
          new_s = malloc (sizeof (*new_s) * (end - start + 2));
          if (new_s != NULL)
          {
             int i;
             /* mettre le defaut en evidence */
             memset(new_s, '?', (end - start + 2));
     
             for (i = start; i <= end; i++)
             {
                new_s[i - start] = s[i];
             }
          }
       }
       return new_s;
    }
    Le résultat est édifiant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    'jour?'
     
    Press ENTER to continue.
    Il manque effectivement un 0 à la fin de la chaine.

    J'en profite pour ajouter un test supplémentaire de cohérence des paramètres (la fin ne doit pas dépasser la longueur de la chaine), et corriger le main() pour permettre la libération de la mémoire allouée. Dernier détail, une chaine littérale n'est pas modifiable, j'ajoute donc 'const' au pointeur dans le main() ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <assert.h>
     
    char *str_sub (const char *s, size_t start, size_t end)
    {
       char *new_s = NULL;
     
       /* attention aux valeurs incoherentes... */
       if (s != NULL && start < end && end <= strlen (s))
       {
          new_s = malloc (sizeof (*new_s) * (end - start + 2));
          if (new_s != NULL)
          {
             int i;
             /* mettre le defaut en evidence */
             memset(new_s, '?', (end - start + 2));
     
             for (i = start; i <= end; i++)
             {
                new_s[i - start] = s[i];
             }
             /* correction */
             new_s[i - start] = 0;
          }
       }
       return new_s;
    }
     
    int main (void)
    {
       char const *ch1 = "bonjour monsieur";
       char *sub = str_sub (ch1, 3, 6);
       if (sub != NULL)
       {
          printf ("'%s'\n", sub);
          free (sub), sub = NULL;
       }
       assert (sub == NULL);
     
       return 0;
    }
    Pose des questions si tu ne comprends pas.

    (et je vais lancer une procédure de tests unitaires sur cette fonction qui me parait quand même assez douteuse...)

    Effectivement, il y a des problèmes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    error at test #10 (str_sub(bonjour, 0, 0) = '(null)')
    error at test #22 (str_sub(bonjour, 6, 6) = '(null)')
    error at test #23 (str_sub(bonjour, 7, 7) = '(null)')
     
    Press ENTER to continue.
    Et voilà le code mis au point et validé. Attention, le paramètre 'end' désigne le caractère situé après le dernier caractère de la sous-chaine.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <assert.h>
     
    char *str_sub (const char *s, size_t start, size_t end)
    {
       char *new_s = NULL;
     
       /* attention aux valeurs incoherentes... */
       if (s != NULL && start <= end && end <= strlen (s))
       {
          size_t new_len = end - start + 1;
     
          new_s = malloc (sizeof *new_s * (new_len + 1));
          if (new_s != NULL)
          {
             size_t i;
             /* mettre le defaut en evidence */
             memset (new_s, '?', (new_len + 1));
     
             for (i = start; i < end; i++)
             {
                assert (i - start < new_len);
                new_s[i - start] = s[i];
             }
             /* correction */
             assert (i - start <= new_len);
             new_s[i - start] = 0;
          }
       }
       return new_s;
    }
     
    int main (void)
    {
       char const *ch1 = "bonjour";
     
       struct test
       {
          int num;
          struct
          {
             int start;
             int end;
          }
          in;
          struct
          {
             char const *s;
          }
          out;
       };
     
    /* *INDENT-OFF* */
       static struct test const a[] =
       {
          {10, {0,  0}, {""       }},
          {11, {0,  1}, {"b"      }},
          {12, {0,  7}, {"bonjour"}},
     
          {20, {1,  6}, {"onjou"  }},
          {21, {6,  7}, {"r"      }},
          {22, {6,  6}, {""       }},
          {23, {7,  7}, {""       }},
     
          {30, {0, -1}, {NULL}},
          {31, {-1, 0}, {NULL}},
          {32, {0,  8}, {NULL}},
          {33, {7,  8}, {NULL}},
          {34, {8,  8}, {NULL}},
          {35, {5,  4}, {NULL}},
       };
    /* *INDENT-ON* */
     
       size_t i;
       int err = 0;
       for (i = 0; i < sizeof a / sizeof *a; i++)
       {
          struct test const *p = a + i;
     
          char *sub = str_sub (ch1, p->in.start, p->in.end);
          if (sub != NULL)
          {
             if (p->out.s != NULL)
             {
                if (strcmp (sub, p->out.s) != 0)
                {
                   printf ("error at test #%d (str_sub(%s, %d, %d) = '%s')\n",
                           p->num, ch1, p->in.start, p->in.end, sub);
                   err = 1;
                }
             }
             else
             {
                printf ("error at test #%d (str_sub(%s, %d, %d) = '%s')\n",
                        p->num, ch1, p->in.start, p->in.end, sub);
                err = 1;
             }
     
             free (sub), sub = NULL;
          }
          else
          {
             if (sub != p->out.s)
             {
                printf ("error at test #%d (str_sub(%s, %d, %d) = '%s')\n",
                        p->num, ch1, p->in.start, p->in.end, sub);
                err = 1;
             }
          }
          assert (sub == NULL);
       }
     
       if (!err)
       {
          puts ("P A S S E D");
       }
       return 0;
    }
    Ça donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    P A S S E D
     
    Press ENTER to continue.

  8. #8
    Rédacteur/Modérateur

    Avatar de User
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    8 348
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 8 348
    Points : 19 596
    Points
    19 596
    Billets dans le blog
    65
    Par défaut
    OK merci,

    Je vais analyser tout cela !

  9. #9
    Rédacteur

    Avatar de loka
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Novembre 2004
    Messages
    2 672
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Service public

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 672
    Points : 5 509
    Points
    5 509
    Par défaut
    Il semblerait que le code vient d'être corrigé dans le tuto.

    Si vous rencontrez des problèmes de ce genre, merci de remonter l'info à celui qui a écrit le tuto afin qu'il puisse corriger (ça arrive de faire des erreurs ).

    Merci et bonne continuation

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. extraction d'un sous élèment dans une variable javascript
    Par jowelle dans le forum Général JavaScript
    Réponses: 8
    Dernier message: 28/12/2011, 12h56
  2. Réponses: 3
    Dernier message: 13/10/2010, 19h09
  3. [RegEx] Remplacement de chaine dans une sous chaine
    Par fpouget dans le forum Langage
    Réponses: 4
    Dernier message: 23/02/2010, 08h49
  4. Réponses: 6
    Dernier message: 13/11/2009, 16h06
  5. recherche d'une chaine dans une sous chaine
    Par claralavraie dans le forum Oracle
    Réponses: 1
    Dernier message: 31/07/2006, 12h00

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo