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 :

[Débutant] utilisation du & salvatrice ou pas...


Sujet :

C++

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 9
    Points : 7
    Points
    7
    Par défaut [Débutant] utilisation du & salvatrice ou pas...
    Voila dans certaines de mes procedures, j'obtenais des resultats faux, alors que tous les calculs y marchaient bien, et que le résultat juste avant la derniere accolade etait correcte...

    En gros dans la procedure tout marchait, mais impossible de sortir les resultat de la procedure... (ce sont des procedure void que j'ecris en faisant :

    void procedure(résultat1,..resultatN, variable1,...variableN)...

    Je me suis apercu qu'en mettant un & devanat résultatI ça marchait bien mieux... mais après ça ne marche pas pour tous les types, car si resultatI est un tableau par exemple, il me dit que c'est illegal de faire un tableau de references...

    Existe-t-il donc un équivalent du "&" pour les tableaux ?


    Merci

  2. #2
    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
    Je me suis apercu qu'en mettant un & devanat résultatI ça marchait bien mieux... mais après ça ne marche pas pour tous les types, car si resultatI est un tableau par exemple, il me dit que c'est illegal de faire un tableau de references...
    Existe-t-il donc un équivalent du "&" pour les tableaux ?
    Ca marchait mieux parce que, dans ce cas, tes variables résultatI désignaient les objets que tu avais passés en argument. Il te fait réfléchir à ça.
    Pour les tableaux, c'est différent : Si tu passes un tableau en argument, la fonction va manipuler les objets d'origine du tableau, donc il suffit dans ce cas de passer tout simplement le tableau.

  3. #3
    Membre éprouvé Avatar de Caine
    Inscrit en
    Mai 2004
    Messages
    1 028
    Détails du profil
    Informations personnelles :
    Âge : 52

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 028
    Points : 1 122
    Points
    1 122
    Par défaut
    Bonjour,
    Le mode de passage par défaut des arguments n'est pas le passage par valeur.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
     
    int Echange(int a, int b) {
     
    int temp = b;
     
    b = a;
    a = temp;
     
    }
    Tu verras si tu testes, que a et b sont inchangé.

    Car dans ce mode de passage des arguments, le compilateur génère de copies des arguments, puis en sortie de fonction recopie les valeurs initiales des arguments. Les arguments ne sont donc pas modifiés.

    Le symbole & permet un passage par valeur, qui évite la solution C des pointeurs.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
     
    int Echange(int& a, int& b) {
     
    int temp = b;
     
    b = a;
    a = temp;
    }

    Ici, int& a passe en argument l'adresse de la variable passée en premier argument.

    Pour mieux comprendre, le code équivalent en C c'est ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
     
    int Echange(int* a, int* b) {
     
    int temp = *b;
     
    *b = *a;
    *a = temp;
    }

  4. #4
    jmv
    jmv est déconnecté
    Membre confirmé Avatar de jmv
    Profil pro
    Enseignant
    Inscrit en
    Mai 2004
    Messages
    395
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Mai 2004
    Messages : 395
    Points : 603
    Points
    603
    Par défaut
    en C++, les arguments sont passés par valeurs, si une fonction modifie un de ses arguments, cette modification se fait sur la valeur de l'argument et non sur la variable d'origine. Exemple, dans le code suivant, n n'est pas modifié.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void f(int arg)
    {
        arg = 0;
    }
     
    int main()
    {
        int n = 1;
        f(n);
        // ici n vaut toujours 1
    }
    Pour qu'une fonction puisse modifier une variable qui lui est externe, elle a besoin de l'adresse de cette variable, et non de sa valeur. Il y a 2 solutions :
    1° avec pointeur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void f(int *arg)
    {
        *arg = 0;
    }
     
    int main()
    {
        int n = 1;
        f(&n);
        // ici n vaut 0
    }
    2° avec référence
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void f(int &arg)
    {
        arg = 0;
    }
     
    int main()
    {
        int n = 1;
        f(n);
        // ici n vaut 0
    }
    Pour les tableaux, c'est différents, il sont toujours passés par adresse, une fonction peut donc modifier les éléments d'un tableau
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void f(int arg[]) // ou void f(int *arg)
    {
        arg[0] = 0;
    }
     
    int main()
    {
        int n[] = {1,2,3,4};
        f(n);
        // ici n[0] vaut 0
    }

  5. #5
    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
    Caine dixit :
    Le mode de passage par défaut des arguments n'est pas le passage par valeur.
    Il y a deux méthodes : le passage par valeur (comme en C) et le passage par référence
    Car dans ce mode de passage des arguments, le compilateur génère de copies des arguments,
    Oui, Le compilateur crée des variables locales initialisées avec la valeur des arguments
    puis en sortie de fonction recopie les valeurs initiales des arguments
    . En sortie de fonction, il n'y a pas de recopie des valeurs initiales des arguments. Il y a destruction des variables locales (y compris les paramètres). Toute modification de la valeur des paramètres modifie les variables locales et donc laisse inchangées les variables passées en argument.

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    180
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 180
    Points : 90
    Points
    90
    Par défaut
    Bon, clairement, les arguments de tes fonctions (ou procédures) sont gérés différement selon qu'ils sont ou non des tableaux!

    Imagine que c'est une barrette de RAM! Ta fonction à deux argument: x et y.

    Tu appelle cette fonction dans le main et tu lui donne en argument a et b

    Il y'a quatres variables et non pas deux dans la mémoire!

    |----|--|----|--|----|--|----|
    --a-------b-------x------y

    Quand tu appelles la fonction x prend la valeur de a et y celle de b!

    Ensuite la fonction bosse sur les variables x et y sans se préoccuper de a et de b!

    Mais si tu met un '&' devant le type, sache que c'est correct du point de vue de la syntaxe mais n'en met pas systématiquement! Réfléchi bien si tu as vraiment besoin de travailler directement sur les variables!
    Donc si tu met un '&' devant le type le programme ne crée pas d'emplacement mémoire x et y mais travaille directment sur a et b.
    Autrement dit si tu écris x=3 dans ta fonction! après appel de cette fonction dans le main a aura pour valeur 3!

    Pour les tableaux c'est un peu différent! Tu n'as pas besoin de mettre le '&' devant le type du tableau, la fonction traville directment sur le tableau passé en argument donc pas besoin de '&'!!

    En espérant t'avoir aidé!

    Spartan03

  7. #7
    Membre émérite
    Avatar de xavlours
    Inscrit en
    Février 2004
    Messages
    1 832
    Détails du profil
    Informations forums :
    Inscription : Février 2004
    Messages : 1 832
    Points : 2 410
    Points
    2 410
    Par défaut
    Attention, le passage de tableau par référence (avec un &) peut etre nécessaire si tu le réalloues : tu le déplaces en mémoire et tu changes la variable du pointeur. Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void putToThree(int* i) {
      i = new int(3);
    }
    Ce code ne changera pas le pointeur (ou le tableau) que tu as passé en paramètre.

    2e truc : j'ai déjà eu des problèmes de copie du résultat : parfois il faut mettre un & devant le type retourné (mais bon là c'est des cas assez tordus).

  8. #8
    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
    xavlours :
    Attention, le passage de tableau par référence (avec un &) peut etre nécessaire si tu le réalloues : tu le déplaces en mémoire et tu changes la variable du pointeur. Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void putToThree(int* i) { 
      i = new int(3); 
    }
    Je ne comprend pas : ceci n'est pas un passage par référence. De plus, le paramètre i est écrasé et devrait être une variable locale. Comme la fonction ne renvoie pas i, l'allocation dynamique part dans la nature. Enfin new int(3) n'alloue pas un tableau ( new int[3] ) mais un int initialisé avec la valeur 3
    2e truc : j'ai déjà eu des problèmes de copie du résultat : parfois il faut mettre un & devant le type retourné (mais bon là c'est des cas assez tordus).
    C'est surtout lorsque la fonction doit retourner un objet (ce qui est une des bonnes raisons des références d'exister)

  9. #9
    Futur Membre du Club
    Inscrit en
    Août 2004
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 5
    Points : 6
    Points
    6
    Par défaut
    le & en C++ permet de créer un alias dans le code. Il est tout a fait légal d'écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    int b;
    int &a = b;
    a et b sont alors exactement le meme objet. Par contre, une fois une référence affectée, tu ne peux pas la changer et une réference ne peux pas etre initialisée par défaut :
    L'avantage aussi de passer une référence (ou un pointeur, l'idée étant tres similaire) est d'éviter un appel au constructeur de copie de l'object que tu passes en paramettre. Prends cette structure en exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    struct Dummy
    {
       const Dummy & Dummy(const Dummy &other )
       { /* realise la copie */
       }
     
       int[1000] m_Array;
    };
    et la fonction suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    int NonNul( const Dummy dummy )
    {
       int nbFound(0);
       for(int i(0); i != 1000; ++i)
       {
          if(dummy.m_Array[i] != 0) ++nbFound;
       }
       return nbFound;
    }
    si tu fais un appel a cette fonction, elle va devoir réaliser une copie complete de l'objet dummy donc du tableau de 1000 int dedans, soit pour un int à 4 byte, 4 kbyte, ce qui prends de la place et du temps.
    en modifiant simplement la définition de la fonction à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    int NonNul( const Dummy &dummy )
    {
       // meme code ...
    }
    tu ne fais qu'une référence à l'objet dummy, ce qui prends la taille d'un pointeur si je me rappelle bien = normalement 4 byte... Le gain de temps et d'espace mémoire est non négligeable.

    en gros tu devrais passer tes variables par référence dans les cas suivant (c'est de tete et au boulot donc y'aura peut etre des oublis):
    - le type n'est pas un scalaire de base.
    - le type n'a pas de constructeur de copie.
    - tu veux modifier l'objet sans devoir passer un pointeur à cet objet (car le déférencement prends plus de temps).

    ce sont les trois principales situations mais il y en a surement d'autre

  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
    Ca$ul :
    en gros tu devrais passer tes variables par référence dans les cas suivant ...
    - tu veux modifier l'objet sans devoir passer un pointeur à cet objet (car le déférencement prends plus de temps).
    Le temps d'exécution ne doit être différent, car la référence va être implantée conmme un pointeur. Ce qui change, c'est la syntaxe d'accès à l'intérieur de la fonction et évite l'écriture explicite des *...
    Personnellement, je préfère souvent pour ce type d'application le passage d'un pointeur car la syntaxe utilisée lors de l'appel montre que la fonction peut modifier l'argument. Avec les références, cela ne se voit pas immédiatement
    Une autre raison, de passer une référence est lorsque la fonction doit renvoyer une référence

  11. #11
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 379
    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 379
    Points : 41 575
    Points
    41 575
    Par défaut
    En fait, il y a deux écoles: les uns préfèrent les pointeurs pour la raison citée par diogene, et viennent souvent du C (comme moi). Pour moi, les références ne servent que lorsque les pointeurs ne marchent pas (redef. d'opérateurs par exemple)

    Les autres préfèrent les références, qui ont l'avantage d'être obligatoires: On ne peut pas passer de référence NULL à une fonction, ce qui évite d'avoir à tester dans la fonction si l'objet passé est NULL ou non. Pour eux, les pointeurs sont à utiliser uniquement là où on ne peut utiliser de référence (arguments optionnels, par exemple).

  12. #12
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 279
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 279
    Points : 11 015
    Points
    11 015
    Par défaut
    Pour les autres, dont je fais parti, documentation et utilisation systématique des const font que les pointeurs seuls sont rares.

    Un paramètre entrant est forcément référence-constante, pointeur-constant, ou pris-par-valeur-et-donc-copié. L'intérêt du pointeur c'est pour l'optionel ou pour quand je désire expliciter la durée de vie de l'objet. Mais là, je peux le prendre juste pointeur car il s'agit de transférer sa responsabilité à un autre objet.

    Un paramètre en "out" ou "in-out" sera documenté comme tel. Et le nom de la fonction fera en sorte de bien signaler le sens de passage.

    A noter de plus qui si il y a une sémantique de valeur l'utilisation de pointeurs me choque généralement et donc j'ai tendance à l'éviter.

    Voilà d'autres points rapides données tard le soir. Il y avait eu un autre fil plus abouti sur le sujet dans le passé.

  13. #13
    Futur Membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 9
    Points : 7
    Points
    7
    Par défaut
    Ouh la merci beaucoup je ne m'attendais pas à tant d'explications, c'est génial !!!

    Bon c'est pas dit que j'assimile tout, mais ça me sera de toute façon très utile !

    Encore merci !

Discussions similaires

  1. [MYSQL] [débutant] utiliser replace avec mysql.pas
    Par alex01pernot dans le forum Bases de données
    Réponses: 2
    Dernier message: 30/08/2006, 21h23
  2. [Débutant] Utiliser un SGBD ou pas (VC++) ?
    Par skual dans le forum Débuter
    Réponses: 7
    Dernier message: 30/01/2006, 14h08
  3. [Débutant] Utilisation du mot clé ASSERT
    Par analysiz dans le forum Eclipse Java
    Réponses: 2
    Dernier message: 29/07/2004, 11h43
  4. [CR8.5] Obligé d'utiliser un sous-rapport ou pas ?
    Par liberio dans le forum SAP Crystal Reports
    Réponses: 2
    Dernier message: 09/06/2004, 18h10
  5. [Débutant] Utilisation de FOP - Register Fonts with FOP
    Par Johnbob dans le forum XML/XSL et SOAP
    Réponses: 4
    Dernier message: 31/01/2004, 00h27

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