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 :

Tableau de tableau sur char ... problème free !


Sujet :

C

  1. #1
    Rédacteur
    Avatar de Franck.H
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2004
    Messages
    6 951
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2004
    Messages : 6 951
    Points : 12 462
    Points
    12 462
    Par défaut Tableau de tableau sur char ... problème free !
    Bonjour,

    Je veut éclater une chaîne de caracteres, pour cela j'alloue dynamiquement un: char ** pp_tab:

    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
     
       i = 0;
       while ((tmp_word = strtok (tmp_str2, " ")) != NULL)
       {
          /* Allocation/Reallocation du tableau */
          p_tmp = realloc (pp_tab, (i + 1) * sizeof (*pp_tab));
     
          if (p_tmp == NULL)
          {
             err = 1;
             break;
          }
     
     
          /* Mise a jour du pointeur. */
          pp_tab = p_tmp;
     
     
          /* Affectation du mot au tableau. */
          pp_tab[i] = malloc ((sizeof (**pp_tab) * strlen (tmp_word)) + 1);
     
          if (pp_tab[i] == NULL)
          {
             err = 1;
             break;
          }
     
          strcpy (pp_tab[i], tmp_word);
          pp_tab[i][strlen (tmp_word)] = '\0';
     
     
          tmp_str2 = NULL;
          i++;
       }
       pp_tab[i] = NULL;
    Pour la libération, je procède de cette manière:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
       i = 0;
       printf ("Suppression du tableau:\n");
       while (tab[i] != NULL)
       {
          free (tab[i]);
          i++;
       }
       free (tab);
    Mais voilà le problème lors de l'exécution:

    *** glibc detected *** free(): invalid pointer: 0x0804c258 ***
    Abandon
    Où me suis-je trompé ?
    Merci d'avance

    PS: Dans mon test, j'ai 11 chaine d'allouée dans le tableau et j'ai pu constater que le problème viens lors de la liberation de la 10°, donc 2 avant celle qui vaut NULL..Cependant, je n'ai aucun problème lorsque parcours le tableau pour visionner le contenu !
    Mon Site
    Ma bibliothèque de gestion des chaînes de caractères en C

    L'imagination est plus importante que le savoir. A. Einstein

    Je ne répond à aucune question technique par MP, merci d'avance !

  2. #2
    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 Re: Tableau de tableau sur char ... problème free !
    Citation Envoyé par CSoldier
    Je veut éclater une chaîne de caracteres, pour cela j'alloue dynamiquement un: char ** pp_tab:
    Mais voilà le problème lors de l'exécution:

    *** glibc detected *** free(): invalid pointer: 0x0804c258 ***
    Abandon
    PS: Dans mon test, j'ai 11 chaine d'allouée dans le tableau et j'ai pu constater que le problème viens lors de la liberation de la 10°, donc 2 avant celle qui vaut NULL..Cependant, je n'ai aucun problème lorsque parcours le tableau pour visionner le contenu !
    Curieux, je n'ai pas de problèmes avec ce code (le tien est incomplet):
    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
     
    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
     
    static char ** crea(char *const str2)
    {
        /* ----- Decoupage de la chaine ----- */
     
        /* Recherche des mots. */
        char **pp_tab = NULL;
        size_t i = 0;
        char *tmp_str2 = str2;
        char *tmp_word;
        int err=0;
        while ((tmp_word = strtok (tmp_str2, " ")) != NULL)
        {
            /* Allocation/Reallocation du tableau */
            char **p_tmp = realloc (pp_tab, (i + 1) * sizeof (*pp_tab));
     
            if (p_tmp == NULL)
            {
                err = 1;
                break;
            }
            else
            {
                /* Mise a jour du pointeur. */
                pp_tab = p_tmp;
     
     
                /* Affectation du mot au tableau. */
                pp_tab[i] = malloc (sizeof (**pp_tab) * strlen (tmp_word));
     
                if (pp_tab[i] == NULL)
                {
                    err = 1;
                    break;
                }
     
                strcpy (pp_tab[i], tmp_word);
            }
     
     
            tmp_str2 = NULL;
            i++;
        }
     
        /* sentinel */
        if (pp_tab != NULL)
        {
            pp_tab[i] = NULL;
        }
     
        return pp_tab;
    }
     
    static void disp(char **tab)
    {
        size_t i = 0;
     
        while (tab[i] != NULL)
        {
            printf ("'%s'\n", tab[i]);
            i++;
        }
    }
     
    static void supp(char **tab)
    {
        size_t i = 0;
        printf ("Suppression du tableau:\n");
        while (tab[i] != NULL)
        {
            free (tab[i]);
            i++;
        }
        free (tab);
    }
     
    int main(void)
    {
        char s[]="a b c d";
        char ** tab = crea(s);
     
        if (tab != NULL)
        {
           disp(tab);
           supp(tab);
        }
        return 0;
    }
    Pas de Wi-Fi à la maison : CPL

  3. #3
    Rédacteur
    Avatar de Franck.H
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2004
    Messages
    6 951
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2004
    Messages : 6 951
    Points : 12 462
    Points
    12 462
    Par défaut
    Voici mon code de la fonction:

    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
    char ** C_Str_split (C_Str *self)
    {
       int err = 0;
       char *tmp_word = NULL;
       char *tmp_str = NULL;
       char *tmp_str2 = NULL;
       char **pp_tab = NULL;
       char **p_tmp = NULL;
       int i;
     
     
       /* ----- Allocation d'un espace pour une copie de la chaine ----- */
     
       tmp_str = malloc ((self->len * sizeof (char *)) + 1);
     
       if (tmp_str == NULL)
       {
          /* Erreur: impossible d'allouer l'espace requis. */
          C_STR_ERR_MSG ("C_Str_split",
                         "Impossible d'allouer l'espace requis !\n");
     
          return NULL;
       }
     
       /* Copie de la chaine de l'instance de la classe. */
       strcpy (tmp_str, self->sz_string);
       tmp_str2 = tmp_str;
     
       /* ----- */
     
     
       /* ----- Decoupage de la chaine ----- */
     
       /* Recherche des mots. */
       i = 0;
       while ((tmp_word = strtok (tmp_str2, " ")) != NULL)
       {
          /* Allocation/Reallocation du tableau */
          p_tmp = realloc (pp_tab, (i + 1) * sizeof (*pp_tab));
     
          if (p_tmp == NULL)
          {
             err = 1;
             break;
          }
     
     
          /* Mise a jour du pointeur. */
          pp_tab = p_tmp;
     
     
          /* Affectation du mot au tableau. */
          pp_tab[i] = malloc ((sizeof (**pp_tab) * strlen (tmp_word)) + 1);
     
          if (pp_tab[i] == NULL)
          {
             err = 1;
             break;
          }
     
          strcpy (pp_tab[i], tmp_word);
          pp_tab[i][strlen (tmp_word)] = '\0';
     
     
          tmp_str2 = NULL;
          i++;
       }
     
       /* ----- */
     
     
       if (err == 0)
       {
          /* Marque la fin du tableau */
          pp_tab[i] = NULL;
     
     
          /* ----- Liberation de la memoire ----- */
     
          free (tmp_str);
          tmp_word = NULL;
          tmp_str = NULL;
     
          /* ----- */
       }
       else
       {
          /* Erreur: impossible d'allouer l'espace requis. */
          C_STR_ERR_MSG ("C_Str_split",
                         "Impossible d'allouer l'espace requis !\n");
     
          free (tmp_str);
          free (pp_tab);
     
          tmp_str = NULL;
          pp_tab = NULL;
          tmp_word = NULL;
          p_tmp = NULL;
       }
     
       /* ----- */
     
     
       return pp_tab;
    }
    Dans la fonction je fait une copie de la chaine car je veut garder l'originale intacte
    Mon Site
    Ma bibliothèque de gestion des chaînes de caractères en C

    L'imagination est plus importante que le savoir. A. Einstein

    Je ne répond à aucune question technique par MP, merci d'avance !

  4. #4
    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 CSoldier
    Dans la fonction je fait une copie de la chaine car je veut garder l'originale intacte
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        /* ----- Allocation d'un espace pour une copie de la chaine ----- */
        tmp_str = malloc ((self->len * sizeof (char *)) + 1);
    Pourquoi char * ? C'est soit
    • tmp_str = malloc (self->len + 1);
    • tmp_str = malloc ((self->len + sizeof * tmp_str )+ 1);

    Ce n'est pas ça le problème, mais c'est juste incohérent.
    Pas de Wi-Fi à la maison : CPL

  5. #5
    Rédacteur
    Avatar de Franck.H
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2004
    Messages
    6 951
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2004
    Messages : 6 951
    Points : 12 462
    Points
    12 462
    Par défaut
    Oui merci pour cette correction.
    En tous cas, j'ai beau chercher, je vois pas le problème !
    Mon Site
    Ma bibliothèque de gestion des chaînes de caractères en C

    L'imagination est plus importante que le savoir. A. Einstein

    Je ne répond à aucune question technique par MP, merci d'avance !

  6. #6
    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 CSoldier
    Oui merci pour cette correction.
    En tous cas, j'ai beau chercher, je vois pas le problème !
    Ce code fonctionne chez moi. Mais tu n'as toujours pas posté ton code code complet réduit au minimum qui montre le problème. Je fais des suppositions...
    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
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
     
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
     
    #define C_STR_ERR_MSG(f, m)\
       fprintf (stderr, "%s: %s", f, m)
     
    typedef struct
    {
        size_t len;
        char const *sz_string;
    }
    C_Str;
     
    static char ** C_Str_split (C_Str *self)
    {
        int err = 0;
        char *tmp_word = NULL;
        char *tmp_str = NULL;
        char *tmp_str2 = NULL;
        char **pp_tab = NULL;
        char **p_tmp = NULL;
        int i;
     
        /* ----- Allocation d'un espace pour une copie de la chaine ----- */
        tmp_str = malloc (self->len + 1);
     
        if (tmp_str == NULL)
        {
            /* Erreur: impossible d'allouer l'espace requis. */
            C_STR_ERR_MSG ("C_Str_split",
                           "Impossible d'allouer l'espace requis !\n");
     
            return NULL;
        }
     
        /* Copie de la chaine de l'instance de la classe. */
        strcpy (tmp_str, self->sz_string);
        tmp_str2 = tmp_str;
     
        /* ----- */
     
     
        /* ----- Decoupage de la chaine ----- */
     
        /* Recherche des mots. */
        i = 0;
        while ((tmp_word = strtok (tmp_str2, " ")) != NULL)
        {
            /* Allocation/Reallocation du tableau */
            p_tmp = realloc (pp_tab, (i + 1) * sizeof (*pp_tab));
     
            if (p_tmp == NULL)
            {
                err = 1;
                break;
            }
     
     
            /* Mise a jour du pointeur. */
            pp_tab = p_tmp;
     
     
            /* Affectation du mot au tableau. */
            pp_tab[i] = malloc ((sizeof (**pp_tab) * strlen (tmp_word)) + 1);
     
            if (pp_tab[i] == NULL)
            {
                err = 1;
                break;
            }
     
            strcpy (pp_tab[i], tmp_word);
            pp_tab[i][strlen (tmp_word)] = '\0';
     
     
            tmp_str2 = NULL;
            i++;
        }
     
        /* ----- */
     
     
        if (err == 0)
        {
            /* Marque la fin du tableau */
            pp_tab[i] = NULL;
     
     
            /* ----- Liberation de la memoire ----- */
     
            free (tmp_str);
            tmp_word = NULL;
            tmp_str = NULL;
     
            /* ----- */
        }
        else
        {
            /* Erreur: impossible d'allouer l'espace requis. */
            C_STR_ERR_MSG ("C_Str_split",
                           "Impossible d'allouer l'espace requis !\n");
     
            free (tmp_str);
            free (pp_tab);
     
            tmp_str = NULL;
            pp_tab = NULL;
            tmp_word = NULL;
            p_tmp = NULL;
        }
     
        /* ----- */
     
     
        return pp_tab;
    }
     
    static void disp(char **tab)
    {
        size_t i = 0;
     
        while (tab[i] != NULL)
        {
            printf ("'%s'\n", tab[i]);
            i++;
        }
    }
     
    static void supp(char **tab)
    {
        size_t i = 0;
        printf ("Suppression du tableau:\n");
        while (tab[i] != NULL)
        {
            free (tab[i]);
            i++;
        }
        free (tab);
    }
     
    int main()
    {
        C_Str s;
     
        s.sz_string = "a b c d";
        s.len = strlen(s.sz_string);
     
     
        char ** tab = C_Str_split (&s);
     
        if (tab != NULL)
        {
            disp(tab);
            supp(tab);
        }
        return (0);
    }
    Pas de Wi-Fi à la maison : CPL

  7. #7
    Rédacteur
    Avatar de Franck.H
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2004
    Messages
    6 951
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2004
    Messages : 6 951
    Points : 12 462
    Points
    12 462
    Par défaut
    Voici le code complet reduit:

    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
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
     
     
    typedef struct C_Str
    {
       char *sz_string;
       size_t len;
    }
    C_Str;
     
     
    static C_Str * C_Str_new (const char *s_str)
    {
       C_Str *self = (C_Str *) NULL;
       char *tmp_str = NULL;
     
     
       /* Verifie si l'argument n'est pas NULL. */
       if (s_str != NULL)
       {
          /* Allocation dynamique de la nouvelle instance. */
          self = (C_Str *) malloc (sizeof (C_Str));
     
          if (self == (C_Str *) NULL)
          {
             /* Erreur: impossible d'allouer l'espace requis. */
             return self;
          }
     
     
          /* Allocation d'un espace memoire pour la chaine. */
          tmp_str = malloc ((strlen (s_str) * sizeof (*tmp_str)) + 1);
     
          if (tmp_str == NULL)
          {
             /* Erreur: impossible d'allouer l'espace requis. */
             free ((void *)self);
             self = (C_Str *) NULL;
     
             return self;
          }
     
          strcpy (tmp_str, s_str);
     
     
          /* On fait pointer la chaine en argument par la classe */
          self->sz_string = tmp_str;
          tmp_str = NULL;
     
          /* Calcul de la taille et affectation du resultat dans la classe */
          self->len = strlen (self->sz_string);
       }
     
     
       return self;
    }
     
     
    static void C_Str_destroy (C_Str **self)
    {
       if (*self != NULL)
       {
          /* Suppression de la chaine. */
          if ((*self)->sz_string != NULL)
          {
             free ((*self)->sz_string);
          }
     
          (*self)->sz_string = NULL;
     
     
          free (*self);
          *self = (C_Str *) NULL;
       }
    }
     
     
    static char ** C_Str_split (C_Str *self)
    {
       int err = 0;
       char *tmp_word = NULL;
       char *tmp_str = NULL;
       char *tmp_str2 = NULL;
       char **pp_tab = NULL;
       char **p_tmp = NULL;
       size_t i;
     
     
       /* ----- Allocation d'un espace pour une copie de la chaine ----- */
     
       tmp_str = malloc ((self->len * sizeof (*tmp_str)) + 1);
     
       if (tmp_str == NULL)
       {
          /* Erreur: impossible d'allouer l'espace requis. */
          return NULL;
       }
     
       /* Copie de la chaine de l'instance de la classe. */
       strcpy (tmp_str, self->sz_string);
       tmp_str2 = tmp_str;
     
       /* ----- */
     
     
       /* ----- Decoupage de la chaine ----- */
     
       /* Recherche des mots. */
       i = 0;
       while ((tmp_word = strtok (tmp_str2, " ")) != NULL)
       {
          /* Allocation/Reallocation du tableau */
          p_tmp = realloc (pp_tab, (i + 1) * sizeof (*pp_tab));
     
          if (p_tmp == NULL)
          {
             err = 1;
             break;
          }
     
     
          /* Mise a jour du pointeur. */
          pp_tab = p_tmp;
     
     
          /* Affectation du mot au tableau. */
          pp_tab[i] = malloc ((sizeof (**pp_tab) * strlen (tmp_word)) + 1);
     
          if (pp_tab[i] == NULL)
          {
             err = 1;
             break;
          }
     
          strcpy (pp_tab[i], tmp_word);
          pp_tab[i][strlen (tmp_word)] = '\0';
     
     
          tmp_str2 = NULL;
          i++;
       }
     
     
       /* Marque la fin du tableau */
       pp_tab[i] = NULL;
     
       /* ----- */
     
     
       if (err == 0)
       {
          free (tmp_str);
          tmp_str = NULL;
       }
       else
       {
          /* Erreur. */
     
          /* On vide la chaine temporaire. */
          free (tmp_str);
          tmp_str = NULL;
     
          /* On efface le tableau qui a deja ete cree. */
          i = 0;
          while (pp_tab[i] != NULL)
          {
             free (pp_tab[i]);
             i++;
          }
          free (pp_tab);
          pp_tab = NULL;
     
          tmp_word = NULL;
          p_tmp = NULL;
       }
     
       /* ----- */
     
     
       return pp_tab;
    }
     
     
    int main (void)
    {
       C_Str *my_cstr = NULL;
       char **tab = NULL;
       int i = 0;
     
     
       my_cstr = C_Str_new ("Une chaine de test !");
     
       if (my_cstr == NULL)
       {
          fprintf (stderr, "Erreur\n");
          exit (EXIT_FAILURE);
       }
     
     
       /* Decoupage de la chaine dans un tableau */
       printf ("Decoupage de la chaine dans un tableau:\n");
       tab = C_Str_split (my_cstr);
     
       if (tab)
       {
          i = 0;
          printf ("\nListe des mots:\n");
          while (tab[i] != NULL)
          {
             printf ("Mot %d\t: %s\n", i+1, tab[i]);
             i++;
          }
          printf ("\n");
     
          i = 0;
          printf ("Suppression du tableau:\n");
          while (tab[i] != NULL)
          {
             free (tab[i]);
             printf ("...%d\n", i+1);
             i++;
          }
          free (tab);
          printf ("Ok\n\n");
       }
     
     
       C_Str_destroy (&my_cstr);
     
     
       return EXIT_SUCCESS;
    }
    Mon Site
    Ma bibliothèque de gestion des chaînes de caractères en C

    L'imagination est plus importante que le savoir. A. Einstein

    Je ne répond à aucune question technique par MP, merci d'avance !

  8. #8
    Rédacteur
    Avatar de Franck.H
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2004
    Messages
    6 951
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2004
    Messages : 6 951
    Points : 12 462
    Points
    12 462
    Par défaut
    Pour infos, je suis sous Linux avec gcc 4, je sais pas si ca peut avoir un rapport mais sait-on jamais ! C'est compilé en C99 par défaut si je me trompe pas !
    Mon Site
    Ma bibliothèque de gestion des chaînes de caractères en C

    L'imagination est plus importante que le savoir. A. Einstein

    Je ne répond à aucune question technique par MP, merci d'avance !

  9. #9
    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 CSoldier
    Voici le code complet reduit:
    A première vue, ça a l'air correct :

    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
     
    Decoupage de la chaine dans un tableau:
     
    Liste des mots:
    Mot 1   : Une
    Mot 2   : chaine
    Mot 3   : de
    Mot 4   : test
    Mot 5   : !
     
    Suppression du tableau:
    ...1
    ...2
    ...3
    ...4
    ...5
    Ok
    Je vais tester dans le detail...

    Je n'ai pas trouvé d'erreurs épouvantables. J'ai un peu simplifié le code :
    EDIT : Diogene a trouvé le bug : Correction
    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
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
     
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
     
    typedef struct
    {
        char *sz_string;
        size_t len;
    }
    C_Str;
     
    /* -ed- 
    il ne faut hesiter a faire ses outils... 
     nota : strdup() est POSIX
     */
    static char *str_dup (char const *const s)
    {
        char *s_dup=NULL;
     
        if (s != NULL)
        {
            size_t size = strlen(s)+1;
            s_dup = malloc(size);
     
            if (s_dup != NULL)
            {
                memcpy(s_dup, s, size);
            }
        }
        return s_dup;
    }
     
     
    static C_Str * C_Str_new (char const * const s_str)
    {
        C_Str * self =NULL;
     
        /* Verifie si l'argument n'est pas NULL. */
        if (s_str != NULL)
        {
            /* Allocation dynamique de la nouvelle instance. */
            self = malloc (sizeof (C_Str));
     
            if (self != NULL)
            {
                /* Allocation d'un espace memoire pour la chaine. */
                char *tmp_str =str_dup (s_str);
     
                if (tmp_str != NULL)
                {
                    /* On fait pointer la chaine en argument par la classe */
                    self->sz_string = tmp_str, tmp_str = NULL;
     
                    /* Calcul de la taille et affectation du resultat dans la classe */
                    self->len = strlen (self->sz_string);
                }
                else
                {
                    /* Erreur: impossible d'allouer l'espace requis. */
                    free (self), self = NULL;
                }
            }
        }
     
        return self;
    }
     
     
    static void C_Str_destroy (C_Str **const self)
    {
        if (self != NULL)
        {
            if (*self != NULL)
            {
                /* Suppression de la chaine. */
                if ((*self)->sz_string != NULL)
                {
                    free ((*self)->sz_string);
                }
     
                (*self)->sz_string = NULL;
     
                free (*self);
                *self = (C_Str *) NULL;
            }
        }
    }
     
    static char ** C_Str_split (C_Str const *const self)
    {
        char **pp_tab = NULL;
        int err = 0;
     
        /* ----- Allocation d'un espace pour une copie de la chaine ----- */
     
        char *tmp_str = str_dup (self->sz_string);
     
        if (tmp_str != NULL)
        {
            {
                char *tmp_str2 = tmp_str;
     
                /* ----- Decoupage de la chaine ----- */
     
                /* Recherche des mots. */
                size_t i = 0;
                char *tmp_word;
     
                while ((tmp_word = strtok (tmp_str2, " ")) != NULL)
                {
                    /* Allocation/Reallocation du tableau */
     
                   /* -ed- Correction : merci a Diogene. (+1 pour la sentinelle) */
                    char **p_tmp = realloc (pp_tab, i + 1 + 1);
     
                    if (p_tmp == NULL)
                    {
                        err = 1;
                        break;
                    }
     
                    /* Mise a jour du pointeur. */
                    pp_tab = p_tmp;
     
                    /* Affectation du mot au tableau. */
                    pp_tab[i] = str_dup (tmp_word);
     
                    if (pp_tab[i] == NULL)
                    {
                        err = 1;
                        break;
                    }
     
                    /* les strtok() suivants doivent avoir NULL en premier parametre */
                    tmp_str2 = NULL;
                    i++;
                }
     
                /* Marque la fin du tableau */
                pp_tab[i] = NULL;
            }
     
            if (!err)
            {
                free (tmp_str);
                tmp_str = NULL;
            }
            else
            {
                /* Erreur. */
     
                /* On libere la chaine temporaire. */
                free (tmp_str);
                tmp_str = NULL;
     
                /* On efface le tableau qui a deja ete cree. */
                size_t i = 0;
     
                /* -ed- astucieux. Le NULL de l'erreur sert de sentinelle... */
                while (pp_tab[i] != NULL)
                {
                    free (pp_tab[i]);
                    i++;
                }
                free (pp_tab), pp_tab = NULL;
            }
        }
        return pp_tab;
    }
     
    int main (void)
    {
        C_Str *my_cstr = C_Str_new ("Une chaine de test !");
     
        if (my_cstr == NULL)
        {
            fprintf (stderr, "Erreur\n");
        }
        else
        {
            /* Decoupage de la chaine dans un tableau */
            printf ("Decoupage de la chaine dans un tableau:\n");
            char **tab = C_Str_split (my_cstr);
     
            if (tab != NULL)
            {
                int i = 0;
                printf ("\nListe des mots:\n");
                while (tab[i] != NULL)
                {
                    printf ("Mot %d\t: %s\n", i+1, tab[i]);
                    i++;
                }
                printf ("\n");
     
                i = 0;
                printf ("Suppression du tableau:\n");
                while (tab[i] != NULL)
                {
                    free (tab[i]);
                    printf ("...%d\n", i+1);
                    i++;
                }
                free (tab);
                printf ("Ok\n\n");
            }
     
            C_Str_destroy (&my_cstr);
     
        }
        return EXIT_SUCCESS;
    }
    Je n'ai pas bien compris à quoi servait l'objet C_Str...
    Pas de Wi-Fi à la maison : CPL

  10. #10
    Rédacteur
    Avatar de Franck.H
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2004
    Messages
    6 951
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2004
    Messages : 6 951
    Points : 12 462
    Points
    12 462
    Par défaut
    Ok merci, moi j'ai compilé et testé ce code que j'ai posté mais j'ai la même erreur !

    Mon résultat:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Liste des mots:
    Mot 1   : Une
    Mot 2   : chaine
    Mot 3   : de
    Mot 4   : test
    Mot 5   : !
     
    Suppression du tableau:
    ...1
    ...2
    ...3
    ...4
    *** glibc detected *** free(): invalid pointer: 0x0804a0b0 ***
    Abandon
    Mon Site
    Ma bibliothèque de gestion des chaînes de caractères en C

    L'imagination est plus importante que le savoir. A. Einstein

    Je ne répond à aucune question technique par MP, merci d'avance !

  11. #11
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    J'ai la même erreur à l'exécution :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
       while ((tmp_word = strtok (tmp_str2, " ")) != NULL) 
       {
          /* Allocation/Reallocation du tableau */
          p_tmp = realloc (pp_tab, (i + 1) * sizeof (*pp_tab));
    ........      
          i++;
       }
       /* Marque la fin du tableau */
       pp_tab[i] = NULL;
    tu n'as pas alloué la place dans pp_tab pour mettre ce NULL ! Tu dois reallouer (i+2 )*sizeof(*pp_tab)
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  12. #12
    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 diogene
    J'ai la même erreur à l'exécution :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
       while ((tmp_word = strtok (tmp_str2, " ")) != NULL) 
       {
          /* Allocation/Reallocation du tableau */
          p_tmp = realloc (pp_tab, (i + 1) * sizeof (*pp_tab));
    ........      
          i++;
       }
       /* Marque la fin du tableau */
       pp_tab[i] = NULL;
    tu n'as pas alloué la place dans pp_tab pour mettre ce NULL ! Tu dois reallouer (i+2 )*sizeof(*pp_tab)
    Oui !
    Pas de Wi-Fi à la maison : CPL

  13. #13
    Rédacteur
    Avatar de Franck.H
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2004
    Messages
    6 951
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2004
    Messages : 6 951
    Points : 12 462
    Points
    12 462
    Par défaut
    Oui merci, ca fonctionne maintenant !
    Mon Site
    Ma bibliothèque de gestion des chaînes de caractères en C

    L'imagination est plus importante que le savoir. A. Einstein

    Je ne répond à aucune question technique par MP, merci d'avance !

  14. #14
    Rédacteur
    Avatar de Franck.H
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2004
    Messages
    6 951
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2004
    Messages : 6 951
    Points : 12 462
    Points
    12 462
    Par défaut
    Huumm j'avais pas pensé à faire une fonction spécifique pour faire mes copies de chaines, c'est sympa !
    Mon Site
    Ma bibliothèque de gestion des chaînes de caractères en C

    L'imagination est plus importante que le savoir. A. Einstein

    Je ne répond à aucune question technique par MP, merci d'avance !

  15. #15
    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 CSoldier
    Huumm j'avais pas pensé à faire une fonction spécifique pour faire mes copies de chaines, c'est sympa !
    http://emmanuel-delahaye.developpez.com/clib.htm
    Module STR
    Fonction STR_dup()
    Pas de Wi-Fi à la maison : CPL

  16. #16
    Rédacteur
    Avatar de Franck.H
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2004
    Messages
    6 951
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2004
    Messages : 6 951
    Points : 12 462
    Points
    12 462
    Par défaut
    Question subsidiaire:

    Quelle est vraiment la différence entre utiliser par exemple memcpy ou strcpy ?
    Enfin je parle du point de vue du résultat !
    Mon Site
    Ma bibliothèque de gestion des chaînes de caractères en C

    L'imagination est plus importante que le savoir. A. Einstein

    Je ne répond à aucune question technique par MP, merci d'avance !

  17. #17
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    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 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Puisque tu connais déjà la taille pour faire l'allocation, je pense que memcpy() est plus rapide (peut traiter les octets par blocs, certains procs ont même déjà une instruction qui fait le déplacement tout seul)

    Emmanuel: Tiens, c'est vrai strdup() n'est pas standard... Il semblerait qu'elle ne soit même pas POSIX (je viens de trouver "#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)" dans des headers FreeBSD)
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  18. #18
    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 CSoldier
    Quelle est vraiment la différence entre utiliser par exemple memcpy ou strcpy ?
    Enfin je parle du point de vue du résultat !
    Aucun. C'est une question de performances.

    Ca dépend évidemment de l'implémentation, mais Il y a de fortes chances que memcpy() soit inliné et mieux optimisée que strcpy() (copie par bloc de 2 ou 4 octets, instructions rapides genre 'REP' ...)

    Par construction des chaines C, strcpy() ne peut pas être optimisé. C'est un des problèmes du C... Plus la chaine s'allonge, plus un strlen() ou un strcpy(), ou finalement, n'importe quelle fonction impliquant les chaines deviennent prohibitifs.

    Pour de meilleures chaines, tout le monde y va de son objet 'string'...

    http://emmanuel-delahaye.developpez.com/clib.htm
    Module FSTR

    répond aux besoins de base...
    Pas de Wi-Fi à la maison : CPL

  19. #19
    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 Médinoc
    Emmanuel: Tiens, c'est vrai strdup() n'est pas standard... Il semblerait qu'elle ne soit même pas POSIX (je viens de trouver "#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)" dans des headers FreeBSD)
    http://www.unix.org/version3/online.html
    (s'inscrire, ça mord pas...)
    NAME

    strdup - duplicate a string

    SYNOPSIS

    [XSI] [Option Start] #include <string.h>

    char *strdup(const char *s1); [Option End]

    DESCRIPTION

    The strdup() function shall return a pointer to a new string, which is a duplicate of the string pointed to by s1. The returned pointer can be passed to free(). A null pointer is returned if the new string cannot be created.

    RETURN VALUE

    The strdup() function shall return a pointer to a new string on success. Otherwise, it shall return a null pointer and set errno to indicate the error.

    ERRORS

    The strdup() function may fail if:

    [ENOMEM]
    Storage space available is insufficient.

    The following sections are informative.
    EXAMPLES

    None.

    APPLICATION USAGE

    None.

    RATIONALE

    None.

    FUTURE DIRECTIONS

    None.

    SEE ALSO

    free(), malloc(), the Base Definitions volume of IEEE Std 1003.1-2001, <string.h>

    CHANGE HISTORY

    First released in Issue 4, Version 2.

    Issue 5

    Moved from X/OPEN UNIX extension to BASE.
    Pas de Wi-Fi à la maison : CPL

  20. #20
    Rédacteur
    Avatar de Franck.H
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2004
    Messages
    6 951
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2004
    Messages : 6 951
    Points : 12 462
    Points
    12 462
    Par défaut
    Ok ! Merci pour ces infos !
    Mon Site
    Ma bibliothèque de gestion des chaînes de caractères en C

    L'imagination est plus importante que le savoir. A. Einstein

    Je ne répond à aucune question technique par MP, merci d'avance !

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 1
    Dernier message: 22/12/2009, 11h40
  2. Allocation dynamique: Tableau de pointeur sur char
    Par Anonymouse dans le forum Débuter
    Réponses: 4
    Dernier message: 21/10/2007, 10h57
  3. Problème free() : Tableau de structures
    Par bit_o dans le forum C
    Réponses: 11
    Dernier message: 28/04/2007, 15h53
  4. convertir tableau d'entier en char[]
    Par nin47 dans le forum C
    Réponses: 20
    Dernier message: 12/10/2005, 20h03
  5. envoi tableau de data sur port série
    Par chourmo dans le forum Langage
    Réponses: 2
    Dernier message: 27/07/2005, 16h23

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