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 :

Listes Chainées et libération mémoire?


Sujet :

C

  1. #1
    Membre confirmé
    Inscrit en
    Octobre 2008
    Messages
    82
    Détails du profil
    Informations forums :
    Inscription : Octobre 2008
    Messages : 82
    Par défaut Listes Chainées et libération mémoire?
    Bonjour,

    Je travail sur un projet en C dans lequel j'utilise de longues listes chainées...

    Voici un exemple de liste :

    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
    struct data_POSS
    {
       int valide;
       int Tab1[50];
       int Tab2[200];
    };
     
    struct node_POSS
    {
       struct data_POSS data;
       struct node_POSS *psuiv;
       struct node_POSS *pprec;
    };
     
    struct liste_POSS
    {
       struct node_POSS *pTete;
       struct node_POSS *pQueue;
       int Nb_Elements;
    };
    Ensuite je l'instancie de la manière suivante :

    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
    void add_POSS (struct liste_POSS *p_liste, struct data_POSS *p_data)
    {
       struct node_POSS *pNouveau = malloc (sizeof *pNouveau);
       if (pNouveau != NULL)
       {
          pNouveau->data = *p_data;
          pNouveau->psuiv = NULL;
     
          if (p_liste->pTete == NULL)
          {
          /* Premier maillon = Premiere Ligne */
             p_liste->pTete = pNouveau;
             pNouveau->pprec = NULL;
          }
          else
          {
             p_liste->pQueue->psuiv = pNouveau;
             pNouveau->pprec = p_liste->pQueue;
          }
          p_liste->pQueue = pNouveau;
       }
    }
     
    void Create_liste (struct liste_POSS *p_POSS)
    {
      int i, j;
      struct data_POSS data_CP;
     
      p_POSS->Nb_Elements = 0;
     
      for (i=0;i<65534;i++)
        {
    	data_CP.valide=1;
    	for (j=0;j<50;j++) {data_CP.Tab1[j]=0;}
    	for (j=0;j<200;j++) {data_CP.Tab2[j]=0;}
     	add_POSS(p_POSS, &data_CP);
    	p_POSS->Nb_Elements = p_POSS->Nb_Elements + 1;
         }                                        
    }
    Dans mon Main.c j'appelle la fonction Create_liste afin de créer une chaine.
    Après, avoir travaillé sur cette chaine j'essaie de la réinitialiser en rappelant la fonction Create_liste...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    void Main ()
    {
         int i;
         struct liste_POSS TOTO_liste = {NULL, NULL, 0};
     
         for (i=0;i<5;i++) 
         {
              Create_liste(&TOTO_liste);
     
            // UTILISATION et TRAITEMENT DE LA LISTE
     
         }
    Or, la fonction Create_liste ne donne pas a chaque fois le même nombre d'éléments dans la liste chainée... au début j'ai bien 35535, puis ensuite ca diminue...
    Mon programme est assez gros, et utilise beaucoup de liste et liste de liste...
    Aussi, je me suis dit que c'etait peut etre un probleme mémoire et j'ai ajouté:

    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
    void liberation_Mem (struct liste_POSS *C_POSS)
    {
         struct node_POSS *p_sw = C_POSS->pTete;
         struct node_POSS *p_tmp;
     
         while (p_sw!=NULL)
         {
               p_tmp = p_sw->psuiv;
               free(p_sw);
               C_POSS->pTete = p_tmp;
     
               p_sw = C_POSS->pTete;
         }    
    }
     
    void Main ()
    {
         int i;
         struct liste_POSS TOTO_liste = {NULL, NULL, 0};
     
         for (i=0;i<5;i++) 
         {
              Create_liste(&TOTO_liste);
     
            // UTILISATION et TRAITEMENT DE LA LISTE
     
              liberation_Mem (&TOTO_liste );
     
         }
    Est ce que la libération de mémoire est correcte?

    Merci pour votre aide,

    Alex

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 407
    Par défaut
    D'ici, ça a l'air correct.

    Simplement, tu devrais peut-être remettre les pointeurs à NULL dans la structure, au cas où on tenterait d'y accéder après libération...
    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.

  3. #3
    Membre expérimenté Avatar de quetzacoatl
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    168
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 168
    Par défaut
    Il y a quelque chose d'étrange dans votre fonction "add_POS", vous faites:

    struct node_POSS *pNouveau = malloc (sizeof *pNouveau);

    Alors qu'a priori pNouveau n'est pas un type mais un élément
    Vous vouliez faire j'imagine:

    struct node_POSS *pNouveau = malloc (sizeof ( struct node_POSS));

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 407
    Par défaut
    ^Non, c'est la manière correcte de faire.
    Ainsi, si le type de pNouveau est modifié, il y aura moins de remplacements à faire.

    La seule difficulté c'est de ne pas oublier l'étoile.
    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.

  5. #5
    Membre confirmé
    Inscrit en
    Octobre 2008
    Messages
    82
    Détails du profil
    Informations forums :
    Inscription : Octobre 2008
    Messages : 82
    Par défaut
    Merci pour votre aide !

    Du coup, si c'est bon, je ne comprends pas pourquoi Create liste ne crée pas toujours 65534 cellules...

    Si je vérifie comme ça par exemple :

    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
    void Create_liste (struct liste_POSS *p_POSS)
    {
      int i, j, COmpteur;
      struct data_POSS data_CP;
     
      p_POSS->Nb_Elements = 0;
     
      for (i=0;i<65534;i++)
        {
    	data_CP.valide=1;
    	for (j=0;j<50;j++) {data_CP.Tab1[j]=0;}
    	for (j=0;j<200;j++) {data_CP.Tab2[j]=0;}
     	add_POSS(p_POSS, &data_CP);
    	p_POSS->Nb_Elements = p_POSS->Nb_Elements + 1;
         }      
     
         struct node_POSS *p_swp =  p_POSS->pTete;
         while (p_swp!=NULL)
         {
             COmpteur++;
             p_swp = p_swp->psuiv;
          }
         printf("%d\t%d\r\n", p_POSS->Nb_Elements, COmpteur);
     
    }
    On obtient toujours p_POSS->Nb_Elements = 65534 mais COmpteur peut avoir une autre valeur...

    Y a t il une solution pour voir combien de mémoire le programme utilise ???

    Car j'avais déjà des plantages "aléatoires" du programme que j'ai résolus en ajoutant la fonction "liberation_Mem"... Du coup, je me dis que ça doit encore être du à ça...

  6. #6
    Membre expérimenté Avatar de quetzacoatl
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    168
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 168
    Par défaut
    Je pense que le problème vient peut-être de votre fonction

    void add_POSS (struct liste_POSS *p_liste, struct data_POSS *p_data)
    En effet, vous y faites
    pNouveau->data = *p_data;
    Or *p_data contient deux tableaux, vous n'allez donc pas recopié les tableaux de cette façon , et pire encore une partie de la mémoire réservée par votre malloc ne sera plus accessible.

  7. #7
    Membre confirmé
    Inscrit en
    Octobre 2008
    Messages
    82
    Détails du profil
    Informations forums :
    Inscription : Octobre 2008
    Messages : 82
    Par défaut
    Je ne comprends pas pourquoi...

  8. #8
    Membre expérimenté Avatar de quetzacoatl
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    168
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 168
    Par défaut
    Ecrire quelque chose du genre tab1=tab2 ne recopie pas tab2 dans tab1, les tableaux étant en réalité des pointeurs, on affecte au pointeur tab1 qui pointe sur la première case d'un tableau, l'adresse de la premiere case de tab2.
    Ainsi tab1 pointe sur la première case de tab2, mais il n'y a pas de recopie comme on désirait.
    Et je pense que l'espace mémoire réservé par tab1 n'étant plus pointée, cela peut peut-être causé des soucis.

    Pour recopier les tableaux il faut utilisr des fonctions du genre memcpy()

  9. #9
    Expert confirmé
    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
    Par défaut
    Dans Create_liste(), COmpteur n'est pas initialisé à 0 , d'où des résultats farfelus .

  10. #10
    Membre confirmé
    Inscrit en
    Octobre 2008
    Messages
    82
    Détails du profil
    Informations forums :
    Inscription : Octobre 2008
    Messages : 82
    Par défaut
    ça c'est une erreur de saisie... quand j'ai écrit le code sur le forum...
    Compteur est bien initialisé !

    Et au fur et a mesure des ré initialisation de la liste, le nombre d'éléments décroit...

    Je vais ajouter ça, ca me donnera surement plus d'info...

    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
     
    void add_POSS (struct liste_POSS *p_liste, struct data_POSS *p_data)
    {
       struct node_POSS *pNouveau = malloc (sizeof *pNouveau);
     
       if (pNouveau != NULL)
       {
          pNouveau->data = *p_data;
          pNouveau->psuiv = NULL;
     
          if (p_liste->pTete == NULL)
          {
          /* Premier maillon = Premiere Ligne */
             p_liste->pTete = pNouveau;
             pNouveau->pprec = NULL;
          }
          else
          {
             p_liste->pQueue->psuiv = pNouveau;
             pNouveau->pprec = p_liste->pQueue;
          }
          p_liste->pQueue = pNouveau;
       }
       else // l'allocation a échoué
      { 
        printf("C'est la que ca merde !\r\n");
      }
     
    }

  11. #11
    Membre Expert
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Par défaut
    Citation Envoyé par alexglvr Voir le message
    ça c'est une erreur de saisie... quand j'ai écrit le code sur le forum...
    Pourquoi tu t'embêtes à retaper le code à la main ? Utilise le copié/collé, ça va te simplifier énormément la vie.

  12. #12
    Membre confirmé
    Inscrit en
    Octobre 2008
    Messages
    82
    Détails du profil
    Informations forums :
    Inscription : Octobre 2008
    Messages : 82
    Par défaut
    Pourquoi tu t'embêtes à retaper le code à la main ? Utilise le copié/collé, ça va te simplifier énormément la vie.
    Par ce que le code réel est beaucoup trop gros pour être posté, du coup, j'ai fait un petit code spécial qui montre mon problème ! Ça prend deux minutes, et ça simplifie la compréhension...

  13. #13
    Expert confirmé
    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
    Par défaut
    Par ce que le code réel est beaucoup trop gros pour être posté, du coup, j'ai fait un petit code spécial qui montre mon problème !
    C'est une bonne idée, mais fait alors un copier/coller du code spécial qui montre le problème. Si le code de test que tu montres est faux, on ne va pas s'en sortir.

    Personnellement, en exécutant le code que tu proposes (si j'ai bien rassemblé les différents morceaux) et après correction des erreurs pour que ça compile, je ne constate pas de problèmes.

    J'ai pris : Create_liste() du post #5 (et corrigé COmpteur), add_POSS() du post #10, les définitions du post #1, le main (après correction)du post #1 et ensuite aussi l'ensemble liberation_Mem()+ main (après correction) du post #1 et enfin ajouté les deux #include manquant.

  14. #14
    Membre confirmé
    Inscrit en
    Octobre 2008
    Messages
    82
    Détails du profil
    Informations forums :
    Inscription : Octobre 2008
    Messages : 82
    Par défaut
    La première itération fonctionne chez moi, mais après non (avec le code complet).

    Mais je pense que c'est du à un pb de mémoire...
    Y a t il une limite mémoire à ne pas dépasser??

    Le vrai code génère des dizaines de listes chainées / arbres pouvant contenir plusieurs millions de cellules...

    Je vais tester ce soir ou demain si l'erreur se produit bien lors du malloc...

    JE vous tiens au courant !

    Alex

  15. #15
    Membre confirmé
    Inscrit en
    Octobre 2008
    Messages
    82
    Détails du profil
    Informations forums :
    Inscription : Octobre 2008
    Messages : 82
    Par défaut
    J'ai fait le test en ajoutant dans add_POSS une notification si l'allocation de mémoire echoue...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    void add_POSS (struct liste_POSS *p_liste, struct data_POSS *p_data)
    {
       struct node_POSS *pNouveau = malloc (sizeof *pNouveau);
     
       if (pNouveau != NULL)
       {
         ....
       }
       else // l'allocation a échoué
      { 
        printf("C'est la que ca merde !\r\n");
      }
    Et c'est bien ca...

    A la première itération c'est bon (il reste encore assez de mémoire pour que le programme fonctionne), par contre, à la suivante, les erreurs d'allocation commencent....

    Pourtant entre les deux je fais une libération mémoire....

    Bon, je vais réfléchir à une solution moins gourmande en mémoire...

  16. #16
    Membre du Club
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations forums :
    Inscription : Juin 2008
    Messages : 8
    Par défaut
    Tu peux tester avec un valgrind =)

  17. #17
    Expert confirmé

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

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 615
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par alexglvr Voir le message
    Pourtant entre les deux je fais une libération mémoire....

    Bon, je vais réfléchir à une solution moins gourmande en mémoire...
    ne jamais oublier que free ne libère pas réellement la mémoire, sauf si c'est la toute dernière partie de la mémoire.. Schéma déjà donné de multiples fois...

    Une manière de faire qui, bin que ne garantissant pas la vraie libération, la favorise (si il n'y a pas d'autres allocation ailleurs entretemps), c'et de libérer en sens inverse de l'allocation : commencer par la fin...

Discussions similaires

  1. Liste chainée en mémoire partagée
    Par drogeek dans le forum C
    Réponses: 2
    Dernier message: 21/05/2013, 08h13
  2. Liste chainé et fuite mémoire
    Par poussinphp dans le forum C++
    Réponses: 2
    Dernier message: 26/04/2007, 00h06
  3. mémoire et liste chainée?
    Par tintin72 dans le forum C++
    Réponses: 17
    Dernier message: 17/12/2005, 21h54
  4. Réponses: 24
    Dernier message: 30/10/2005, 10h27
  5. tri de liste chainée
    Par RezzA dans le forum C
    Réponses: 7
    Dernier message: 26/01/2003, 21h25

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