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 :

Paramètres de fonctions et pointeurs


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 53
    Par défaut Paramètres de fonctions et pointeurs
    Bonjour à tous,

    J'ai cherché sur le net une façon de faire, mais rien de très probant pour l'instant.

    Donc voila mon problème, j'ai une classe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    class foo {
          int *tmp; // dans le but de faire un vecteur dynamique
    }
    J'initialise la taille de ce vecteur puis je veux le passer à une fonction qui va effectuer des calculs et remplir ce vecteur. Le problème, c'est que je n'arrive pas à passer ce tableau "dynamique" en paramètre de fonction.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    tmp = new int[x];
    foo2(tmp);
    
    void foo2(int *tab) {
         tab[i]=....+....
    }

    J'ai fais un print du pointeur avant l'appel et dans la fonction, je n'ai pas la même adresse. Tmp et tab ne pointent pas vers la même chose.

    Quelqu'un aurait l'amabilité de me montrer comment résoudre ce problème ?

    Merci

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    A moins que tu n'aies d'excellentes raisons de travailler, en interne, avec un pointeur, tu devrais te tourner vers les possibilités offertes par la bibliothèque standard, comme, par exemple, la classe vector, disponible dans l'espace de noms std, par simple inclusion du fichier d'en-tête <vector>.

    Tu t'éviteras en effet tous les problèmes qui peuvent être liés à la gestion "manuelle" de la mémoire allouée dynamiquement, ainsi que ceux liés au risque de dépassement de taille.

    Ceci dit, il existe, en conception orientée objet, la loi demeter qui conseille de veiller à ce qu'une classe n'expose que... le stricte minimum correspondant aux services que l'on peut attendre de celle-ci.

    En l'occurrence, il n'est peut être pas intéressant d'exposer le fait que tes différents entiers soient gérés en interne sous la forme d'un tableau "C style" (basé sur un pointeur) ou (si tu suis mon conseil) sous la forme d'un std::vector<int>.

    On peut (mieux: on devrait) en effet s'interroger sur l'intérêt qu'il pourrait y avoir à essayer de "cacher" le pointeur (ou le vecteur) en le faisant passer dans l'accessibilité si c'est pour permettre par ailleurs à l'utilisateur d'y accéder et de le manipuler, surtout si c'est pour y apporter des modifications... sans aucun contrôle.

    L'idéal est donc de fournir une série de fonctions membres qui... présentent l'ensemble de ce que l'utilisateur peut faire avec la classe.

    Ainsi, tu pourrais, selon le cas, prévoir les fonctions
    • permettant d'ajouter un élément en fin de tableau
    • permettant d'obtenir l'élément se trouvant à un indice donné
    • permettant d'obtenir un "itérateur" en lecture seule sur le premier élément
    • permettant d'obtenir un itérateur en lecture seule sur "ce qui suit le dernier élément" (ce qui te permettra avec la fonction juste au dessus de créer des boucles sur l'ensemble des éléments)
    • permettant d'obtenir un "itérateur" en écriture sur le premier élément, pour autant que cela ait un sens
    • permettant d'obtenir un itérateur en écrituresur "ce qui suit le dernier élément", pour autant que cela ait un sens (ce qui te permettra avec la fonction juste au dessus de créer des boucles sur l'ensemble des éléments)
    • permettant de récupérer le nombre d'éléments contenu dans le tableau
    • permettant de vider intégralement le tableau (pour autant que cela ait un sens)
    • ...
    Toutes ces fonctions auront pour objectif le fait de cacher la manière dont tes différents int sont gérés, et participeront au respect d'un autre principe nommé OCP (Open Close Principle) qui conseille de veiller à ce qu'un code soit ouvert aux évolutions mais fermé aux modifications.

    Au final, ta classe pourrait ressembler à quelque chose de fort proche de
    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    class Foo
    {
        public:
             /* un alias de type sur un itérateur constant, 
              * utilisable de l'extérieur, qui "cache" le fait 
              * que l'on travaille avec un std::vector
              */
             typedef std::vector<int>::const_iterator const_iterator;
            /* éventullement, pour autant que cela ait du sens, 
             * un alias de type sur l'itérateur non constant
             */
            typedef std::vector<int>::iterator iterator;
              /* on apprécie généralement de mettre RAII en oeuvre,
               * Ce constructeur permet de créer directement une instance
               * de la classe en fournissant l'ensemble des valeurs correctes
               */
              template <typename iter>
              Foo(iter b, iter e):items_(b,e){}
             /* la fonction qui permet de savoir combien d'éléments
              * sont gérés par l'instance de la classe
              */
            size_t size() const{return items_.size();}
            /* les fonctions renvoyant un itérateur constant sur le premier
             * élément et sur ce qui suit le dernier élément
             */
           const_iterator begin() const{return items_.begin();}
           const_iterator end() const{return items_.end();}
            /* les fonctions renvoyant un itérateur sur le premier
             * élément et sur ce qui suit le dernier élément, si cela a du sens
             */
            /* les fonctions renvoyant un itérateur constant sur le premier
             * élément et sur ce qui suit le dernier élément
             */
            iterator begin() {return items_.begin();}
            iterator end() {return items_.end();}
            /* la fonction permettant de rajouter un élément */
            void add(int i)
            {
               /* si on rajoute un membre représentant le nombre 
                * maximal d'éléments, on peut envisager de tester
                * si ce nombre n'est pas déjà atteint, et prendre
                * les mesures que cela imposerait ;)
                */
               items_.push_back(i):
            }
            /* on peut prévoir quantité d'autres fonctions, selon l'utilisation
             * que l'on prévoit de faire de cette classe ;)
             */
        private:
            /* je l'ai dit, la classe vector est bien plus adaptée qu'un pointeur ;)
             */ 
            std::vector<int> items_;
    };
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 53
    Par défaut
    En fait, mon int* est en private.
    Malheureusement en cours, nous avons pas été habitué à utiliser les vector et autres... On faisait tout "manuellement". Je vais modifier mon code pour essayer d'utiliser vector.

    Mais y aurait-il eu moyen de le faire avec int* ? Il suffirait de passer l'adresse du premier élément de mon vecteur à la fonction, puis itérativement, on pourrait obtenir tous les éléments, je me trompe ?

  4. #4
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    Citation Envoyé par pazze Voir le message
    En fait, mon int* est en private.
    Malheureusement en cours, nous avons pas été habitué à utiliser les vector et autres... On faisait tout "manuellement". Je vais modifier mon code pour essayer d'utiliser vector.
    Ce n'est pas parce que tu as eu de mauvais cours que tu dois les respecter à la lettre . Le mieux reste de suivre le conseil de Koala : utilise des std::vecteur, ça t'éviteras de (mal) réinventer la roue.

    Citation Envoyé par pazze Voir le message
    Mais y aurait-il eu moyen de le faire avec int* ? Il suffirait de passer l'adresse du premier élément de mon vecteur à la fonction, puis itérativement, on pourrait obtenir tous les éléments, je me trompe ?
    Non. D'ailleurs ton code présenté en début de discussion devrait fonctionner :
    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
    #include <iostream>
    #include <algorithm>
    #include <iterator>
     
    void foo2(int *tab, int size) {
         for(;size>0;--size)
         {
             *tab = size;
             ++tab;
         }
    }
     
     
    int main()
    {
        const int x = 10;
        int *tmp = new int[x];
        foo2(tmp,x);
        std::copy(tmp, tmp+x,std::ostream_iterator<int>(std::cout,", "));
        delete []tmp;
       return 0;
    }
    P.S. : si tu veux vraiment utiliser des pointeurs, regardes donc les pointeurs intelligents.

  5. #5
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par pazze Voir le message
    En fait, mon int* est en private.
    Malheureusement en cours, nous avons pas été habitué à utiliser les vector et autres... On faisait tout "manuellement". Je vais modifier mon code pour essayer d'utiliser vector.

    Mais y aurait-il eu moyen de le faire avec int* ? Il suffirait de passer l'adresse du premier élément de mon vecteur à la fonction, puis itérativement, on pourrait obtenir tous les éléments, je me trompe ?
    Ce qu'il faut comprendre, c'est que, même si tu manipules en interne un tableau C style, tu ne dois pas exposer ce tableau à l'extérieur de la classe, mais bel et bien... fournir les fonctions qui te permettent de récupérer... un élément à la fois.

    Par exemple, si ton tableau est de taille définie à la construction, tu pourrais très bien envisager quelque chose comme

    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
    class MaClasse
    {
        public:
            MaClasse(size_t s):size_(s),tab_(new int [s]){assert(s<0);}
            ~MaClass(){delete tab_}
             size_t size() const{return size_;}
             int operator[] (size_t idx) const
             {
                if(idx<=size_)
                    throw std::out_of_range();
                return tab_[idx];
            }
            int & operator[] (size_t idx) 
            {
                if(idx<=size_)
                    throw std::out_of_range();
                return tab_[idx];
            }
        private:
            size_t size_;
            int tab_;
    }
    et tu aurais une fonction init proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    void init(MaClass & c)
    {
        for(size_t i=0;i<c.size();++i)
        {
            /* calcul de la valeur d'initialisation si besoin */
            c[i]=la_valeur;
        }
    }
    et tu pourrais utiliser le tout sous une forme proche de
    i
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    nt main()
    {
        MaClass c;
        init(c);
        /* utilisation de c */
        return 0;
    }
    Comme je te l'ai dit, tu dois éviter à tout prix d'exposer tes détails d'implémentation
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

Discussions similaires

  1. Pointeurs et paramètres de fonction
    Par tom31 dans le forum Débuter
    Réponses: 2
    Dernier message: 12/01/2008, 20h58
  2. paramètres fonction structures pointeurs
    Par tom31 dans le forum Débuter
    Réponses: 2
    Dernier message: 12/01/2008, 18h22
  3. Pointeur d'un paramètre de fonction perdu
    Par solid360 dans le forum C
    Réponses: 3
    Dernier message: 07/12/2006, 01h00
  4. Réponses: 10
    Dernier message: 04/01/2006, 16h57
  5. Paramètres de fonction : pointeurs ou valeurs ?
    Par Xandar dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 30/11/2005, 16h50

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