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 :

fonctions, tableaux et pointeurs


Sujet :

C++

  1. #1
    Candidat au Club
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Octobre 2016
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Enseignant Chercheur

    Informations forums :
    Inscription : Octobre 2016
    Messages : 8
    Points : 3
    Points
    3
    Par défaut fonctions, tableaux et pointeurs
    Bonjour,

    J'ai une petite question concernant le c++, suivant la réponse il n'est pas impossible que d'autres questions s'en suivent

    Supposons que je fasse la fonction suivante

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    double* maFonction(){
        double* res = new double[3];
        return(res);
    }
    ma fonction renvoie un pointeur sur un double... (je n'ai pas rempli les valeurs du tableau de double mais ce n'est pas important pour ma question)

    ce que je ne comprends pas c'est que la variable res est déclarée localement dans la fonction, donc j'imagine que l'espace mémoire est "libéré" une fois la fonction éxécutée et peut donc être réutilisé, du coup mon pointeur pointe potentiellement sur n'importe quoi si l'espace est utilisé à nouveau non ?

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 113
    Points : 32 958
    Points
    32 958
    Billets dans le blog
    4
    Par défaut
    res est libérée à la fin de l'accolade mais pas la mémoire qu'il a alloué et sur laquelle il pointe, où pointe également le pointeur retourné (par copie) par la fonction
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Candidat au Club
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Octobre 2016
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Enseignant Chercheur

    Informations forums :
    Inscription : Octobre 2016
    Messages : 8
    Points : 3
    Points
    3
    Par défaut
    D'accord merci. Si je fais appel a une fonction enormement de fois, il convient donc de libérer l'espace mémoire utilisé par toutes les variables et objets temporaires dans cette fonction ?

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 113
    Points : 32 958
    Points
    32 958
    Billets dans le blog
    4
    Par défaut
    Je comprends pas ce que tu racontes.

    Que tu appelles ta fonction 1 ou 10000000000000 fois, ça change strictement rien aux variables allouées sur la pile, elles disparaissent avec elle (cf cours débutants : portée des variables).
    Si tu fais de l'allocation dynamique, bien sur qu'il faut la libérer, sinon tu vas juste finir par crasher parce que le système n'a plus de mémoire disponible.
    Btw, aujourd'hui l'appel à l'allocation dynamique peut être rare en utilisant les outils (récents) de containers de la std (vector, list, unique_ptr, ...).
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  5. #5
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 186
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 186
    Points : 17 126
    Points
    17 126
    Par défaut
    Si on veut être plus précis, il y a une confusion entre libération de la mémoire allouée dynamiquemet (c'est à dire manuellement)

    Voici un usage de ta fonction:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    double* maFonction(){
        double* res = new double[3];
        return(res);
    }
     
    int main() {
        double * p = maFonction();
        delete[] p;
    }
    Note bien que la mémoire doit être libérée via delete[], ce qui n'est pas du tout pareil que delete.

    dans l'ordre, on a:
    • maFonction est appelée.
    • new est appelée pour un double[3] pour créer un bloc mémoire (dans le tas). l'adresse du bloc créé est la valeur de cette expression.
    • la valeur retournée sert à initialiser une nouvelle variable locale nommée res (de maFonction)
    • la valeur de cette variable est utilisée pour initialiser la valeur de retour de maFonction
    • on sort de la fonction: res est détruite. étant un type non-classe (ni class ni struct ni union), il n'y a pas de destructeur, donc rien n'est fait: sa valeur est juste oubliée.
    • la valeur de retour est utilisé pour initialiser une nouvelle variable locale p (de main)
    • on libère le bloc mémoire du tas désigné par l'adresse contenue dans p. (heureusement, c'est bien l'adresse d'un bloc allouée par new ... [])
    • on sort de main
    • p est détruite: même (absence de) traitement que res dans maFonction



    C'est parce qu'il faut faire extrêmement attention à libérer une et une seule fois les blocs mémoires créée dans le tas que sont apparus:
    • les (template de) classes de la STL comme vector, string ou map
    • fstream
    • les pointeurs dits intelligents dont unique_ptr et shared_ptr.

    Bon, d'accord, pas uniquement pour cette raison, mais c'est un problème au cœur de ces classes.

    Tu ferais probablement mieux de choisir l'une des fonctions suivantes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    std::vector<double> maFonction() {
         //trois valeurs dans le vecteur, toutes égales à 0.
        return std::vector<double>(3, 0);
    }
     
    std::array<double, 3> maFonction() {
        return std::array<double, 3>();
    }
    Remarque qu'il n'y a pas besoin de parenthèses autour de la valeur retournée.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  6. #6
    Candidat au Club
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Octobre 2016
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Enseignant Chercheur

    Informations forums :
    Inscription : Octobre 2016
    Messages : 8
    Points : 3
    Points
    3
    Par défaut
    Merci à vous. Oui en effet, je ne savais pas qu'il y avait deux types de mémoire (dynamique ou non) : je vais regarder ca de plus pres!

  7. #7
    Candidat au Club
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Octobre 2016
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Enseignant Chercheur

    Informations forums :
    Inscription : Octobre 2016
    Messages : 8
    Points : 3
    Points
    3
    Par défaut
    Allez, une dernière question pour la route :

    double* d = new double[3];

    delete[] d;

    comment delete[] sait que la longueur du tableau est 3 doubles ? je pensais que le pointeur était l'adresse du premier element ! Ce premier élément fait parti d'un bloc mémoire contenant tous les éléments du tableau ? Si c'est le cas existe-t-il une fonction qui renvoie la taille d'un tel tableau en prenant d en argument ?

    Merci !! Je devrais réussir à m'en tirer pour la suite

  8. #8
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Il n'y a qu'un seul type de mémoire mais deux méthodes d'allocation (rappel : allocation désigne l'action de réserver de l'espace en mémoire système en prévision d'un usage exclusif par le programme) : statique et dynamique. La différence étant principalement que l'allocation statique exige de connaître la taille du bloc à réserver à la compilation, contrainte absente de la seconde.

    Ces deux méthodes ont leurs cibles privilégiées : la pile et le tas, respectivement. Tu trouveras ailleurs de nombreuses explications détaillées sur ce que sont l'un et l'autre, comment ils fonctionnent et quelles garanties ils offrent. Pour résumer très brièvement, ce sont deux zones distinctes en mémoire et :

    • les variables locales, les paramètres de fonctions et les sauvegardes de contexte (lors de l'appel d'une fonction) sont placés sur la pile, leur allocation et leur libération sont implicites ;
    • les blocs renvoyés par new ou malloc sont alloués sur le tas ; en fin d'utilisation, leur libération nécessite un appel explicite de la part de leur propriétaire (à savoir : ton programme).



    Citation Envoyé par RazLaCrepe Voir le message
    comment delete[] sait que la longueur du tableau est 3 doubles ?
    Le système d'exploitation, responsable de la gestion de la mémoire entre tous les processus, conserve une table des adresses de tous les blocs alloués sur le tas ainsi que leur taille. Ces informations sont récupérées et utilisées lors d'un appel à delete[] / delete / free.

    Peu lui chaut d'ailleurs que tu stockes trois objets de type double au sein de ce bloc, il n'en a pas conscience. Seul lui importe le fait que la taille du bloc est 3 * sizeof(double) bytes (octets).


    Citation Envoyé par RazLaCrepe Voir le message
    je pensais que le pointeur était l'adresse du premier element ! Ce premier élément fait parti d'un bloc mémoire contenant tous les éléments du tableau ?
    C'est tout à fait cela.


    Citation Envoyé par RazLaCrepe Voir le message
    Si c'est le cas existe-t-il une fonction qui renvoie la taille d'un tel tableau en prenant d en argument ?
    Réponse courte : non, car le processus à l'origine de l'allocation connaît déjà - par définition - la taille du bloc qu'il demande. C'est à lui de la conserver si c'est pertinent.

    Réponse plus précise : oui, parfois. C'est très dépendant du système d'exploitation et de l'implémentation de l'allocateur. Tu n'en auras jamais l'usage si tu ne fais pas de programmation système.

  9. #9
    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 518
    Points
    41 518
    Par défaut
    Note sur la taille et delete[]:
    L'information de taille du tableau est stockée en interne et le standard C++ ne définit aucun moyen pour le code utilisateur de récupérer cette taille.

    D'ailleurs, pour des tableaux de types "plain old data" (POD) comme double (en gros, tous les types n'ayant pas de destructeur), il est possible que cette information ne soit même pas retenue, et que seule la taille mémoire réservée (qui peut être plus grande que celle du tableau) le soit! L'implémentation peut faire ce qu'elle veut du moment que:
    1. L'OS s'y retrouve quand il s'agit de libérer la mémoire,
    2. Les destructeurs sont appelés quand il y en a.
    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.

Discussions similaires

  1. [WD10] Utiliser une fonction OpenGL avec pointeur (int)
    Par Zoons dans le forum WinDev
    Réponses: 3
    Dernier message: 06/07/2006, 17h38
  2. allocation dynamique et tableaux de pointeurs
    Par gbardy dans le forum 4D
    Réponses: 3
    Dernier message: 06/07/2006, 12h08
  3. en COM Tableaux de pointeurs d'interface:
    Par Barahn dans le forum MFC
    Réponses: 11
    Dernier message: 30/09/2005, 17h42
  4. Fonction retournant un pointeur
    Par Le Furet dans le forum C
    Réponses: 8
    Dernier message: 25/09/2005, 19h54
  5. Declaration de fonction retournant un pointeur sur fonction
    Par pseudokifaitladifférence dans le forum C
    Réponses: 5
    Dernier message: 11/08/2003, 20h37

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