Un Tuto, siou plait...

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Torp
Messages : 360
Inscription : lun. 22/nov./2004 13:05

Un Tuto, siou plait...

Message par Torp »

Hello,

Bon alors voilà..., est ce qu'il n'y en aurais pas un parmi vous, qui voudrait se lancer dans la réalisation d'un vrai tuto sur les pointeurs, les adresses mémoires, etc....

En effet, les infos et exemples à ce sujet sont éparpillés un peu partout sur le forum, et malgré mes efforts j'ai un peu de mal à joindre les 2 bouts et bien intégrer le concept et les possibilités...

Suite à une demande que j'avais faite sur la programmation d'un dico, Comtois a "pondu" un code que j'ai vraiment du mal à aborder car il utilise les pointeurs à gogo (récursifs en plus)....

http://purebasic.hmt-forum.com/viewtopic.php?t=2280

Le seul tuto qui à l'air sympa (posté par Nico) est en Teuton. Alors s'il faut que j'apprenne en plus l'allemand, suis pas prés de comprendre le code de Comtois ... :lol: (Peut être en existe t il déjà un en francais mais j'lai po trouvé).

http://freak.purearea.net/help/pointer/kapitel1.html

De plus, je crois que ce tuto sera le bien venu pour un paquet de monde.

Voilà la demande est faite...
Ame charitable, si tu m'entends... :wink:
comtois
Messages : 5186
Inscription : mer. 21/janv./2004 17:48
Contact :

Message par comtois »

faire un cours magistral sur les pointeurs , j'en suis bien incapable , je n'emploierais pas les bons termes et je risquerais de t'induire en erreur.
J'arrive à les utiliser , mais pour expliquer c'est une autre histoire :)

Tu buttes sur quelle partie du programme exactement ?
Est-ce que l'algo en lui même est clair ? c'est juste la mise en oeuvre qui coince ? ou autre chose ?

est-ce que tu peux isoler la portion de programme sur laquelle tu buttes le plus ? on pourra peut-être partir de ça pour expliquer ?

sinon , tu peux chercher sur le net , il y a pas mal de tut sur les pointeurs , même si c'est du C , le principe est le même .

un pointeur contient une adresse qui pointe vers une valeur d'un type donné.

dans le programme dico , le type donné , c'est la structure Noeud.

Code : Tout sélectionner

Structure Noeud
  lettre.s ; lettre contenue dans ce noeud de l'arbre
  entier.b ; flag indiquant si le mot est entier
  *Fils.Noeud[26] 
EndStructure 
Un Noeud occupe 109 octets en mémoire .
4 octets pour stocker l'adresse de lettre.s
1 octet pour entier.b
et 4*26 octets pour Fils (Un pointeur c'est une adresse qui occupe 4 octets)

à chaque fois que tu as besoin d'ajouter un Noeud à l'arbre , il faut allouer 109 octets .

Code : Tout sélectionner

*Noeud.Noeud=AllocateMemory(SizeOf(Noeud))
Et tu récupères l'adresse du Noeud créé dans *Noeud
le .Noeud c'est pour indiquer le type de la donnée sur laquelle pointe *Noeud.
Torp
Messages : 360
Inscription : lun. 22/nov./2004 13:05

Message par Torp »

Voici une petit code :

Code : Tout sélectionner

NewList Dico()
NewList Perso()

For i=1 To 3
  AddElement(Dico())
  Dico()=i
Next

For i=4 To 6
  AddElement(Perso())
  Perso()=i
Next

Procedure affiche(*pointeur,nb)
  For i=1 To nb
    Debug *pointeur
    *pointeur+1
  Next
EndProcedure

affiche(@Dico(),CountList(Dico()))
affiche(@Perso(),CountList(Perso()))
Donc ici, si j'ai bien compris ca m'affiche les adresses mémoire des différentes valeurs de Dico() et Perso(). Mais comment obtenir les valeurs elles-même?

++
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Message par nico »

C'est toi qui l'a écrit ce code?
Torp
Messages : 360
Inscription : lun. 22/nov./2004 13:05

Message par Torp »

Ben ouais, ca fait 15 jours que je lis et relis les post sur les pointeurs (mais j'arive pas à ce que je veux...)
comtois
Messages : 5186
Inscription : mer. 21/janv./2004 17:48
Contact :

Message par comtois »

il ne faut pas confondre une liste chainée avec un tableau , les adresses ne se suivent pas dans une liste chainée .

tu ne peux pas faire une boucle comme dans ton exemple .
la structure d'une liste chainée , c'est

Code : Tout sélectionner

Structure Liste
   untruc.l
   unautre.l
   *Precedent.liste
   *Suivant.liste
EndStructure
ta boucle doit connaitre l'adresse de 'suivant' ou/et l'adresse de 'précedent' pour dérouler le contenu d'une liste chainée.
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Message par nico »

Ben en fait, c'est pas tellement plus compliqué. :mrgreen:

Code : Tout sélectionner

Structure test
  *suivant
  *precedent
EndStructure 

NewList Dico() 
NewList Perso() 

For i=1 To 3 
  AddElement(Dico()) 
  Dico()=i 
Next 

For i=4 To 6 
  AddElement(Perso()) 
  Perso()=i 
Next 

Procedure affiche(*Pointeur.test,nb)
  Debug PeekL(*Pointeur+8)
  For i=1 To nb-1 
    *Pointeur.test=*Pointeur\suivant 
    Debug PeekL(*Pointeur+8)
  Next 
EndProcedure 

affiche(FirstElement(Dico()),CountList(Dico())) 

affiche(FirstElement(Perso()),CountList(Perso()))
Torp
Messages : 360
Inscription : lun. 22/nov./2004 13:05

Message par Torp »

En fait, c'est ca que j'ai du mal a piger :

Code : Tout sélectionner

*Pointeur.test=*Pointeur\suivant 
pourtant j'ai bien lu la doc


Structure Element
*Next.Element ; Pointeur vers l'élément suivant de la liste ou zéro si c'est le dernier élément
*Previous.Element ; Pointeur vers l'élément précédent de la liste ou zéro si c'est le premier élément

; La structure utilisée par la liste suit directement ces 2 variables (ce qui implique que les
; données utilisateurs se situent à l'addresse du nouvel élément + 8 octets.
EndStructure


mais mystère, je comprends pas la logique...

Ma logique aurait été de faire tout simplement ca (faire des sauts de 8 octets):

Code : Tout sélectionner

NewList Dico()
NewList Perso()

For i=7 To 9
  AddElement(Dico())
  Dico()=i
Next

For i=10 To 12
  AddElement(Perso())
  Perso()=i
Next

Procedure affiche(*pointeur,nb)
  *pointeur+8
  For i=1 To nb
    Debug PeekL(*pointeur)
    *pointeur+8
  Next
  
EndProcedure


affiche(FirstElement(Dico()),CountList(Dico()))
Debug "----------------------"
affiche(FirstElement(Perso()),CountList(Perso()))
Mais bon ca marche pas #spin (à part pour la première valeur...)
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Message par nico »

La doc va seulement t'être utile si déjà tu comprends les pointeurs et pas l'inverse.

Si tu veux comprendre le fonctionnement des pointeurs commence par faire simple.
Torp
Messages : 360
Inscription : lun. 22/nov./2004 13:05

Message par Torp »

Ben ouai, mais quand j'essaye de faire simple, ca marche pas... :lol: (exemple ci dessus)
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Message par nico »

Premiere approche:

il y a deux possibilités pour accéder à une variable
- par son nom , l'adressage immédiat
- par son adresse, l'adressage indirect

l'utilisation des pointeurs est liés à la mémoire puisqu'un pointeur est une variable spéciale qui contient toujours une adresse mémoire.

Toutes les variables d'un programme sont contenus en mémoire dans des cases que l'on nomme adresses. A une adresse correspond un octet, une variable occupera un ou plusieurs octets suivant son type.Il faut bien différencier le contenu d'une variable avec son adresse.

Exemple: nombre.w=256 nombre ici est de type word, il est donc définit sur deux octets mais son adresse mémoire est définit sur 4 octets(système window 32bits).

Cela signifie que la variable nombre occupe deux adresses mémoires contenant chacune 1 octet. Une variable peut donc occuper plusieurs adresses mémoires d'octets contigüs.

Connaissant le type d'une variable, seul nous est nécessaire de connaitre la première adresse d'une variable contenant l'octet de poid faible.
la représentation de 256 sur deux octets donne 0 pour le premier et 1 pour le deuxième.

L' adresse mémoire d'une variable ne change pas au cours d'un programme, elle reste la même pendant toute la durée de vie de la variable; c'est window qui la détermine à chaque lancement du programme.

-les variables numériques:
soit une variable: nombre.w
pour connaitre son adresse mémoire (adresse mémoire de l'octet de poid faible) je place un @ devant le nom de la variable: soit @nombre

Ensuite à partir de son adresse, je peux lire ou écrire dans cette variable de deux manières. La première sont les instructions Peek (lecture) et poke (écriture) que l'on complète par une lettre suivant le type de la variable qui va déterminé le nombre d'octets à lire.

Comme nombre est déclaré de type word, nous utiliserons PeekW et PokeW

Code : Tout sélectionner

; Exemple pratique:
nombre.w=256
adresse=@nombre
debug peekW(@nombre)

Code : Tout sélectionner

; Allons un peu plus loin
; nombre est définit sur deux octets et à chaque octet correspond
; une adresse mémoire, nous allons le vérifier
; pour lire chaque octet, nous utiliserons PeekB.

nombre.w=256
adresse1=@nombre
adresse2=@nombre+1
debug peekb(adresse1) ; le premier octet de la premiere adresse
;memoire de la variable est 0 comme expliqué plus haut
debug peekb(adresse2) ; le deuxième contient 1

Code : Tout sélectionner

; De même pour écrire dans une variable avec un pointeur
nombre.w=256
adresse=@nombre
debug peekW(adresse) 
; je change la valeur de la variable nombre
pokeW(adresse,123)
debug peekW(adresse) 
debug nombre
Si tu imprimes bien ce qui a été dit, tu auras une première base.
Dernière modification par nico le dim. 30/janv./2005 18:40, modifié 2 fois.
Torp
Messages : 360
Inscription : lun. 22/nov./2004 13:05

Message par Torp »

C'est très clair, impec, merci. (Désolé de te faire bosser le Dimanche... #spin)
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Message par nico »

L'une des premières utilisations des pointeurs est son utilisation dans les procédures.

un pointeur utilisé dans une procédure peut nous permettre de renvoyer plusieurs valeurs.

Nous connaissons déjà le passage de paramètres par valeur; dans l'exemple qui suit, la procédure va copier les valeurs de nombre1 et nombre2 et les affecter à valeur1 et valeur2. La modification des variables valeur1 et valeur2 ne peut affecter en aucun cas affecter les variables nombre1 et nombre2.

Code : Tout sélectionner

; Exemple de passage de paramètres par valeur
Procedure.l addition(valeur1.l, valeur2.l)
  valeur=valeur1+valeur2
  ProcedureReturn valeur
EndProcedure

nombre1.l=11
nombre2.l=22
Resultat=addition(nombre1, nombre2)
Debug Resultat ; resultat renvoie la valeur 33

Soit le code ci-dessus, imaginons que je souhaite pour deux valeurs obtenir non seulemment l'additon de ces deux valeurs mais aussi leur multiplication sans passer par des variables globales; nous allons devoir utiliser les pointeurs comme ceci:

Dans cet exemple, je vais passer à la procédure non plus les variables elles-mêmes mais leurs adresses respectives à la procédure. La procédure utilisera les pointeurs représentés par *valeur1 et *valeur2 pour pointer vers ces adresses. Les variables nombre1 et nombre2 vont servir de variable d'entrée-sortie puisque dans un premier temps, elles vont fournir leurs valeurs à la procédure et dans un second temps, elles vont nous permettrent de récupérer les résultats de l'addition et de la multiplication. Contrairement au premier exemple la modification du contenu des variables pointés par les pointeurs affectera les variables nombre1 et nombre2.

Code : Tout sélectionner

;  Exemple de passage de paramètres par pointeur (ou adresse)
Procedure.l test(*valeur1.l, *valeur2.l)
  addition=PeekL(*valeur1)+PeekL(*valeur2)
  multiplication=PeekL(*valeur1)*PeekL(*valeur2)
  PokeL(*valeur1,addition)
  PokeL(*valeur2,multiplication)
  ProcedureReturn 1
EndProcedure

nombre1.l=11
nombre2.l=22
Resultat=test(@nombre1, @nombre2)
Debug nombre1 ; résultat de l'addition
Debug nombre2 ; résultat de la multiplication
Dernière modification par nico le lun. 07/févr./2005 17:45, modifié 1 fois.
Torp
Messages : 360
Inscription : lun. 22/nov./2004 13:05

Message par Torp »

Limpide
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Message par nico »

Si tu veux, je peux te faire une introduction pour créer des interfaces avec Pure, je ne vais pas te dire ce qui se cache derrière les interfaces parce que je ne sais pas mais je peux t'expliquer la démarche qui reste simple si tu veux t'essayer à la création d'interface sous PB.
Répondre