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

Turbo Pascal Discussion :

Allocation et désallocation de pointeurs dans une fonction [Turbo Pascal]


Sujet :

Turbo Pascal

  1. #1
    Futur Membre du Club
    Inscrit en
    Octobre 2002
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : Octobre 2002
    Messages : 9
    Points : 5
    Points
    5
    Par défaut Allocation et désallocation de pointeurs dans une fonction
    Bonjour,

    J'ai un record pour les nombres complexes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    type
        complexe=record
                       re,im:real;
                        end;
        pcomplexe=^complexe;
    Ensuite je fais une fonction pour ajouter 2 nbres complexes, 2 solutions :

    - Méthode 1 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    function ajout1(c1,c2:pcomplexe):pcomplexe;
    begin
         ajout1^.re:=c1^.re+c2^.re;
         ajout1^.im:=c1^.im+c2^.im;
    end;
    - Méthode 2 (plus propre je pense) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    function ajout2(c1,c2:pcomplexe):pcomplexe;
    var 
         temp:pcomplexe;
    begin
         new(temp);
         temp^.re:=c1^.re+c2^.re;
         temp^.im:=c1^.im+c2^.im;
         ajout2:=temp;
    end;
    Le problème : comment faire la désallocation du pointeur temp dans la méthode 2 ? Est-ce que l'alloc-désalloc est automatique dans la méthode 1 ?

    Quelle est la meilleure solution ?

  2. #2
    HRS
    HRS est déconnecté
    Membre confirmé
    Avatar de HRS
    Inscrit en
    Mars 2002
    Messages
    677
    Détails du profil
    Informations forums :
    Inscription : Mars 2002
    Messages : 677
    Points : 638
    Points
    638
    Par défaut
    Pour la méthode 2 :

    je rajouterais
    derrière
    car cette instruction n'a pas besoin d'être la dernière de la fonction

    Pour la 1ère :

    puisque vous n'avez pas eu à faire new (ajout), pas besoin donc de faire delete (ajout).

  3. #3
    Futur Membre du Club
    Inscrit en
    Octobre 2002
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : Octobre 2002
    Messages : 9
    Points : 5
    Points
    5
    Par défaut
    Je pense que tu voulais dire "dispose(temp)" et pas "delete(temp)".

    J'ai essayé cette solution, mais ca ne marche pas, le resultats renvoyé par la fonction est faux.

    ex simple: avec le dispose: (1+1i)+(1+1i) me renvoie 2+0i,
    alors qu'avec les methodes 1 et 2 le resultat est juste: 2+2i.

    D'ailleurs je comprend pas trop le resultat avec le dispose.
    precision: j'ai TP7.
    Sans dispose ca marche mais il n'y a pas de desallocation, et si jamais j'appelle cette fonction un grand nombre de fois, je pense que ca peut cree des probs?

    D'autre par pour la methode 1, est-ce que en interne la fonction desalloue l'espace occupé par le pointeur qu'elle renvoie?

  4. #4
    Futur Membre du Club
    Inscrit en
    Octobre 2002
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : Octobre 2002
    Messages : 9
    Points : 5
    Points
    5
    Par défaut
    Voila le code complet pour tester:

    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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
     
    program test;
     
    type
        complexe=record
                       re,im:real;
                 end;
        pcomplexe=^complexe;
     
    procedure affichage(c:pcomplexe);
    begin
         with c^ do
              if im<0 then
                 writeln(re:3:2,im:3:2,'i')
                 else
                     writeln(re:2:3,'+',im:2:3,'i');
    end;
     
                    {METHODE 1}
    function ajout1(c1,c2:pcomplexe):pcomplexe;
    begin
         ajout1^.re:=c1^.re+c2^.re;
         ajout1^.im:=c1^.im+c2^.im;
    end;
     
                    {METHODE 2}
    function ajout2(c1,c2:pcomplexe):pcomplexe;
    var 
         temp:pcomplexe; 
    begin 
         new(temp);
         temp^.re:=c1^.re+c2^.re;
         temp^.im:=c1^.im+c2^.im; 
         ajout2:=temp;
    end;
     
      {METHODE 2 avec dispose (normalement marche pas)}
    function ajout3(c1,c2:pcomplexe):pcomplexe;
    var
         temp:pcomplexe; 
    begin 
         new(temp); 
         temp^.re:=c1^.re+c2^.re;
         temp^.im:=c1^.im+c2^.im; 
         ajout3:=temp;
         dispose(temp);
    end;
     
    var
        a,b:pcomplexe;
     
    begin
         new(a);
         new(b);
     
         a^.re:=1;a^.im:=1;
         b^.re:=1;b^.im:=1;
     
         {affichage(ajout1(a,b));
         affichage(ajout2(a,b));}
         affichage(ajout3(a,b));
     
         dispose(a);
         dispose(b);
    end.

  5. #5
    Membre émérite

    Homme Profil pro
    Urbaniste
    Inscrit en
    Mars 2002
    Messages
    255
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Aveyron (Midi Pyrénées)

    Informations professionnelles :
    Activité : Urbaniste

    Informations forums :
    Inscription : Mars 2002
    Messages : 255
    Points : 2 717
    Points
    2 717
    Par défaut
    Tes deux codes sont faux! Tu dois allouer de la mémoire, puis renvoyer un pointeur sur la zone allouée (algo 2). Mais attention, la mémoire doit être libérée plus tard.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var a,b,resultat: pcomplexe;
    begin
      new (a);
      new (b);
      resultat = ajout2 (a,b);
      affiche (resultat);
      dispose (resultat);
      ...
      dispose (a);
      dispose(b);
    end.
    Autre solution : utiliser le mot clé "var" pour les paramètres (passage implicite par adresse) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    procedure somme (var a,b: complexe; var resultat: complexe);
    begin
      resultat.re = a.re +b.re;
      resultat.im = b.im +b.im;
    end;
     
    var a,b,resultat: complexe; { et non pcomplexe }
    begin
      ...
      somme (a,b,resultat);
      affiche (resultat);
      ...
    end.
    ou avec des pointeurs
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    var a,b,resultat: pcomplexe;
    begin
      new (a); new (b); new (resultat);
     ...
      somme (a^,b^,resultat^);
      affiche (resultat^);
      dispose (a); dispose (b); dispose (resultat);
    end.
    @+ Haypo

  6. #6
    Membre expert
    Avatar de Eric Sigoillot
    Inscrit en
    Mars 2002
    Messages
    1 212
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 212
    Points : 3 369
    Points
    3 369
    Par défaut
    Haypo a tout à fait raison à ce niveau là.

    Je vais t'expliquer le problème plus en détail, au lieu de balancer la solution comme ça.

    Le fait est que la première fonction que tu as créé renvoie un pointeur vers une zone mémoire... fictive ! Enfin, pas vraiment fictive. Le seul problème est qu'elle n'a pas été allouée par le système d'exploitation, et est de ce fait non réservée à l'usage de ta fonction. Tu vas donc non seulement écraser des données qui peuvent être importantes (d'où un risque de plantage non négligeable), et obtenir par la même occasion un résultat probablement faux, en tout cas qui le deviendra tôt ou tard lorsque que la zone mémoire utilisée sera réécrite par des données autorisées.

    Ta deuxième fonction est peut-être un peu moins fausse, mais reste tout aussi aléatoire. En effet, lorsque ta fonction sera appelée, tu vas demander une place mémoire, et tu vas stocker son adresse dans la variable Temp. Malheureusement pour toi, la variable Temp est stockée sur ce qu'on appelle la "pile" (Stack en anglais). Lorsque l'on appelle une procédure ou une fonction, l'ordinateur crée un "cadre de pile" dans lequel il va stocker les variables temporaires, dont Temp fait partie. Le seul problème est que dès que tu sors de a fonction, le cadre de pile est détruit, et le contenu de ta variable Temp par la même occasion ! Autrement dit, le pointeur vers l'emplacement mémoire est définitivement perdu. La zone mémoire allouée est donc totalement inaccessible, et il te sera impossible de la libérer par la suite. Qui plus est, tu vas stocker des données là encore où il ne faut pas. Le résultat revient au même qu'avant.

    Le plus simple reste donc d'utiliser les paramètres par adresse (avec var dans la déclaration), comme Haypo l'a montré. Je ne vais pas recommencer la même chose.

    Celà peut te sembler très théorique, mais essaie de t'en souvenir. Ca peut éviter bien des problèmes de débogages.

    A+
    Règles du forum
    F.A.Q Pascal

    Pour me joindre (aucune question technique, merci)

  7. #7
    Futur Membre du Club
    Inscrit en
    Octobre 2002
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : Octobre 2002
    Messages : 9
    Points : 5
    Points
    5
    Par défaut
    Merci pour vos reponses, je pense avoir a peu pres compris, mais y a un truc que j'ai pas compris:
    Citation Envoyé par Hdd34
    Ta deuxième fonction est peut-être un peu moins fausse, mais reste tout aussi aléatoire. En effet, lorsque ta fonction sera appelée, tu vas demander une place mémoire, et tu vas stocker son adresse dans la variable Temp. Malheureusement pour toi, la variable Temp est stockée sur ce qu'on appelle la "pile" (Stack en anglais). Lorsque l'on appelle une procédure ou une fonction, l'ordinateur crée un "cadre de pile" dans lequel il va stocker les variables temporaires, dont Temp fait partie. Le seul problème est que dès que tu sors de a fonction, le cadre de pile est détruit, et le contenu de ta variable Temp par la même occasion ! Autrement dit, le pointeur vers l'emplacement mémoire est définitivement perdu. La zone mémoire allouée est donc totalement inaccessible, et il te sera impossible de la libérer par la suite. Qui plus est, tu vas stocker des données là encore où il ne faut pas. Le résultat revient au même qu'avant.
    Si comme tu le dis ,"des que je sors de la fct, temp est detruit", pourquoi est-ce que je peut l'afficher quand meme? Je me casse trop la tete, peut-etre ?

    D'autre part, si j'ai bien compris, on est obligé d'utiliser une variable intermediaire ds le prog principal. Seulement, si je veux faire plusieures opérations a la suite, il me faudras autant de variables intermediaire que d'operations, non?
    Donc est-ce qu'il n'y a pas un moyen de pouvoir faire ca:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    resultat:=somme(somme(a,b),somme(a,a)));
    affiche(resultat);
    ????

  8. #8
    Membre expert
    Avatar de Eric Sigoillot
    Inscrit en
    Mars 2002
    Messages
    1 212
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 212
    Points : 3 369
    Points
    3 369
    Par défaut
    Salut !

    Lorsque j'emploie le terme "détruit", ça ne veut pas dire que le contenu de temps a disparu. Il est seulement indiqué comme "disponible". Pour être clair, il faut comprendre un minimum comment fonctionne la pile. Elle porte très bien son nom... Il suffit en fait de se représenter une pile d'assiettes, dans laquelle on place des nombres. Chaque assiette peut contenir deux octets (je ne sais pas trop si c'est comestible... ). Juste à côté de ta pile d'assiettes, il y a une grande règle graduée, avec deux curseurs. Le premier est situé tout en bas de la pile, et n'est pas sensé bouger durant tout le programme... Quand au deuxième, il est variable. Il indique en fait le haut de la pile, enfin, la première assiette utilisable.
    Lorsque tu entres dans ta fonction, si la varaible Temp fait 4 octets, le pointeur de pile est augmenté de 4, indiquant que si on veut placer des choses dans la pile, il faudra les mettre 4 octets plus haut qu'avant. Le problème est que dès que vas sortir de ta fonction, le pointeur de pile va redescendre les échelons, indiquant par là même que la place de ta variable Temp est disponible pour écrire autre chose.

    Tant que tu ne retouches pas à la pile, il y a des chances pour Temp reste intacte. Mais ça ne saurait durer...

    Maintenant, j'avoue avoir fait une erreur... Sorry ! Ce que j'ai dit est uniquement valable lorsque l'on crée un pointeur vers un emplacement statique. Or, tu alloues un espace mémoire dans ta fonction avec New, et tu renvoies ce pointeur avec la fonction. L'emplacement étant dynamique, il n'est pas perdu. Néanmoins, il faut penser à le sauvegarder en sortie de fonction pour pouvoir libérer cette mémoire avec Dispose.

    De ce fait, il serait possible d'utiliser Result := Somme(Somme(a, b), Somme(c, d));.
    Mais dans ce cas, il faudrait accepter d'avoir des fuites de mémoire... Et ce n'est pas vraiment à conseiller...

    A+
    Règles du forum
    F.A.Q Pascal

    Pour me joindre (aucune question technique, merci)

  9. #9
    Futur Membre du Club
    Inscrit en
    Octobre 2002
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : Octobre 2002
    Messages : 9
    Points : 5
    Points
    5
    Par défaut
    Donc, en general, faire une fonction qui renvoie un pointeur ca peut vite mener a faire des erreurs. D'ailleurs il vaut mieux faire des procedures, puisque ds les 2 cas on seras obliger d'utiliser une variable temporaire dans le prog principal. A quoi ca sert de faire une fonction, si on ne peut pas l'utiliser comme une fonction mathematiques, dans une suites de calcul? Est-te vous d'accord?

  10. #10
    Membre expert
    Avatar de Eric Sigoillot
    Inscrit en
    Mars 2002
    Messages
    1 212
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 212
    Points : 3 369
    Points
    3 369
    Par défaut
    Je ne suis pas tout a fait d'accord.
    Dans ton cas, tu cherches à renvoyer un complexe, sur 12 octets. Or, TP est en mesure de renvoyer des résultats de quatre octets.

    Les valeurs de retour des fonctions ont été améliorées avec Delphi, et de ce fait, il est inutile de passer par les pointeurs à présent. Mais avec TP, il faut s'en contenter.

    Tu peux toujours utiliser les paramètres par adresse.

    A+[/code]
    Règles du forum
    F.A.Q Pascal

    Pour me joindre (aucune question technique, merci)

  11. #11
    Futur Membre du Club
    Inscrit en
    Octobre 2002
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : Octobre 2002
    Messages : 9
    Points : 5
    Points
    5
    Par défaut
    1)
    Citation Envoyé par Hdd34
    Tu peux toujours utiliser les paramètres par adresse.
    Donc utiliser une procedure.

    2)
    Haypo a ecrit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    procedure somme (var a,b: complexe; var resultat: complexe); 
    begin 
      resultat.re = a.re +b.re; 
      resultat.im = b.im +b.im; 
    end;
    Quel est l'interet de "var a,b: complexe"? On ne va pas modifier la valeur de a et b?
    Moi j'aurais ecrit "(a,b: complexe; var resultat: complexe);"

    3)
    Donc TP c pas terrible

    4)
    Sinon, une autre questions un peu hors-sujets: Est-ce qu'en C/C++ on peut renvoyer un type structuré?

  12. #12
    HRS
    HRS est déconnecté
    Membre confirmé
    Avatar de HRS
    Inscrit en
    Mars 2002
    Messages
    677
    Détails du profil
    Informations forums :
    Inscription : Mars 2002
    Messages : 677
    Points : 638
    Points
    638
    Par défaut
    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
     
    tests fait avec
     
    -TP7 (TurboPascal 7.01 - compilateur 16 bits gratuit) 
    -FP (DevPascal + FreePascal 1.0.6 - compilateur 32 bits gratuit)
    -Gnu (DevPascal + GnuPascal 2.1 - compilateur 32 bits gratuit)
    -OP (ObjectPascal de Delphi - compilateur 32 bits)
     
    Résultats des courses avec les 3 fonctions ajoutx
     
    ajout1 : TP7 et FP - marche sur un seul appel de la fonction
                         mais plante au 2ème appel successif
             Gnu et OP - erreur de compile
    ajout2 : marche sur les 4 compilo mais ne libère pas la
             memoire (est ce utile ?)
     
    ajout3   TP7       - résultat incorrect (2.O00+0.000i)
             FP        - résultat incorrect (O.O00+2.000i)
             Gnu et OP - résultat correct   (2.000+2.000i)
    --------------------------------------
    autant ajout1 est une mauvaise solution, autant ajout3 qui
    semblait la meilleure solution, disfonctionne de manière
    presqu'identique sur 2 compilo
     
    Il pourrait y avoir interférences dans la pile entre une allocation/
    desallocation de pointeur et la valeur retournée par la fonction
     
    ---------------------------------------------------
    PS : contrairement à TP7, les fonctions peuvent retourner une
         structure sur les compilo 32 bits et donc les pointeurs
         de structure présentent moins d'intérêt

  13. #13
    Membre expert
    Avatar de Eric Sigoillot
    Inscrit en
    Mars 2002
    Messages
    1 212
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 212
    Points : 3 369
    Points
    3 369
    Par défaut
    Pour répondre à Neird, ta réponse 3 t'engage à aller voir ailleurs...

    Je ne connais pas suffisement le C/C++ pour savoir si les compilateurs équivalents à TP sont en mesure de retourner un type structuré. Par contre, il est vrai que la surcharge des opérateurs est intéressante dans ce cas là.

    Il y a plusieurs manière de gérer le problème posé. On peut choisir de se servir des pointeurs, en en libérant la mémoire une fois que l'on a fini de se servir du résultat, on peut se servir de paramètres var (la réponse de HRS est d'ailleurs correcte pour la remarque).

    On peut aussi s'amuser à prendre une variable globale pour les résultats (euh... pas terrible ça !).

    On peut aussi passer par la POO pour créer un objet qui se chargera d'additionner ses copains avec lui-même , et j'en passe !

    Il suffit de voir ce que l'on veut comme résultat.

    A+
    Règles du forum
    F.A.Q Pascal

    Pour me joindre (aucune question technique, merci)

  14. #14
    Futur Membre du Club
    Inscrit en
    Octobre 2002
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : Octobre 2002
    Messages : 9
    Points : 5
    Points
    5
    Par défaut
    Merci pour vos reponses.

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 19/01/2010, 14h01
  2. passage de pointeur dans une fonction
    Par El Manco dans le forum Débuter
    Réponses: 10
    Dernier message: 09/02/2009, 22h13
  3. Modification de pointeurs dans une fonction
    Par bluemartini dans le forum Débuter
    Réponses: 4
    Dernier message: 26/09/2008, 10h23
  4. Modifier le contenu de pointeurs dans une fonction
    Par Sol_Invictus dans le forum Débuter
    Réponses: 6
    Dernier message: 11/09/2008, 23h30
  5. Pointeur dans une fonction ?
    Par sliiim6184 dans le forum C
    Réponses: 4
    Dernier message: 28/12/2006, 11h32

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