Page 1 sur 2

Pointeurs => pas tout compris

Publié : mar. 18/juil./2006 11:05
par foossile
Je viens d'étudier les tutoriaux sur les pointeurs
Apparement il s'agit d'une phase importante de l'apprentissage de la programmation.
Mais j'avoue me mélanger un peu surtout en ce qui concerne la syntaxe pour travailler avec les pointeurs.
corrigez moi si je me trompe

admettons une variable nombre
nombre.l = 100 déclare une variable de type "long" et affecte la valeur 100
adressevar = @nombre affecte dans adressevar l'adresse mémoire de la variable

peekx(adresse) lit le contenue de l'adresse
pokex(adresse,valeur) écrit à l'adresse la valeur en paramètre
x tant pour le type (b,W,L,F)

peekL(adressevar) va donc me retourner 100
peekL(@nombre) me retourne aussi 100

pokeL(adressevar,200) enregistre la valeur 200 dans la variable qui a l'adresse 'adressevar' (donc nombre dans notre cas)
pokeL(@nombre,200) effectue la même chose

*pointeur déclare un pointeur (je suppose donc que c'est "*" qui définie que c'est un pointeur et non une variable)
je peux donc faire :
*pointeur = @nombre ou *pointeur=adressevar
peekL(*pointeur) me retourne donc 200 (valeur de la variable)

c'est là que je pige plus, pourquoi utiliser un pointeur (ma foi un peu compliqué). je sais qu'il doit y avoir des raisons sinon ca n'existerait pas, mais je trouve les tutoriaux un peu flou quant aux réelles utilités des pointeurs.

Merci de me dire si je fais erreur et de m'éclairer la lanterne quant à son utilité.

PS: hé oui c'est chiants les débutants, faut toujours leur répéter :)

Publié : mar. 18/juil./2006 11:29
par Backup
Les pointeurs ne sont pas indispensable en programmation,
par contre il aportent rapidité de l'execution du code
ainsi que la possibilité de faire des bidouilles comme retourné plusieurs
resultats d'un Procedure
a ce propos, j'aimerai bien que Fred pense a nous donner la possibilité
de pouvoir faire autant de Procedure Return qu'on veut :D

Publié : mar. 18/juil./2006 13:40
par Flype
a ce propos, j'aimerai bien que Fred pense a nous donner la possibilité
de pouvoir faire autant de Procedure Return qu'on veut
Impossible, ou alors va falloir être plus précis.

Publié : mar. 18/juil./2006 13:46
par foossile
Dobro a écrit :Les pointeurs ne sont pas indispensable en programmation,
par contre il aportent rapidité de l'execution du code
ainsi que la possibilité de faire des bidouilles comme retourné plusieurs
resultats d'un Procedure
a ce propos, j'aimerai bien que Fred pense a nous donner la possibilité
de pouvoir faire autant de Procedure Return qu'on veut :D
Ne peut-on pas utiliser les variables globales pour contourner ce problème ?
Peut être est-ce trop gourmand en ressource ?

Publié : mar. 18/juil./2006 14:56
par Flype
oui, les globales représentent la meilleure solution.
et, non, ce n'est pas trop gourmand en ressource.

une autre solution est de retourner un pointeur sur une structure.

ou encore une structure en globale.


Petit comparatif pour faire (presque) la même chose, à toi de choisir :

Code : Tout sélectionner

Global PERSONNE_Nom.s
Global PERSONNE_Prenom.s
Global PERSONNE_Age.s

Procedure.l Analyse(chaine.s)
  
  PERSONNE_Nom    = StringField(chaine, 1, " ")
  PERSONNE_Prenom = StringField(chaine, 2, " ")
  PERSONNE_Age    = StringField(chaine, 3, " ")
  
EndProcedure

Analyse("donald duck 34")

Debug PERSONNE_Nom
Debug PERSONNE_Prenom
Debug PERSONNE_Age

Code : Tout sélectionner

Structure PERSONNE
  nom.s
  prenom.s
  age.s
EndStructure

Global x.PERSONNE

Procedure.l Analyse(chaine.s)
  
  x\nom    = StringField(chaine, 1, " ")
  x\prenom = StringField(chaine, 2, " ")
  x\age    = StringField(chaine, 3, " ")
  
EndProcedure

Analyse("donald duck 34")

Debug x\nom
Debug x\prenom
Debug x\age

Code : Tout sélectionner

Structure PERSONNE
  nom.s
  prenom.s
  age.s
EndStructure

Procedure.l Analyse(*x.PERSONNE, chaine.s)
  
  *x\nom    = StringField(chaine, 1, " ")
  *x\prenom = StringField(chaine, 2, " ")
  *x\age    = StringField(chaine, 3, " ")
  
EndProcedure

Analyse(x.PERSONNE, "donald duck 34")

Debug x\nom
Debug x\prenom
Debug x\age

Code : Tout sélectionner

Structure PERSONNE
  nom.s
  prenom.s
  age.s
EndStructure

Procedure.l Analyse(chaine.s)
  
  *x.PERSONNE = AllocateMemory(SizeOf(PERSONNE))
  
  If *x
    *x\nom    = StringField(chaine, 1, " ")
    *x\prenom = StringField(chaine, 2, " ")
    *x\age    = StringField(chaine, 3, " ")
  EndIf
  
  ProcedureReturn *x
  
EndProcedure

*x.PERSONNE = Analyse("donald duck 34")

If *x
  Debug *x\nom
  Debug *x\prenom
  Debug *x\age
  FreeMemory(*x)
EndIf

Code : Tout sélectionner

Procedure.l test(string.s, *nom, *prenom, *age)
  
  If *nom And *prenom And *age
    
    PokeS(*nom,    StringField(string, 1, " ")) 
    PokeS(*prenom, StringField(string, 2, " ")) 
    PokeL(*age,    Val(StringField(string, 3, " ")))
    
    ProcedureReturn #True
    
  EndIf
  
EndProcedure

If test("donald duck 34", @nom.s{16}, @prenom.s{16}, @age.l)
  
  Debug nom
  Debug prenom
  Debug age
  
EndIf

Publié : mar. 18/juil./2006 15:30
par comtois
dans les petits exemples de Flype, et dans un petit programme , ça peut encore être gérable d'utiliser des variables globales, mais ça peut très vite devenir lourd si le programme prend de l'ampleur.

A quoi peuvent servir les pointeurs ?

Je donne un exemple dans ce tut.
Il s'agit d'une procédure qui permet de gérer l'animation d'un sprite.

Tu peux mettre au point la procédure indépendamment du reste du programme, et ensuite tu peux animer autant de sprites que tu le désires puisqu'il suffit de passer l'adresse d'un sprite à la procédure.
En travaillant avec des variables locales, ça permet de te créer des boites noires, tu n'as plus à te soucier du code de la procédure.

L'avantage d'une variable globale , c'est qu'effectivement tu peux la modifier dans une procédure sans la passer en paramètre, mais c'est aussi un énorme inconvénient , parce que tu cours le risque de la modifier par erreur à d'autres endroits, et dans un code immense, bonjour pour retouver où !

Tu peux aussi faire des belles boulettes en jouant avec les pointeurs, bref si tu débutes, tu peux t'en passer, tu ressentiras bien assez tôt le besoin de les utiliser :)

http://www.games-creators.org/wiki/Pure ... remiersPas

Publié : mar. 18/juil./2006 16:45
par Flype
mais c'est aussi un énorme inconvénient , parce que tu cours le risque de la modifier par erreur à d'autres endroits, et dans un code immense, bonjour pour retouver où !
Ce qu'on appelle, en programmation, les 'effets de bord'.

Publié : mar. 18/juil./2006 17:06
par foossile
Je suis sans doute très bête mais je pige toujours pas l'avantage des pointeurs.

A chaque variable qu'on veut utiliser on affecte un pointeur donc au bout du compte, pour un même nombre de variable utilisée, il y a autant de 'pointeurs' dans un cas que de variables globales dans l'autre cas non ? Donc autant de chance de faire des bourdes avec les uns comme les autres.

Eclairez moi svp....

Publié : mar. 18/juil./2006 17:40
par comtois
Imagine qu'on bosse ensemble sur le même projet, tu me demandes de faire une procédure pour gérer l'animation de sprites.
On s'est mis d'accord pour une structure s_Sprite qui englobe tous nos besoins en matière de gestion de sprites.
C'est tout ce dont j'ai besoin pour créer une procédure que tu pourras intégrer dans ton code, et tu pourras animer tes sprites.
Je vais pouvoir écrire une procédure sans connaître le nom de tes variables, et toi tu pourras utiliser ma procédure sans connaître les variables locales que j'utilise.Et comme je n'utilise que des variables locales il n'y a pas de risque de double emploi avec des variables de même nom que tu aurais pu utiliser de ton côté.

la seule chose que tu auras besoin de savoir , c'est les paramètres, entre autre dans notre cas, la procédure se présenterait ainsi

Code : Tout sélectionner

Procedure AnimationSprite(*Pointeur.s_Sprite)
   Déclaration de variables locales 
   code d'animation d'un sprite 
EndProcedure 
Et toi , de ton côté, tu auras créé plusieurs sprites
Fermier.s_Sprite
Cheval.s_Sprite
Berger.s_Sprite

et quand tu auras besoin d'animer un sprite tu auras juste à appeler la procédure que je t'ai filé:

Code : Tout sélectionner

;Animation du fermier
AnimationSprite(@Fermier)
Si tu veux animer le berger

Code : Tout sélectionner

;Animation du berger
AnimationSprite(@Berger)
la procédure AnimationSprite() attend l'adresse d'un sprite, et en utilisant les pointeurs il est possible d'animer n'importe quel sprite utilisant la même structure s_Sprite.

Donc il n'y a pas autant de pointeur que de sprite, puisque dans l'exemple que je te donne, il y a un seul pointeur pour une multitude de sprites.

Publié : mar. 18/juil./2006 18:20
par foossile
ah ben voilà avec un exemple concret, je pige un peu mieux
en gros (on me corrige si j'ai tort) ;
programme léger : variables globales
progamme lourd ou projet multi participants : pointeurs
(ce qui n'empêche pas le double emploi ;) )

Pfff, j'en ai encore un paquet de truc à apprendre moi :p

Publié : mar. 18/juil./2006 18:24
par Backup
Flype a écrit :
a ce propos, j'aimerai bien que Fred pense a nous donner la possibilité
de pouvoir faire autant de Procedure Return qu'on veut
Impossible, ou alors va falloir être plus précis.

pouvoir faire ceci

Code : Tout sélectionner

Procedure multi (a,b,c,d:result1,:result2,:result3)
  result1= a+b
  result2= a+b+c
  result3= a+b+c+d 
  ProcedureReturn result1
  ProcedureReturn result2
  ProcedureReturn result3 
EndProcedure

je sais qu'en purebasic le procedurereturn fait quiter la procedure
mais ne me dit pas que c'est impossible
dans plein de basic (meme ancien) la procedure se quitte seulement a la rencontre de la directive "EndProcedure"
les proceduresreturn

renvoient par le meme canal les resultats

dans l'exemple donné cela donnerai les resultats
dans la seconde partie des parametres

c'est a dire que les parametres pourrai servir de canal d'entre ou de sortie !!! :D

et ça ouvrirai plein de chose interressantes non ? :D

ou bien nous pourion avoir :

Code : Tout sélectionner

Procedure multi (a,b,c,d)
  result1= a+b
  result2= a+b+c
  result3= a+b+c+d 
  ProcedureReturn result1
  ProcedureReturn result2
  ProcedureReturn result3 
EndProcedure



avec trois apel successif

result=multi (a,b,c,d) ; ici resultat du premier procedurereturn
result=multi (a,b,c,d) ; ici resultat du deuxiem procedurereturn
result=multi (a,b,c,d) ; ici resultat du troisiem procedurereturn

cela obligerai a la tenu d'un espece de compteur interne a la procedure
car au prochain apel cela redonnerai le premier resultat :D ect ...

Publié : mar. 18/juil./2006 19:39
par nico
Faire la démonstration de l'utilité des pointeurs n'est pas aisé car ils sont surtout indispensable lorsqu'on ne se limite pas seulement aux fonctions de PureBasic, donc en se lançant dans les API Window. Si on te faisait une démonstration très concrète des pointeurs, le code te paraitrait hors de portée et l'utilisation des pointeurs te semblerais du coup vraiment inutile ce qui est faux.

Je considère les pointeurs comme une des bases du langage car sa compréhension est indispensable pour dépasser le niveau de débutant!

( Cela dit , il y a des personnes qui n'utilisent pas les pointeurs, ils ne sont pas débutant pour autant, hein Dobro! :) )

Il vaut mieux commencer à étudier les pointeurs dès que l'on se sent à l'aise avec le langage avant même que le besoin s'en fasse ressentir car bien que le fonctionnement des pointeurs ne soit pas très compliqués en soi, son assimilation prend un certain temps tout de même car il est déroutant au début et il est indispensable de se faire la main dans différents cas de figure.

Publié : mar. 18/juil./2006 19:41
par nico

Code : Tout sélectionner

; -----------------------------------
; Petite démonstration des pointeurs:
; -----------------------------------

Chaine$="flype comtois nico chris dobro erix14"
Chaine_resultante.s=""

; Comment faire pour mettre en Majuscule
; la première lettre de chaque prénom ?

;La réponse: l'utilisation des pointeurs!

For a=1 To 6
  Prenom_a_modifier.s= StringField(Chaine$, a, " ")
  *pointeur=@Prenom_a_modifier
  PokeB(*pointeur,PeekB(*pointeur)-32)
  Chaine_resultante = Chaine_resultante + Prenom_a_modifier + " "
Next
Chaine_resultante = RTrim(Chaine_resultante) 

Debug chaine$
Debug Chaine_resultante

Publié : mar. 18/juil./2006 19:56
par jerexgrz
En ce qui me concerne, les pointeurs sont intéressants car ils permettent de contourner certains problemes que l'on peut rencontrer comme par ex la limite du 'procedure return'.

Je les utiliserais plutot pour réaliser des operations que pb ne sait pas faire en natif. Et par contre, s'il est possible de passer par PB en natif, je prefere, car cela evite de programmer soi meme les fonctions et par consequent, celà evite de faire un code lent(optimisation par Fred) et compliqué (si il y a plein de lignes).

Publié : mar. 18/juil./2006 21:16
par Flype
Voici une autre alternative pour gérer plusieurs 'Return'.

Et justement, je pense qu'il y a beaucoup de choses à comprendre et à apprendre dans cet example au sujet des pointeurs.
Ils sont pratiques à plusieurs égards ici :

1/ pour gérer plusieurs 'return' sans globales
2/ pour 'travailler' une chaine de caractères
3/ pour 'optimiser' la vitesse de traitement

Code : Tout sélectionner

Procedure.l Multi(Chaine.s, *NbMot.Long, *NbMin.Long, *NbMaj.Long, *NbDigit.Long)
  
  Protected *pointeur.Character = @Chaine
  
  If *NbMot And *NbMin And *NbMaj And *NbDigit
    
    While *pointeur\c
      
      Select *pointeur\c
        Case ' '
          *NbMot\l   + 1
        Case 'a' To 'z'
          *NbMin\l   + 1
        Case 'A' To 'Z'
          *NbMaj\l   + 1
        Case '0' To '9'
          *NbDigit\l + 1
      EndSelect
      
      *pointeur + SizeOf(Character)
      
    Wend
    
    ProcedureReturn #True
    
  EndIf
  
EndProcedure


MaChaine.s = "PureBasic 4.0 by Fantaisie Software (2000-2006), Feel the power..."


If Multi(MaChaine, @nMot.l, @nMin.l, @nMaj.l, @nDigit)
  
  Debug "Nombre de mots : "       + Str(nMot)
  Debug "Nombre de minuscules : " + Str(nMin)
  Debug "Nombre de majuscules : " + Str(nMaj)
  Debug "Nombre de digits  : "    + Str(nDigit)
  
EndIf
@dobro
Je trouve cette solution élégante et proche de ce que tu veux sans chambouler le fonctionnement de PB.

A noter que toute fonction callback fonctionne sur ce principe pour avoir plusieurs 'return'. Donc si même windows fait comme çà...