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 :

Questions d'un novice sur les « infâmes » pointeurs


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Avatar de VivienD
    Homme Profil pro
    Développeur logiciel
    Inscrit en
    Octobre 2009
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Développeur logiciel
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2009
    Messages : 523
    Par défaut Questions d'un novice sur les « infâmes » pointeurs
    Bonsoir,

    J'ai eu quelques cours sur les bases de la programmation en C, où l'on a abordé de manière succincte le thème concernant les pointeurs. Je souhaite en fait enrichir mes connaissances en la matière et je me suis vite rendu compte que les pointeurs, aussi infâmes puissent-ils être, sont en réalité des outils indispensables. Toutefois j'ai beau consulter différentes sources mais quelques zones d'ombre persistent, et je n'aime pas ça. C'est pourquoi je fais appel à votre aide. Avant de poser les questions que me viennent en tête je précise que, à chaque fois que j'aurai une question à propos des pointeurs, je m'amuserai à faire l'archéologue et je déterrerai ce sujet. En revanche, si d'autres novices sont aussi embêtés que moi en ce qui concerne ce thème, ils peuvent bien évidemment poser leurs questions dans ce sujet.

    Assez parlé, voici les questions :

    [1] - Comment choisir le type du pointeur ? Est-ce qu'il doit concorder avec le type de la variable à pointer ? Est-ce que ça dépend du processeur (par exemple, long *pTruc; pour les processeur 32 bits) ? Est-ce que ça dépend d'autre chose ?

    [2] - Comment pointer un tableau multidimensionnel ?

    C'est tout pour aujourd'hui, mais ne soyez pas déçus car il y en aura d'autres.

    Merci d'avance.

    Adishatz !

  2. #2
    Membre émérite
    Inscrit en
    Juillet 2005
    Messages
    512
    Détails du profil
    Informations forums :
    Inscription : Juillet 2005
    Messages : 512

  3. #3
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 485
    Par défaut
    Bonsoir,

    Citation Envoyé par VivienD Voir le message
    Assez parlé, voici les questions :

    [1] - Comment choisir le type du pointeur ? Est-ce qu'il doit concorder avec le type de la variable à pointer ? Est-ce que ça dépend du processeur (par exemple, long *pTruc; pour les processeur 32 bits) ? Est-ce que ça dépend d'autre chose ?
    En fait, les pointeurs ne sont pas un concept abstrait propre au C. Il s'agit en fait d'une variable qui contient une adresse en mémoire. Si le concept d'adresse en mémoire ne t'est pas familier, dis-le nous, on commencera par là mais, a priori, tu as l'air de connaître quand même les grandes lignes du fonctionnement de ta machine.

    Ceci posé, on comprend que n'importe quel objet, lorsqu'il est instancié quelque part en mémoire, a donc forcément une adresse et, donc, tu peux pointer n'importe quoi, quelque soit sa taille. Le format du pointeur, lui, va effectivement varier d'une architecture à l'autre mais c'est ton compilateur qui va gérer cela pour toi. À dire vrai, c'est même pour cela que l'on a créé un type « pointeur » : il décrit de manière implicite le format de l'adressage de la machine-cible. Le programmeur n'a donc plus à s'en soucier et son code devient portable.

    [2] - Comment pointer un tableau multidimensionnel ?
    Question pas facile. :-) Surtout pour commencer !

    En fait, on le déclare suivant le même principe qu'un pointeur de fonction. Les pointeurs de tableaux et de fonctions sont ce qu'il y a de plus compliqué dans ce domaine. Je te les montre donc simplement pour répondre à ta question et satisfaire ta curiosité. Il va sans dire que commencer par là n'a rien de pédagogique.

    En gros, tu peux indexer un pointeur comme s'il s'agissait d'un tableau puisque l'on peut aisément y déduire la position d'un élément de rang n : il suffit de partir de l'adresse donnée par le pointeur et d'y ajouter n fois la taille de cet élément.

    D'autre part, tu n'es pas obligé de connaître la taille de ce tableau pour faire ces calculs et le parcourir. C'est nécessaire, en revanche, pour éviter de le dépasser mais ça, c'est un autre problème. Par contre, dans un tableau multidimensionnel, tu peux ignorer la longueur de la première dimension (la plus grande), mais tu dois obligatoirement connaître celle des suivantes puisque ce sont elles qui vont définir le « pas ».

    Tu vas donc faire de même : pour un tableau tridimensionnel, par exemple, tu vas définir un pointeur avec « * », que tu vas ensuite qualifier avec les deux dernières dimensions dûment renseignées. Tu affectes ensuite l'adresse de ton tableau à ce pointeur, et le fait de l'indexer formera naturellement ta dimension principale, comme si tu utilisais le tableau original.

    Ça a l'air très savant dit comme cela, mais ça passe beaucoup mieux avec un exemple :

    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
    #include <stdio.h>
     
    int main (void)
    {
        int i,j,k;
        int (*ptr)[3][4];
        int tab [2][3][4] = { { {  1, 2, 3, 4 } , {  5, 6, 7, 8 } , {  9,10,11,12 } },
                              { { 13,14,15,16 } , { 17,18,19,20 } , { 21,22,23,24 } } };
     
        for (i=0;i<2;++i)
        for (j=0;j<3;++j)
        for (k=0;k<4;++k) printf ("%d %d %d : %d\n",i,j,k,tab[i][j][k]);
     
        ptr = tab;
     
        for (i=0;i<2;++i)
        for (j=0;j<3;++j)
        for (k=0;k<4;++k) printf ("%d %d %d : %d\n",i,j,k,ptr[i][j][k]);
     
        return 0;
    }

  4. #4
    Membre éclairé
    Avatar de VivienD
    Homme Profil pro
    Développeur logiciel
    Inscrit en
    Octobre 2009
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Développeur logiciel
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2009
    Messages : 523
    Par défaut
    À Lucien63 : j'avais déjà consulté le lien que tu proposes.

    À Obsidian :
    [1] - Alors, si j'ai bien compris cette affaire-ci, je peux mettre short *pTruc;, int *pTruc;, long *pTruc;, voire long long *pTruc;, quelle que soit l'architecture du processeur, sans que ça n'occasionne de pertes de données.

    [2] - Est-il alors possible de créer un pointeur qui vaudra &tab[0][0][0]...[0], et d'accéder aux autres éléments du tableau multidimensionnel par une simple incrémentation de la valeur du pointeur, comme avec les vecteurs ?

  5. #5
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    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 835
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par VivienD Voir le message
    À Obsidian :
    [1] - Alors, si j'ai bien compris cette affaire-ci, je peux mettre short *pTruc;, int *pTruc;, long *pTruc;, voire long long *pTruc;, quelle que soit l'architecture du processeur, sans que ça n'occasionne de pertes de données.
    Exactement. En fait, en mettant par exemple int *pt, tu indiques au compilateur que l'élément pointé (*pt) est un int. Ainsi, si plus tard tu demandes affiche *pt, le compilo ira à l'adresse pt et récupèrera 4 octets pour avoir la valeur exacte de l'int. Sans ça, il ne saurait pas combien d'octets récupérer. C'est tout...

    Citation Envoyé par VivienD Voir le message
    [2] - Est-il alors possible de créer un pointeur qui vaudra &tab[0][0][0]...[0], et d'accéder aux autres éléments du tableau multidimensionnel par une simple incrémentation de la valeur du pointeur, comme avec les vecteurs ?
    Exactement. Voici un court exemple d'affichage de tableau
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    int tab[10]={0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    int i;
    int *pt;
     
    // Affichage des éléments par leur indice
    for (i=0; i < 10; i++)
        printf("L'élément %d vaut %d\n", i, tab[i]);
     
    // Affichage des éléments en passant par un pointeur contenant leur adresse successive
    for (i=0, pt=tab; i < 10; i++, pt++)
        printf("L'élément %d vaut %d\n", i, *pt);

    La seconde boucle est un poil plus rapide car chaque fois que tu invoques tab[i], le compilo se place au début du tableau pour décaler ensuite de i positions. Alors que dans la seconde boucle, j'ai simplement stocké l'adresse du début que je décale. Bien sûr pour un simple tableau d'entiers c'est pas très flagrant mais cela commence à être intéressant quand on doit parcourir des tableaux de structures.

    Toutefois, un petit bémol: il est facile et instantané de passer d'un tableau 1D vers un pointeur, cela devient un peu plus difficile dans le cas de tableaux multi dimensionnels. C'est dû au fait que la mémoire, elle, reste sous forme de liste d'adresses en 1 dimension. Donc pour l'instant, tant que t'es pas trop à l'aise, il vaut mieux faire tes tests avec des tableaux 1D...
    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]

  6. #6
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 485
    Par défaut
    Citation Envoyé par VivienD Voir le message
    À Obsidian :
    [1] - Alors, si j'ai bien compris cette affaire-ci, je peux mettre short *pTruc;, int *pTruc;, long *pTruc;, voire long long *pTruc;, quelle que soit l'architecture du processeur, sans que ça n'occasionne de pertes de données.
    Absolument.

    Mais il est quand même important de souligner que ce n'est pas le pointeur qui va contenir la donnée dont tu énumères les types ici. Ton pointeur ne contient qu'une indication de l'emplacement de la donnée pointée dans la mémoire. Dès lors, tu peux pointer n'importe quoi, que ta donnée tienne en un seul octet ou qu'elle en occupe mille.

    Dans tout les cas, l'adresse délivrée par le pointeur est celle du premier octet de ta donnée (celui dont l'adresse est la plus petite, donc).

    À noter également qu'au départ, un pointeur ne contient aucune adresse valide. C'est à toi de l'initialiser avec l'adresse de quelque chose qui existe déjà.

    [2] - Est-il alors possible de créer un pointeur qui vaudra &tab[0][0][0]...[0], et d'accéder aux autres éléments du tableau multidimensionnel par une simple incrémentation de la valeur du pointeur, comme avec les vecteurs ?
    Il n'y a pas de « vecteur » en C. Ça dépend donc de ce que tu entends par ce mot (comprendre : au sens mathématique ou au sens « C++ ») mais oui, tu peux incrémenter le pointeur, soit avec les opérateurs arithmétiques (ex : « ptr + 2 »), soit avec les opérateurs de pré/post in/dé-crémentation, tels que « ptr++ ».

    Encore une fois, sur un tableau tridimensionnel, c'est un peu délicat, mais sur tous les tableaux à une seule dimension — et spécialement les chaînes de caractères — c'est très largement employé.

    Dans le cas d'un tableau multidimensionnel, ton pointeur représente la plus grande dimension. Chaque « élément » pointé est alors en fait un sous-tableau privé de la première dimension. Cela forme donc une expression de type « tableau », que tu exploites comme un tableau ordinaire.

    Essaie de compiler et d'exécuter le programme que je t'ai donné en exemple. Tu peux aussi essayer d'y ajouter les lignes suivantes, juste avant l'instruction « return » :

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        printf ("%d\n",(*ptr)[0][0]);
        ptr++;
        printf ("%d\n",(*ptr)[0][0]);

  7. #7
    Membre éclairé
    Avatar de VivienD
    Homme Profil pro
    Développeur logiciel
    Inscrit en
    Octobre 2009
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Développeur logiciel
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2009
    Messages : 523
    Par défaut
    [1] - Maintenant j'ai exactement compris comment il faut dimensionner mes pointeurs. Merci.

    [2] -
    Citation Envoyé par Sve@r Voir le message
    Exactement. Voici un court exemple d'affichage de tableau
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    int tab[10]={0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    int i;
    int *pt;
     
    // Affichage des éléments par leur indice
    for (i=0; i < 10; i++)
        printf("L'élément %d vaut %d\n", i, tab[i]);
     
    // Affichage des éléments en passant par un pointeur contenant leur adresse successive
    for (i=0, pt=tab; i < 10; i++, pt++)
        printf("L'élément %d vaut %d\n", i, *pt);

    La seconde boucle est un poil plus rapide car chaque fois que tu invoques tab[i], le compilo se place au début du tableau pour décaler ensuite de i positions. Alors que dans la seconde boucle, j'ai simplement stocké l'adresse du début que je décale. Bien sûr pour un simple tableau d'entiers c'est pas très flagrant mais cela commence à être intéressant quand on doit parcourir des tableaux de structures.

    Toutefois, un petit bémol: il est facile et instantané de passer d'un tableau 1D vers un pointeur, cela devient un peu plus difficile dans le cas de tableaux multi dimensionnels. C'est dû au fait que la mémoire, elle, reste sous forme de liste d'adresses en 1 dimension. Donc pour l'instant, tant que t'es pas trop à l'aise, il vaut mieux faire tes tests avec des tableaux 1D...
    Citation Envoyé par Obsidian Voir le message
    Il n'y a pas de « vecteur » en C. Ça dépend donc de ce que tu entends par ce mot (comprendre : au sens mathématique ou au sens « C++ ») mais oui, tu peux incrémenter le pointeur, soit avec les opérateurs arithmétiques (ex : « ptr + 2 »), soit avec les opérateurs de pré/post in/dé-crémentation, tels que « ptr++ ».

    Encore une fois, sur un tableau tridimensionnel, c'est un peu délicat, mais sur tous les tableaux à une seule dimension — et spécialement les chaînes de caractères — c'est très largement employé.

    Dans le cas d'un tableau multidimensionnel, ton pointeur représente la plus grande dimension. Chaque « élément » pointé est alors en fait un sous-tableau privé de la première dimension. Cela forme donc une expression de type « tableau », que tu exploites comme un tableau ordinaire.

    Essaie de compiler et d'exécuter le programme que je t'ai donné en exemple. Tu peux aussi essayer d'y ajouter les lignes suivantes, juste avant l'instruction « return » :

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        printf ("%d\n",(*ptr)[0][0]);
        ptr++;
        printf ("%d\n",(*ptr)[0][0]);
    J'ai la (mauvaise) habitude de nommer « vecteur » toute matrice et tout tableau n'ayant qu'une dimension.
    En revanche, je vais étudier la question posément et en attendant de maîtriser ce point j'utiliserai des tableaux unidimensionnels (je me demande si c'est bien français, ce que je dis là). En tout cas, merci encore.

    J'allais dire « à plus pour d'autres questions » mais deux questions me viennent à l'esprit.

    [3] - Qu'est-ce qu'un pointeur de fonction ? À quoi est-ce que ça sert concrètement ?

    [4] - Quelle(s) particularité(s) a le pointeur **pMachin ?

  8. #8
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    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 835
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par VivienD Voir le message
    [3] - Qu'est-ce qu'un pointeur de fonction ?
    Une fonction a aussi une adresse. L'adresse de la zone mémoire où elle commence. On peut donc stocker cette adresse dans un pointeur. Et ensuite, on peut l'appeler en passant par le pointeur.

    Citation Envoyé par VivienD Voir le message
    À quoi est-ce que ça sert concrètement ?
    Ca sert chaque fois que tu veux faire un traitement automatisé mais pas forcément connu au moment où tu le programmes (ça peut arriver)

    Par exemple il existe dans la librairie une fonction universelle "qsort()" permettant de trier un tableau de n'importe quoi (selon les désirs de celui qui utilise cette fonction). Mais "trier" quelque chose implique de savoir comment comparer deux "quelque chose". Et celui qui a écrit qsort() ne savait évidemment pas ce que celui qui va l'utiliser va vouloir trier. Donc il ne pouvait pas écrire le code permettant de comparer puisqu'il ne sait pas ce qui sera à trier.
    Donc c'est à l'utilisateur qui désire utiliser cette fonction (et qui sait donc ce qu'il manipule et comment les comparer) de le faire. Il n'a qu'à écrire une fonction permettant de comparer 2 éléments selon une directive simple
    - la fonction doit être prévue pour recevoir 2 adresses (les adresses des choses à comparer)
    - la fonction doit renvoyer -1 si l'élément 1 est plus petit que l'élément 2, 1 s'il est plus grand ou 0 s'ils sont égaux.
    Ensuite, l'utilisateur n'a plus qu'à passer l'adresse de cette fonction à la fonction qsort() qui (ayant stocké cette adresse dans un pointeur à elle) pourra l'appeler et saura ainsi comment comparer 2 éléments et pourra faire le tri du tableau.

    Autre exemple: on te demande de programmer un traitement encore inconnu (et pouvant changer ensuite) sur un tableau de nombres. Chaque nombre du tableau devra être affiché puis ensuite traité selon le bon vouloir de l'utilisateur et le résultat du traitement devra être affiché.
    Ben tu fais ça avec un pointeur de fonction

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // Le moteur de travail - Reçoit l'adresse du tableau, le nombre d'éléments et un pointeur sur la fonction de traitement (cette fonction recevant elle-même un int et renvoyant aussi un int)
    void moteur (int *tab, int nb, int (*ptfct)(int))
    {
         int i;
     
        // Balayage du tableau
        for (i=0; i < nb; i++)
        {
             // Affichage de l'élément et du résultat du calcul
             printf("Le calcul de %d donne %d\n", tab[i], (*ptfct)(tab[i]));
        }
    }

    Maintenant que le moteur est fait, si tu veux le carré des 10 premiers nombres pairs
    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
    // Il faut d'abord définir comment calculer le carré d'un nombre
    int carre(int n)
    {
        return n * n;
    }
     
    int main()
    {
         // Le tableau de nombres
         int tab[10]={2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
     
         // Le traitement
         moteur(tab, 10, carre);
    }

    Ou alors si tu veux le cube des 15 premiers nombres impairs
    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
    // Il faut d'abord définir comment calculer le cube d'un nombre
    int cube(int n)
    {
        return n * n * n;
    }
     
    int main()
    {
         // Le tableau de nombres
         int tab[15]={1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29};
     
         // Le traitement (toujours le même)
         moteur(tab, 15, cube);
    }

    Comme tu vois, tu n'as pas besoin de toucher au moteur pour faire des traitements divers...

    Citation Envoyé par VivienD Voir le message
    [4] - Quelle(s) particularité(s) a le pointeur **pMachin ?
    Il faut un type devant **. On va dire "int **pMachin". Ben c'est un pointeur contenant l'adresse d'un pointeur contenant lui-même l'adresse d'un int...
    Exemple
    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
    int var;
    int *pt_simple;
    int **pt_double;
     
    pt_simple=&var;
    pt_double=&pt_simple;
     
    var=123;
    printf("La valeur au bout du pt_double vaut %d\n", **pt_double);
    printf("La valeur au bout du pt_simple vaut %d\n", *pt_simple);
    printf("La valeur de la variable vaut %d\n", var);
     
    var=456;
    printf("La valeur au bout du pt_double vaut %d\n", **pt_double);
    printf("La valeur au bout du pt_simple vaut %d\n", *pt_simple);
    printf("La valeur de la variable vaut %d\n", var);
    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]

Discussions similaires

  1. Réponses: 4
    Dernier message: 31/01/2012, 17h36
  2. Question d'ordre général sur les macros sur excel
    Par tzehani dans le forum Macros et VBA Excel
    Réponses: 14
    Dernier message: 29/08/2007, 05h16
  3. [Portlet] Questions d'ordre général sur les portlets
    Par Chabin dans le forum Portails
    Réponses: 1
    Dernier message: 25/06/2007, 23h20
  4. Questions d'ordre general sur les design CSS
    Par Clorish dans le forum Mise en page CSS
    Réponses: 20
    Dernier message: 19/06/2007, 13h20
  5. question (peut-être idiote) sur les vues
    Par LadyArwen dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 26/03/2003, 10h35

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