[EN] [IT]
[INFO] [ACQUÉRIR] [PLAN] [RESSOURCES]
CHAPITRE
APPRENDRE À PROGRAMMER AVEC FUTUREBASIC
NOTES

Variables III

Les pointeurs

Leçon 6 : Eh bien ce nʼest pas trop tôt !


Les pointeurs

Dans les 2 leçons précédentes, on a vu les types de variables que nous pouvons manipuler avec nos instructions BASIC, mais, vous vous en doutez ce nʼest pas encore tout. Lorsque jʼai commencé à faire de la programmation, je lisais des manuels et jʼétais quelquefois consterné de ne pas comprendre certains termes que les auteurs assument en général acquis par leurs lecteurs. Cʼétait exactement le cas pour les pointeurs, et jʼavais fini par imaginer que lorsque ce terme était compris, on pouvait enfin se revendiquer programmeur. Jʼavais donc entouré ce terme dʼune certaine magie faute de le comprendre. Lorsque ce mystère sʼest éclairci, jʼai compris pourquoi les auteurs ne sʼattardent pas sur ce concept. Il est en effet plutôt simple.

Jʼai pris soin jusquʼici, de bien faire la distinction entre une variable et son contenu pour que les idées restent bien en place, mais vous verrez quʼen général, on parlera des variables pour se référer à leur contenu (les valeurs quʼelles contiennent) ou aux variables elles-mêmes en tant que conteneurs.

On a vu précédemment que la variable était un espace en mémoire réservé pour contenir des valeurs qui requièrent plus ou moins dʼoctets. On a vu aussi que cet emplacement en mémoire était en principe fixe et ne changeait pas, seul son contenu pouvait être modifié par nos instructions.

Cependant, Il est parfois très utile de connaître lʼadresse en mémoire dʼune variable. Les adresses en mémoire peuvent être représentées par des entiers longs (4 octets), pour manipuler ces adresses on utilise un pointeur. Un pointeur nʼest autre quʼune variable contenant lʼadresse dʼune autre variable. Un pointeur occupe 4 octets en mémoire comme les entiers longs.

FutureBASIC dispose dʼun raccourci que vous rencontrerez très souvent dans des exemples de code pour signifier lʼadresse dʼune variable plutôt que son contenu : le symbole @ est utilisé (signifiant ‘atʼ [à] comme dans les adresses e-mail). Par exemple :

DIM uneChaine AS STR255
uneChaine = "Je suis une chaîne de caractères"

DIM
adresseChaine AS POINTER
adresseChaine = @uneChaine

Notez quʼen BASIC standard, on écrirait ceci :

adresseChaine = VARPTR(uneChaine)

Cela revient au même, mais il faut bien lʼavouer, le symbole @ est bien plus pratique, cʼest pourquoi nous lʼutiliserons de préférence à la fonction standard VARPTR qui retourne lʼadresse de la variable passée en paramètre.

Lorsque vous déclarez une variable pointeur, vous pouvez, si vous le souhaitez, indiquer au Compilateur comment il doit interpréter les données rangées à lʼadresse qui est pointée, en spécifiant un type de variable, par exemple comme ceci :

DIM unPointeur AS POINTER TO LONG


Notez tout de suite les variantes, plus souvent utilisées pour lʼinstruction ci-dessus :

DIM unPointeur AS PTR TO LONG

ou

DIM unPointeur AS ^LONG

Dans lʼinstruction ci-dessus, vous indiquez au Compilateur que lʼadresse qui sera contenue dans la variable unPointeur sera lʼadresse dʼune variable contenant un entier long. Le type que vous indiquez est arbitraire, en réalité FutureBASIC ne vérifie pas si ce que vous écrivez est exact ou non, cʼest vous qui informez le Compilateur sur la taille de la variable qui se trouve en mémoire à lʼadresse contenue dans le pointeur.

Lorsquʼon fait ses premiers pas en programmation, on se soucie assez peu de lʼadresse des variables, en fait, on sʼintéresse avant tout à leur contenu. Les opérateurs du BASIC, font ce quʼils ont à faire en nous masquant ce qui se passe réellement, par exemple si lʼon écrit ceci :

x = y

Cela revient à assigner une valeur à la variable x. Jusque-là ce nʼest pas bien sorcier. En réalité, le Compilateur copie le contenu trouvé à lʼadresse de la variable y vers lʼadresse de la variable x. Pour nous, cʼest une façon très simple de changer des données en mémoire, on nʼa pas besoin de savoir où se trouve exactement la variable x, ni la variable y.

Vous verrez quʼil y a des circonstances en programmation où il est parfois commode de pouvoir changer directement les valeurs en mémoire. Le BASIC dispose de commandes pour lire et écrire directement des valeurs à des emplacements en mémoire. PEEK et POKE sont les deux commandes qui respectivement vous permettent de lire ou dʼécrire des valeurs à une adresse en mémoire. Il y a plusieurs variantes et aussi chacune dʼelles dispose dʼun raccourci avec FutureBASIC.

PEEK
(ou PEEK BYTE) permet de lire un octet.
Raccourci FB : valeurOctet = |adresseMemoire|

POKE

(ou POKE BYTE) permet dʼécrire un octet.
Raccourci : | adresseMemoire,valeurOctet

PEEK WORD

lit un entier court (2 octets).
Raccourci : valeurEntier = {adresseMemoire}

POKE WORD

écrit un entier court (2 octets).
Raccourci : % adresseMemoire,valeurEntier

PEEK LONG

lit un entier long (4 octets).
Raccourci : valeurEntierLong = [adresseMemoire]

POKE LONG

écrit un entier long (4 octets).
Raccourci FB : & adresseMemoire,valeurEntierLong

Les programmeurs FutureBASIC utilisent très souvent les raccourcis, aussi, il est bon de les apprendre très rapidement pour comprendre de nombreux morceaux de code que vous serez amené à rencontrer.

On a montré précédemment avec deux techniques différentes comment initialiser une variable chaîne avec une chaîne vide :

La façon classique en BASIC :

DIM uneChaine AS STR255
uneChaine = ""


Une façon nouvelle de faire la même chose avec FutureBASIC^3 et sa syntaxe entre crochets :

uneChaine[0] = 0

Ci-dessus la valeur 0 est assignée à lʼoctet de longueur, on peut encore faire la même chose en BASIC standard comme ceci :

POKE BYTE VARPTR(uneChaine),0

On range un octet de valeur 0 à lʼadresse de la chaîne (qui est lʼemplacement en mémoire du premier octet). Et voici, les variations obtenues en utilisant les raccourcis :

POKE VARPTR(uneChaine),0 (BYTE est optionnel, lorsquʼon range un octet)
POKE @uneChaine,0
| @uneChaine,0


Les raccourcis ont tendance à rendre le code un peu ésotérique pour les débutants, mais en fait, ils ne sont pas compliqués à mémoriser. Ils sont fréquemment utilisés par les programmeurs FutureBASIC pour deux raisons : souvent le code à taper est plus court (eh oui, parfois la fainéantise a du bon, car elle vous oblige à chercher les méthodes les plus efficaces pour le moindre effort) et très curieusement vous découvrirez que lorsque vous aurez bien assimilé les raccourcis, ils rendront le code plus facile à lire. La deuxième raison est que le code exécutable généré par le Compilateur est un peu plus compact et un peu plus rapide. De nos jours, cela a moins dʼimportance, les machines sont très rapides et elles disposent de grandes quantités de mémoire, mais vous verrez que dans certaines circonstances, vous aussi, vous rechercherez le maximum de vitesse dans lʼexécution de vos programmes. Peut-être rejoindrez vous un jour ces programmeurs que l'on rencontre souvent avec FutureBASIC qui s'amusent par goût ou par fierté à se lancer des défis afin de produire du code le plus compact et le plus rapide possible.

Dans la plupart des cas, le Compilateur crée les variables en allouant un bloc mémoire de la dimension adéquate lorsquʼil rencontre une instruction DIM. En nous autorisant lʼaccès aux fonctions de la Toolbox du Macintosh, FutureBASIC^3 nous permet de créer nous-mêmes nos blocs de mémoire comme le fait le Compilateur. Cette opération sʼexécute en demandant à la Toolbox de créer un pointeur dont on indique la taille. On a cependant, très peu lʼoccasion dʼutiliser les fonctions relatives aux pointeurs dans la mesure où FutureBASIC se charge très bien des opérations de maintenance par lʼintermédiaire des variables que nous lui demandons de créer.

Une variable pointeur contient donc lʼadresse dʼun bloc en mémoire, mais il faut prêter une attention particulière à ce genre de variable, car en accédant directement à la mémoire on travaille sans filet. En effet, rien ne vous empêche de ranger des valeurs à une adresse quelconque en mémoire, si bien que si votre pointeur contient une adresse erronée, la valeur sera inscrite quand même à lʼadresse indiquée et vous pouvez ainsi modifier par inadvertance des valeurs maintenues dans ces blocs pour dʼautres variables de votre programme, ce qui donne souvent des résultats inattendus et des erreurs difficiles à corriger comme des blocages du programme sur des instructions innocentes, ou pire encore, si vous accédez à des zones mémoire réservées à dʼautres applications ou même au Système, vous serez très susceptible dʼexpérimenter un crash de la machine.

Un deuxième inconvénient survient lorsquʼon crée soi-même ses pointeurs pour y stocker des valeurs au gré de ses besoins, car les blocs de mémoire que vous réservez ne sont pas rendus disponibles automatiquement une fois que votre code nʼen a plus lʼutilité et si lʼon ne sʼen débarrasse pas explicitement, ils finissent par saturer la mémoire inutilement. On est donc obligé de faire soi-même le ménage, en demandant au Memory Manager de libérer la mémoire occupée par les pointeurs devenus inutiles aux besoins du programme. Non seulement cette maintenance est nécessaire, mais la mémoire est utilisée moins efficacement à cause de la fragmentation engendrée lors de la libération des blocs de mémoire. Nous reviendrons ultérieurement sur le Memory Manager et l'importance de son travail.



[Precédent] [Table des Matières] [Suivant]
{Note}
© 2000 Pix&Mix
Tous droits réservés

FutureBASIC est une marque déposée appartenant à Staz Software, Inc et utilisée avec permission.