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 :

Problème de free() sur un char **


Sujet :

C

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 36
    Points : 26
    Points
    26
    Par défaut Problème de free() sur un char **
    Salut à tous !

    J'ai le code suivant :
    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
    void
    historique ()
    {
      int nbLignes = 15;
      char **historique;
      int i;
     
      historique = malloc (sizeof(char *) * nbLignes);
     
      for (i = 0; i != nbLignes; i++)
        {
          historique[i] = malloc(sizeof(char*));
          historique[i] = "abcdefabcdefabcdefabcdefabcdef"+i;
     
          if (i >= 1 && historique[i] == NULL)
    	break;
        }
     
      for (i--; i >= 0; i--)
        printf ("%s\n", historique[i]);
     
       for (i=0; historique[i] != NULL; i++)
        free(historique[i]);
     
      free(historique);
    }
    Le problème est que le [i]free(historique); ne passe pas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ** glibc detected *** monprog: free(): invalid pointer: 0x0000000000401858 ***
    Pouvez-vous m'indiquer où est le problème ?

  2. #2
    Membre chevronné
    Homme Profil pro
    Dév. Java & C#
    Inscrit en
    Octobre 2002
    Messages
    1 414
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Dév. Java & C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2002
    Messages : 1 414
    Points : 1 996
    Points
    1 996
    Par défaut
    Bonjour,

    Le problème provient du code suivant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
     historique[i] = malloc(sizeof(char*));
     historique[i] = "abcdefabcdefabcdefabcdefabcdef"+i;
    Tu alloues de l'espace dans le tas et le pointeur est sauvé dans historique[i] puis à l'instruction suivante, ce pointeur est écrasé par la valeur du pointeur &"abc..."+i.

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 36
    Points : 26
    Points
    26
    Par défaut
    Voila mon nouveau code, mais qui ne marche toujours pas :

    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
    void
    historique ()
    {
      int nbLignes = 15;
      char **historique;
      int i;
     
      historique = malloc (sizeof(historique) * nbLignes);
     
      for (i = 0; i != nbLignes; i++)
        {
                historique[i] = malloc(sizeof (char) * 512);
          sprintf(historique[i], "abcdefabcdefabcdefabcdefabcdef");
     
          if (i >= 1 && historique[i] == NULL)
    	break;
        }
     
      for (i--; i >= 0; i--)
        printf ("%s\n", historique[i]);
     
       for (i=0; historique[i]; i++)
        free(historique[i]);
     
      free(historique);
    }

  4. #4
    Membre chevronné
    Homme Profil pro
    Dév. Java & C#
    Inscrit en
    Octobre 2002
    Messages
    1 414
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Dév. Java & C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2002
    Messages : 1 414
    Points : 1 996
    Points
    1 996
    Par défaut
    Un free ne peut se faire que pour un pointeur retourné par un malloc ou NULL.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    historique[i] = malloc(sizeof(char*));
    historique[i] = "abcdefabcdefabcdefabcdefabcdef"+i;
    Step By Step...
    1) "malloc(sizeof(char*))" alloue dans le tas un espace pour un pointeur de char*. "malloc" te retourne le pointeur sur cet espace que tu vas mémoriser dans historique[i].

    2) Tu affectes à historique[i] le pointeur résultant du calcul l'adresse de "abcdefa...." plus l'offset de valeur i.

    Au final dans historique[i], tu n'as plus un pointeur adressant le tas mais une zone mémoire qui ne peut être pas libérée par free.

  5. #5
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 36
    Points : 26
    Points
    26
    Par défaut
    Citation Envoyé par jowo Voir le message
    Un free ne peut se faire que pour un pointeur retourné par un malloc ou NULL.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    historique[i] = malloc(sizeof(char*));
    historique[i] = "abcdefabcdefabcdefabcdefabcdef"+i;
    Step By Step...
    1) "malloc(sizeof(char*))" alloue dans le tas un espace pour un pointeur de char*. "malloc" te retourne le pointeur sur cet espace que tu vas mémoriser dans historique[i].

    2) Tu affectes à historique[i] le pointeur résultant du calcul l'adresse de "abcdefa...." plus l'offset de valeur i.

    Au final dans historique[i], tu n'as plus un pointeur adressant le tas mais une zone mémoire qui ne peut être pas libérée par free.
    Je venais justement de mettre une correction la dessus.
    Merci quand meme, mais un bug subsiste sur le free(historique[i])

  6. #6
    Membre chevronné
    Homme Profil pro
    Dév. Java & C#
    Inscrit en
    Octobre 2002
    Messages
    1 414
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Dév. Java & C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2002
    Messages : 1 414
    Points : 1 996
    Points
    1 996
    Par défaut
    Ce code me paraît douteux...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    for (i=0; historique[i] != NULL; i++)
        free(historique[i]);


    Peut être la réponse
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    for (i=0; i < nbLignes; ++i) {
      free(historique[i]);
    }

  7. #7
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 36
    Points : 26
    Points
    26
    Par défaut
    C'était en effet la réponse.
    Mais imaginons que j'ai simplement un char** et que je n'ai pas de variables contenant le nb d'éléments, comment dois-je faire ?

  8. #8
    Membre chevronné
    Homme Profil pro
    Dév. Java & C#
    Inscrit en
    Octobre 2002
    Messages
    1 414
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Dév. Java & C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2002
    Messages : 1 414
    Points : 1 996
    Points
    1 996
    Par défaut
    Une solution est de mettre une sentinelle à la fin

    Pseudo-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
     
    const char * SENTINEL = "";
     
    // Allocation
    historique = malloc(sizeof(historique) * (nbLigne+1));
    historique[nbLigne] = SENTINEL;
    for (i = 0; i < nbLigne; ++i) {
      historique[i] = malloc(512); // En C,  par définition sizeof(char) == 1 est tjrs vraie
    }
     
     
    // Libération
    for (i = 0; historique[i] != SENTINEL; ++i) {
      free(historique[i]);
    }

  9. #9
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 36
    Points : 26
    Points
    26
    Par défaut
    Ok, merci beaucoup

  10. #10
    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
    @jowo :attention, il y a des erreurs dans ton (pseudo)code :
    - dans le malloc de historique
    - manque la libération de historique

    La meilleure sentinelle, et la plus naturelle, dans ce cas n'est pas l'adresse d'une chaine vide, mais la valeur NULL :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    historique = malloc((nbLigne+1)sizeof *historique);
    for (i = 0; i < nbLigne; ++i)   historique[i] = malloc(512); 
    historique[nbLigne] = NULL; 
    ....
    // Libération
    for (i = 0; historique[i] != NULL; ++i)  free(historique[i]);
    free(historique);

  11. #11
    Membre chevronné
    Homme Profil pro
    Dév. Java & C#
    Inscrit en
    Octobre 2002
    Messages
    1 414
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Dév. Java & C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2002
    Messages : 1 414
    Points : 1 996
    Points
    1 996
    Par défaut
    @diogene Merci pour les corrections.
    Je n'ai pas pris NULL comme sentinelle car elle peut être utilisée pour indiquer l'absence d'allocation. On peut supposer que durant le déroulement du programme certains allocations soient libérées et marquées comme "vide" à l'aide de NULL.

  12. #12
    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
    Citation Envoyé par jowo Voir le message
    Je n'ai pas pris NULL comme sentinelle car elle peut être utilisée pour indiquer l'absence d'allocation. On peut supposer que durant le déroulement du programme certains allocations soient libérées et marquées comme "vide" à l'aide de NULL.
    C'est un argument valable dans l'éventualité que tu cites.
    Dans ce cas, personnellement, plutôt qu'une sentinelle marquant la fin, je préférerais assembler dans une structure le pointeur sur le tableau (historique) et le nombre d'éléments alloués.

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

Discussions similaires

  1. utilisation du free sur un char*
    Par kase74 dans le forum Débuter
    Réponses: 10
    Dernier message: 30/01/2009, 19h02
  2. Problème de free() sur pointeurs (Avancé)
    Par terlington dans le forum Linux
    Réponses: 3
    Dernier message: 19/11/2008, 16h25
  3. Réponses: 1
    Dernier message: 07/02/2008, 21h40
  4. Problème script téléchargement sur dl.free.fr
    Par czeus2 dans le forum Applications et environnements graphiques
    Réponses: 0
    Dernier message: 25/09/2007, 16h30
  5. Problème de *pointeur sur des char
    Par Spartan03 dans le forum C++
    Réponses: 2
    Dernier message: 18/09/2005, 14h20

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