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 :

Liste Chaînée | Question sur malloc/free


Sujet :

C

  1. #1
    Membre du Club
    Homme Profil pro
    Agronome
    Inscrit en
    Septembre 2018
    Messages
    97
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Belgique

    Informations professionnelles :
    Activité : Agronome
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Septembre 2018
    Messages : 97
    Points : 60
    Points
    60
    Par défaut Liste Chaînée | Question sur malloc/free
    Bonjour, savez vous si le exit(EXIT_FAILURE) est une façon propre de finir une fonction quand dans mon cas j'alloue dynamiquement mais que je ne peux pas libérer la mémoire à la fin de cette 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
    /**
    * Ajoute un time/player/score en fin de Liste
    * @param temps, pointeur vers un nombre x(TIME_ARG) d'entiers.
    * @param liste La liste.
    * @param player, pointeur vers une chaîne de characters à insérer.
    * @param score l'entier à insérer.
    * @return La liste avec les nouveaux élements ajoutés.
    */
    p_list push_back_list(p_list liste, int temps[], char *player, int score) {
      	t_classements *nouveau_score ; /* nouveau score de type classements. */
        nouveau_score = malloc(sizeof(*nouveau_score));
        nouveau_score->classement = malloc(sizeof(*nouveau_score->classement));
        nouveau_score->classement->temps = malloc(sizeof(*nouveau_score->classement->temps) * TIME_ARG);
        unsigned int taille_chaine = strlen(player);
        nouveau_score->classement->nom = malloc(sizeof(*nouveau_score->classement->nom) * taille_chaine);
      	if(nouveau_score == NULL || nouveau_score->classement == NULL || nouveau_score->classement->nom == NULL){
          	fprintf(stderr, "Erreur : probleme allocation dynamique.\n");
          	exit(EXIT_FAILURE);
    	  }
        strcpy(nouveau_score->classement->nom, player);
        nouveau_score->classement->temps = temps;
        nouveau_score->classement->score = score;
      	(*nouveau_score).next = NULL ; /* initialiser l'élément suivant à NULL */
    	  if(is_empty_list(liste)){
            return nouveau_score;
        }
        t_classements *temp;
        temp = liste;
      	while(temp->next != NULL) {
            temp = temp->next;
        }
      	temp->next = nouveau_score;
      	return liste; /* retourne l'adresse du nouveau_score. */
    }

  2. #2
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 452
    Points : 43 099
    Points
    43 099
    Par défaut
    exit() va interrompre ton programme. Si c'est le comportement attendu, c'est ok. Quand un programme qui se termine, son espace mémoire est libéré, que tu es utilisé free ou non sur toutes tes allocations.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  3. #3
    Membre expérimenté
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    543
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 543
    Points : 1 745
    Points
    1 745
    Par défaut
    Bonsoir, comme il a été dit, sortir d'une fonction avec exit() veut dire interrompre l'exécution du programme et redonner le contrôle au système d'exploitation en lui signifiant les raisons de l'interruption du programme par un code retour.

    Vous pouvez utiliser exit() pour pouvoir sortir non pas de la fonction, mais interrompre le programme dû à une erreur ou raison qui justifie son emploi. Dans le cas actuel, il n'y a pas d'erreur d'allocation qui justifie l'emploi de exit() on fait donc remonter l'information à la fonction appelante par un simple return bidule (au choix). Ceci dit vu le type que votre fonction retourne à moins que ça soit un pointeur caché il y a forte chance a parié que l'on fonce droit vers un échec de compilateur.

    à bientôt
    Celui qui peut, agit. Celui qui ne peut pas, enseigne.
    Il y a deux sortes de savants: les spécialistes, qui connaissent tout sur rien,
    et les philosophes, qui ne connaissent rien sur tout.
    George Bernard Shaw

  4. #4
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par Magnum8760 Voir le message
    savez vous si le exit(EXIT_FAILURE) est une façon propre de finir une fonction
    Serais-tu heureux si fopen() ou malloc() interrompaient ton programme quand ils n'arrivent pas à faire les opérations demandées ?

    On ne sort jamais d'une sous-fonction par exit. Les fonctions partent et s'empilent à partir du main(), elles doivent se terminer et se dépiler jusqu'au main() qui, seul, aura le droit de quitter.

    Et si une fonction se trouve coinçée par une erreur insoluble sans solution de remplacement, alors elle remonte son échec à la fonction appelante qui se trouvera alors dans la même situation avec le même choix à faire. Et etc jusqu'au main().

    Citation Envoyé par chrtophe Voir le message
    Quand un programme qui se termine, son espace mémoire est libéré
    Pas sur tous les OS !!!
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    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
    Citation Envoyé par Sve@r Voir le message
    On ne sort jamais d'une sous-fonction par exit.
    Évidemment; quand ça pète on doit sortir avec abort() à la place. 🚎

    Plus sérieusement, dans un exercice qui ne porte pas sur la gestion d'erreurs, ou un programme "one-shot", il est acceptable de faire suicider le programme à la première erreur (tant qu'on en profite pour la signaler).
    Par contre, sur un programme professionnel, on a besoin d'une vraie gestion des erreurs (pas de chance, le C est un des pires langages pour ça). Et là on retombe sur ce que dit Sve@r:
    Les fonctions partent et s'empilent à partir du main(), elles doivent se terminer et se dépiler jusqu'au main() qui, seul, aura le droit de quitter.

    Et si une fonction se trouve coinçée par une erreur insoluble sans solution de remplacement, alors elle remonte son échec à la fonction appelante qui se trouvera alors dans la même situation avec le même choix à faire. Et etc jusqu'au main().
    Ce qui veut dire, tester le retour de chaque malloc(), fopen(), etc., et en cas d'échec, retourner à la fonction appelante une valeur indiquant que ça a échoué, etc. Décider aussi à quel(s) moment(s) signaler l'erreur à l'utilisateur (il ne faut pas que le programme se termine "silencieusement" quand il échoue).
    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.

  6. #6
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 452
    Points : 43 099
    Points
    43 099
    Par défaut
    Pas sur tous les OS !!!
    Peux-tu développer ?
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  7. #7
    Membre du Club
    Homme Profil pro
    Agronome
    Inscrit en
    Septembre 2018
    Messages
    97
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Belgique

    Informations professionnelles :
    Activité : Agronome
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Septembre 2018
    Messages : 97
    Points : 60
    Points
    60
    Par défaut
    Les fonctions partent et s'empilent à partir du main(), elles doivent se terminer et se dépiler jusqu'au main() qui, seul, aura le droit de quitter.
    Et si une fonction se trouve coinçée par une erreur insoluble sans solution de remplacement, alors elle remonte son échec à la fonction appelante qui se trouvera alors dans la même situation avec le même choix à faire. Et etc jusqu'au main().
    Ok merci beaucoup. Le C ne possède pas de mécanisme de ramasse-miettes !

    Ici ma fonction prend divers variables structurées et alloue une seul variable à la fois et si ça ne va pas on tue le programme (exit(EXIT_FAILURE), exit(1)... tout ça c'est un peu pareil ici, on quitte le programme.). Donc si ça ne va pas on quitte mais sinon, existe t-il des mécanismes de survie, je pense que non ? Pourtant, pas le choix, la taille des variables doit être connue à la compilation et en plus j'ai cru comprendre que la taille peux varier d'un compilateur à l'autre ! Souvent je préfère encore créer un bon vieux tableau partiel qui ne nécessite pas de free ou même de ré-initialiser mon pointeur avec NULL (ici, il faudrait le faire en dehors de ma sous fonction, je ne vois pas comment sinon) .

    Ceci dit vu le type que votre fonction retourne à moins que ça soit un pointeur caché il y a forte chance a parié que l'on fonce droit vers un échec de compilateur.
    La fonction est un pointeur qui retourne la'dresse d'un nouvel élément d'une liste chaînée. La structure est définie dans mon fichier d'en tête.

    elle est du style :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    typedef struct s_liste{
        int*time;
        char*player;
        int score;
    } t_liste, *p_liste;
    Pas sur tous les OS !!!
    Oui c'est justement pour ça qu'on libère la mémoire avant de quitter, c'est pour éviter les fuites. Je ne vois nulle part que le système libère la mémoire à la fin d'un processus. Ils peuvent peut être laisser les valeurs et ne plus y toucher (ce qui engendrait une faille de sécurité). Certes les OS de maintenant sont sûrs (du moins je l'espère Oo) mais n'étant pas sûr...

    De plus certaines allocations ne sont pas forcément libérées par le système à la fin d'un processus (ouverture de socket par exemple).

    EXIT_SUCCESS (0) et EXIT_FAILLURE (1) sont des define, ils représentent la valeur d'une réussite ou d'une erreur.
    on peut écrire 0 ou 1 mais dans un soucis de portabilité, les define sont conseillés (si l'OS est configuré pour dire 1 = réussi et 0 = erreur )

    Je pense que mon programme est trop petit pour que la valeur de retour ait une importante. Si par contre ton programme est appelé par d'autre, la valeur de retour sert de test au bon déroulement

    De plus, la différence entre return EXIT_SUCCESS et exit(EXIT_SUCCESS) est que le return quitte la fonction, tandis qu'exit quitte le programme ...

  8. #8
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par chrtophe Voir le message
    Peux-tu développer ?
    Volontiers.
    Le C n'est pas que pour Unix/Linux. Il existe aussi sous Windows et de vieilles versions (comme XP) ne libèrent pas la RAM allouée et non "freeée". Et je connais au-moins un magasin qui est encore sous XP (bien qu'il n'utilise pas de trucs faits en C). Pourquoi ? Ben déjà pour ce qu'il fait (navigation, commandes, etc) il n'a pas besoin d'autre chose (quoique récemment j'ai eu un souci avec son firefox qui était trop vieux mais qui ne pouvait pas être mis à jour sur XP et qui refusait d'aller sur Amazon car il n'arrivait pas à authentifier ce site avec ses certificats récents => je leur ai mis un firefox portable) et surtout il n'a pas les ronds pour acheter W10 (et comme c'est un magasin, pas question de le pirater).
    Il peut aussi être implémenté sur des microcontroleurs robotiques ou autres et là aussi je ne suis pas certain que ces trucs libèrent le tout quand le programme s'arrête.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  9. #9
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 452
    Points : 43 099
    Points
    43 099
    Par défaut
    Sous Windows 3.1 je veux bien, mais sous Windows XP... l'appel de exit déclenche la destruction du processus, donc la libération de ses zones mémoires.

    C'est quand-même pas un stagiaire qui a codé le gestionnaire de mémoire virtuelle.

    C'est un problème référencé ?
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  10. #10
    Membre expérimenté
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    543
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 543
    Points : 1 745
    Points
    1 745
    Par défaut
    Citation Envoyé par chrtophe
    Sous Windows 3.1 je veux bien, mais sous Windows XP... l'appel de exit déclenche la destruction du processus, donc la libération de ses zones mémoires.
    C'est quand-même pas un stagiaire qui a codé le gestionnaire de mémoire virtuelle.
    C'est un problème référencé ?
    Oui et tout système d’exploitation (que ce soit Windows XP à 10 et NT) embarque un mécanisme noyau permettant de libérer la mémoire après utilisation même le DOS à travers les interruptions système. Cependant le mécanisme de DOS reste un cas particulier. Il n’y a pas vraiment de mécanisme à proprement parlé qui gère la libération de ressources après la fermeture de l’application puisque ce dernier utilise un mécanisme qui lui est propre tel que le TSR (Terminate but Stay Resident) grâce aux l’appels système (INT sans parler de DPMS / EMS qui est autre chose).

    Plus en détail, lorsqu'un programme est chargé par le DOS, il est attribué un ou plusieurs segments de mémoire et le DOS ne peut qu'exécuter une seule application à la fois, car il est mono-tache. Lors de l’arrêt d’exécution de l’application et selon l’appel système employé, l'exemple d’appels système « INT 21H/4CH », la mémoire et les ressources vont alors être marqués comme inutilisés ce qui paralyse le programme et donc ne permet pas le redémarrer ou exécuter sans charger le programme totalement en mémoire de nouveau.

    Au cas où le programme se termine avec l’appel système 21H/31H, DOS va tout simplement décharger une partie des ressources spécifiques du contexte d’exécution du programme (ça peut être les ressources allouées que DOS ne va pas réutiliser), mais en revanche si c’est un appel aux interrupteurs 27H, le programme se termine mais reste en mémoire résident (d’où on parle réellement de TSR). Dans les versions mises à jour de DOS telles que 2.0, l’appel 21h a été amélioré, on parle alors de maintien de processus (Keep Process).

    Citation Envoyé par Sve@r Voir le message
    Volontiers.
    Le C n'est pas que pour Unix/Linux. Il existe aussi sous Windows et de vieilles versions (comme XP) ne libèrent pas la RAM allouée et non "freeée". Et je connais au-moins un magasin qui est encore sous XP (bien qu'il n'utilise pas de trucs faits en C).

    En soit, tout système d’exploitation avec un mécanisme de gestion de memoire (MMU) voit la libération des ressources différemment, il ne faut pas faire une généralité : il ne faut pas confondre la libération de la mémoire utilisée par l’application dans son contexte d’exécution et la récupération intégrale de la mémoire par le noyau des ressources qu’il a attribué au programme ; les mécanismes sont différents.
    Il y a une gestion mémoire du point de vue kernel dans lequel le système d’exploitation va mettre à disposition de l’application un environnement de fonctionnement qui lui est nécessaire (contexte d’exécution) dans lequel l’application va exécuter son code, allouer de la memoire avec malloc et libérer avec free et admettant que l’on ne fasse pas de free au moment de quitter (ou que l’on quitte par d’autre moyen). Le noyau va récupérer ce qu’il a prêté (et tout ce qui est tas, pile, section code, bss etc.. de l’application free) et restituer au kernel. Ce qui garantit qu’il ne peut y avoir de fuite mémoire possible par la suite. Les seules fuites mémoire possibles se produisent en cours d’execution du programme, ce qui peut aller jusqu’à causer le crash du système si les ressources viennent à manquer.

    Quant au système d’exploitation, pour l’embarqué ou système d’exploitation "exotique", ils n’appliquent pas forcément ce même principe selon leur domaine d’application (Cas pour l’embarqué qui ne libère pas obligatoirement la mémoire ou seulement si le système ce vois redémarrer). Quant au système d’exploitation exotique, tout dépendant de celui qui écrit le kernel, mais aussi la norme qui implémente.

    Citation Envoyé par Magnum8760 Voir le message
    Le C ne possède pas de mécanisme de ramasse-miettes !. Donc si ça ne va pas on quitte mais sinon, existe t-il des mécanismes de survie, je pense que non ?
    Effectivement, on ne peut pas parler de mécanisme de survie, mais il vous est possible à votre niveau d’utiliser les routines telles que atexit, atexit_bou on_exit qui sont appelés automatiquement quand vous quitter votre application par return ou exit(x) et qui exécute une fonction qui vous est propre pour par exemple free les différents mémoires alloués.


    (Exemple sans compilation et qui peut comporter des erreurs).


    Code C : 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
     
    size_t offset;
    void *tabMem[10];
     
     
    void f_freeAllMem( void ){
     
        for( size_t i = offset; -1 != i; i-- ){
            if( NULL != tabMem[i] ){
                free( tabMem[i] );
                tabMem[i] = NULL;
            }
        }
        (void)puts("Free auto done");
    }
     
     
    void *f_alloMem( size_t i ){
        void *p = malloc( i );
        if( NULL == p )
            return NULL;
        tabMem[offset++] = p;
        return (p);
    }
     
     
    int main( void ){
        void* dt = NULL;
        if( 0 != atexit((f_freeAllMem))){
            (void)fprintf(stderr,
                        "Erreur application de l'auto free\n");
            abort();    //
        }
        if( NULL == (dt = f_alloMem(10) ) )
            return (EXIT_FAILURE);
        return EXIT_SUCCESS;
    }


    ou
    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
     
    void f_deletMem( int dtCode, void *ptr ){
     
        (void)dtCode;   // mut
        if( NULL != ptr ){
            free( ptr );
            ptr = NULL;
        }
        ptr = NULL;
    }
     
     
    void *f_alloMem( size_t i ){
        void *p = malloc( i );
        return (p == NULL) ? NULL : p;
    }
     
     
    int main( void ){
        void* dt = NULL;
     
        if( NULL == (dt = f_alloMem(10) ) )
            return (EXIT_FAILURE);
     
        if( 0 != on_exit(f_deletMem, dt ) ){
            (void)fprintf(stderr, "Erreur free auto\n");
            abort();
        }
     
        return EXIT_SUCCESS;
    }



    à bientôt.
    Celui qui peut, agit. Celui qui ne peut pas, enseigne.
    Il y a deux sortes de savants: les spécialistes, qui connaissent tout sur rien,
    et les philosophes, qui ne connaissent rien sur tout.
    George Bernard Shaw

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

Discussions similaires

  1. question sur malloc
    Par Elstak dans le forum C
    Réponses: 6
    Dernier message: 10/05/2007, 19h21
  2. une question sur malloc()
    Par marocleverness dans le forum C
    Réponses: 5
    Dernier message: 02/05/2006, 20h26
  3. question sur malloc
    Par MegaNono dans le forum C
    Réponses: 15
    Dernier message: 01/05/2006, 14h24
  4. Question sur malloc
    Par mikedavem dans le forum C
    Réponses: 4
    Dernier message: 14/04/2006, 08h22
  5. Encore une question sur malloc
    Par IG88 dans le forum C
    Réponses: 5
    Dernier message: 23/06/2004, 15h35

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