0% ont trouvé ce document utile (0 vote)
13 vues6 pages

Programme VAR VAR VAR VAR VAR: 1.6.4 Les Tableaux À Plusieurs Dimensions

Le document traite des tableaux en programmation, en expliquant comment créer et manipuler des tableaux à une et deux dimensions, ainsi que l'utilisation des pointeurs. Il aborde la notion d'adresse des variables, la définition et le contenu des pointeurs, ainsi que l'importance de leur initialisation pour éviter des erreurs de mémoire. Enfin, il souligne l'utilisation de la valeur NULL pour indiquer un pointeur non initialisé et la manière d'accéder aux adresses des variables définies par l'utilisateur.

Transféré par

EL
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
13 vues6 pages

Programme VAR VAR VAR VAR VAR: 1.6.4 Les Tableaux À Plusieurs Dimensions

Le document traite des tableaux en programmation, en expliquant comment créer et manipuler des tableaux à une et deux dimensions, ainsi que l'utilisation des pointeurs. Il aborde la notion d'adresse des variables, la définition et le contenu des pointeurs, ainsi que l'importance de leur initialisation pour éviter des erreurs de mémoire. Enfin, il souligne l'utilisation de la valeur NULL pour indiquer un pointeur non initialisé et la manière d'accéder aux adresses des variables définies par l'utilisateur.

Transféré par

EL
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

1.6.

Tableaux

PROGRAMME recherche_max
VAR maxi :entier // stocke la valeur du maximum
VAR tabloval :entier [50] // un tableau stockant des valeurs
VAR t_ut : entier // la taille utile du tableau
VAR cpt : entier // index des éléments du tableau
VAR rep : caractere // pour la saisie des valeurs
// étape numéro 1 : initialisation des variables
t_ut → 0 // à ce stade, pas de variable dans le tableau
FAIRE
AFFICHER("entrez une valeur dans le tableau : ")
// valeur rangée dans la case d’indice t_ut
SAISIR(tabloval[t_ut])
// incrémentation de t_ut (car ajout d’un élément)
t_ut → t_ut+1 ;
AFFICHER("une autre saisie ? (o/n) :")
SAISIR(rep);
// la boucle reprend s’il reste de la place
// dans le tableau ET si l’utilisateur souhaite continuer
TANTQUE ((t_ut < 50) ET (rep=’o’))
// pour l’instant, le plus grand est dans la case 0
maxi → tabloval[0]
// cherchons case par case (de l’indice 1 à t_ut-1)
POUR cpt DE 1 A t_ut-1 FAIRE
// si l’on trouve plus grand :
SI (tabloval[cpt] > maxi) ALORS
// la valeur est mémorisée dans maxi
maxi → tabloval[cpt]
FINSI
FAIT

1.6.4 Les tableaux à plusieurs dimensions


© Dunod – La photocopie non autorisée est un délit

Il est possible de définir des tableaux à plusieurs dimensions en les indiquant dans des crochets
successifs lors de la définition du tableau. Pour des propos d’illustration l’exemple se limitera à
deux dimensions, la généralisation à N dimensions est immédiate.
Certains problèmes (notamment les jeux de plateau) ont une représentation naturelle en deux
dimensions avec un repérage en lignes/colonnes ou abscisse/ordonnée.

Exemple
Un damier se représente comme un plateau de 100 cases constitué de 10 lignes et 10 colonnes.
Une programmation d’un jeu de dames utilisera donc de manière naturelle un tableau à deux
dimensions, une pour les lignes, l’autre pour les colonnes. L’état de chacune des cases du damier
sera stocké sous la forme d’un entier (1 pour vide, 2 pour pion blanc, etc.). Ainsi la définition

17
Chapitre 1 • Les bases de la programmation

d’un tableau dans ce cadre sera la suivante :


// 10 lignes, chaque ligne ayant 10 colonnes, soit 100 cases entier damier[10][10]

Cette définition permet de simplifier la représentation et donc la résolution du problème !


Utilisation d’indices dans les tableaux à deux dimensions : chaque élément du tableau est repéré
par un numéro de ligne et un numéro de colonne. Ainsi, si lig et col sont deux indices (donc des
entiers) valides (compris entre 0 et 9 pour l’exemple du damier), damier[lig][col] est l’entier
situé à la ligne lig et à la colonne col du tableau à deux dimensions pris en exemple.

Attention tout de même à cet exemple : les notions de ligne et colonne ne sont pas connues par
l’ordinateur, qui ignore ce qui est fait des valeurs qu’il stocke.

1.7 POINTEURS
Abordons maintenant un point souvent redouté à tort : les pointeurs. Un peu de logique et de
rigueur suffisent à bien comprendre cette notion fondamentale. Une fois de plus, la notion de type
sera essentielle dans cette partie.

1.7.1 Notion d’adresse


Toute variable possède trois caractéristiques : un nom et un type, qui ne peuvent être modifiés au
cours du programme, car fixés au moment de la définition de la variable ; et une valeur qui au
contraire évolue au cours du programme. En réalité, toute variable possède également une autre
caractéristique fondamentale, utilisée en interne par la machine : une adresse. En effet, afin de
mémoriser la valeur d’une variable, l’ordinateur doit la stocker au sein de sa mémoire, mémoire
dont les éléments ou cellules sont repérés par des numéros (de manière analogue à ce qui se passe
dans un tableau en réalité). Le nom de la variable n’est en fait pas utile à la machine, qui se contente
de son adresse ; c’est pour le confort du programmeur que le choix du nom est rendu possible.
Ainsi, il existe une dualité entre le nom de la variable (côté programmeur) et son adresse (côté
machine).
L’adresse d’une variable n’est autre que le numéro de la case ou cellule mémoire que celle-ci
occupe au sein de la machine. Au même titre que son nom, l’adresse d’une variable ne peut pas
varier au cours d’un programme. Il n’est même pas possible de choisir l’adresse d’une variable,
cette adresse est attribuée automatiquement par l’ordinateur.
Chose curieuse, ces adresses de variables seront manipulées sans même connaître leur valeur
exacte. Il suffira de savoir les nommer pour les utiliser.
Pour ce faire, un nouvel opérateur est nécessaire : l’opérateur &. Il se lit tout simplement « adresse
de » et précède uniquement un nom de variable.
Exemple
Soit la définition de variable suivante : VAR x : réel
Cette simple définition attribue à la variable : un nom (x), un type (réel), une valeur (inconnue),
et également une adresse (de manière automatique).

18
1.7. Pointeurs

La notation &x signifie donc : « adresse de x ». La valeur précise de cette adresse ne nous est en
réalité d’aucun intérêt, mais il sera parfois nécessaire de la manipuler.

Toute variable possède une et une seule adresse.

1.7.2 Définition et contenu


Un pointeur est une variable un peu particulière, car elle ne stocke ni un entier, ni un réel, ni un
caractère, mais une adresse. Il est tentant de penser qu’une adresse étant un numéro de cellule dans
la mémoire, elle est comparable à un entier. Cependant, une adresse ne s’utilise pas comme un
entier, puisqu’une adresse ne peut pas être négative, et ne sert pas à faire des calculs. Une adresse
est donc en ce sens un nouveau type.

Notion de contenu
Soit p un pointeur (il sera temps de passer à la syntaxe exacte de définition de pointeur lorsque
toutes les notions nécessaires auront été abordées). p étant un pointeur, il est également une variable,
et donc possède un nom, une valeur (qui est une adresse) et un type.
Un pointeur possède en plus une autre caractéristique, qui est son contenu.
Une adresse est le numéro d’une cellule mémoire, et dans cette cellule, se trouve une valeur.
Cette valeur est appelée le contenu du pointeur, et ne doit pas être confondue avec sa valeur.
Le contenu d’un pointeur est la valeur de la cellule mémoire dont ce pointeur stocke l’adresse.
Puisque ces deux notions sont différentes, il existe une nouvelle notation pour indiquer l’accès à
un contenu : cette notion est l’opérateur * (lire étoile). Cet opérateur est le même que l’opérateur
de multiplication, mais le contexte d’écriture permet à l’ordinateur de reconnaître quelle est la
signification exacte de cet opérateur.
Voici une règle très simple et très utile pour l’utilisation de cet opérateur *: il se lit toujours
comme « contenu de », et non pas « pointeur ». Cette règle évitera de nombreuses confusions par
la suite.
© Dunod – La photocopie non autorisée est un délit

Exemple
Soit ptr un pointeur. Supposons que la valeur de ce pointeur soit 25040 (rappelons que cette
valeur est tout à fait arbitraire). Supposons également que dans la mémoire, à l’emplacement
25040 se trouve la valeur 17.
Dans ce cas, la valeur de ptr, notée ptr, est 25040.
Le contenu de ptr, noté *ptr, est la valeur de la cellule mémoire numéro 25040, c’est-à-dire 17.
*ptr vaut donc 17

Type pointé
Quelle est la syntaxe permettant de définir un pointeur ? Cette syntaxe n’est hélas pas immédiate
(sinon elle aurait déjà été présentée), car le type « pointeur » n’existe pas en tant que tel. Il

19
Chapitre 1 • Les bases de la programmation

est nécessaire d’ajouter des informations supplémentaires afin que l’ordinateur puisse exploiter
correctement ces pointeurs.
En réalité, un pointeur a besoin d’informations sur son contenu, sinon il ne peut rien en faire. La
valeur d’un pointeur n’est qu’une adresse, mais cette information n’est pas suffisante pour gérer les
contenus possibles.
Les différents types déjà évoqués auparavant, entier, reel et caractere, ont des tailles
différentes : un entier occupe quatre octets (ou cellules), un réel en occupe huit et un caractère un
seul. Lorsque l’ordinateur cherche à accéder au contenu d’un pointeur en mémoire, il doit savoir
combien de cellules seront concernées par cette opération. Le type de contenu, encore appelé type
pointé, est indispensable à la définition d’un pointeur. Il lui est même tellement lié qu’un pointeur
ne peut pointer qu’un seul type de contenu.
Il n’existe donc pas de pointeur « générique » vers n’importe quel type de contenu, mais des
pointeurs sur (ou vers) des entier, des pointeurs sur des reel, des pointeurs vers des caractere.
Un pointeur se définit par le type de son contenu. Pour la création d’un pointeur nommé ptr qui
pointe sur des entiers, sa définition s’écrit : « le contenu de ptr est de type entier ». En langage
informatique, c’est cette notation qui sera traduite en définition de variable, de la manière suivante :
VAR *ptr : entier (se lisant « le contenu de ptr est de type entier »). Puisque le contenu de
ptr est de type entier, il est aisé d’en déduire que ptr est un pointeur vers un entier. Attention à ce
point qui ne semble pas très important, mais qui est fondamental.
Il en est de même pour les autres types pointés : la définition d’un pointeur nommé ptr_reel
vers un réel est la suivante : VAR *ptr_reel : réel (se lisant : « le contenu de ptr_reel est de
type reel »). Enfin, la définition d’un pointeur nommé p_cgs vers un caractère est la suivante :
VAR *p_cgs : caractere (se lisant : « le contenu de p_cgs est de type caractere »).
Dans les exemples de définition de pointeurs précédents, la convention de nommage d’un
pointeur veut que son nom débute par ptr ou p_. Cependant un pointeur étant une variable, le
choix de son nom n’est contraint que par les règles de nommage de variables exposées en début de
chapitre.

1.7.3 Initialisation
Les dangers de l’opérateur « * »
Comme pour toute variable, un pointeur doit être initialisé avant d’être manipulé. Comme un
pointeur stocke une adresse, il ne peut être initialisé comme une simple variable de type entier,
reel ou caractere car les adresses sont gérées par la machine et non par l’utilisateur. Accéder à
un contenu est une opération délicate car elle est en relation avec la mémoire, qui est une ressource
indispensable au fonctionnement de l’ordinateur. Chaque programme y stocke les valeurs dont
il a besoin pour s’exécuter correctement. Étant donné qu’un ordinateur de type PC classique fait
cohabiter plusieurs dizaines de programmes différents au même instant, il doit déléguer la gestion
de la mémoire à un programme particulier nommé le système d’exploitation. Le rôle de ce dernier
est de veiller au bon fonctionnement de la partie hardware de l’ordinateur, partie qui concerne la
mémoire.

20
1.7. Pointeurs

En imaginant qu’un pointeur puisse stocker n’importe quelle valeur, accéder au contenu se
révélerait particulièrement dangereux pour la stabilité du système. Un simple exemple devrait vous
en convaincre.
Exemple
Soient la définition et l’initialisation de pointeur suivantes :

VAR *ptr : entier // lire : "le contenu de ptr est de type entier"
ptr → 98120 // initialisation de la valeur du pointeur
// (ptr donne accès à la valeur de ptr)
*ptr → -74 // initialisation du contenu du pointeur ptr
// (*ptr est le contenu de ptr)

Ces simples instructions permettraient au programme d’écrire une valeur arbitraire à n’importe
quelle adresse de la mémoire de l’ordinateur, ce qui n’est pas du goût du système d’exploitation.
Dans le cas d’un accès à une adresse non autorisée, ce dernier met une fin brutale à l’exécution du
programme responsable de cet accès : c’est une des sources des « plantages » des programmes,
et même la source la plus fréquente de ce phénomène.
Afin d’éviter un trop grand nombre d’erreurs de ce type, l’ordinateur (le compilateur en réalité),
refusera d’initialiser un pointeur avec des valeurs arbitraires.

Le seul cas où un pointeur stocke une valeur arbitraire est lorsqu’il vient d’être défini : comme
toute autre variable, il stocke alors une valeur aléatoire. La règle d’or d’utilisation de l’opérateur *
(accès au contenu, ou encore prise de contenu) est la suivante :
l’accès au contenu d’un pointeur ne se fait en toute sécurité que si ce dernier a été correctement
initialisé.

La valeur NULL
Il est possible d’initialiser un pointeur avec une adresse qui est forcément inaccessible, quel que
soit le programme écrit. L’utilité d’une telle initialisation est qu’elle permet de savoir par un simple
test si le pointeur a été initialisé avec une adresse valide, et ainsi éviter les accès malencontreux à
des adresses invalides. L’adresse qui est forcément inaccessible est l’adresse 0. Selon le type de
machines, cette adresse stocke des informations plus ou moins vitales pour le compte du système
© Dunod – La photocopie non autorisée est un délit

d’exploitation. En informatique, l’adresse 0 porte un nom particulier : NULL, qui n’est qu’un autre
nom qui est donné à la valeur 0, mais NULL ne s’utilise que dans des contextes particuliers. De
nombreuses instructions utilisent d’ailleurs cette valeur notée NULL.
Exemple d’utilisation de NULL
PROGRAMME test_NULL
// lire "le contenu de p_val est de type réel" :
VAR *p_val : réel
// initialisation de p_val avec NULL
// que l’on sait inaccessible
p_val → NULL
// plus loin dans le programme...
SI (p_val "= NULL)

21
Chapitre 1 • Les bases de la programmation

// instructions dans lesquelles on peut accéder à *p_val


SINON
AFFICHER("attention, p_val vaut NULL, on ne peut accéder à *p_val")
FINSI
Dans ce cas, le programme affiche un message d’avertissement plutôt que de provoquer une erreur
qui n’est pas évidente à repérer et à corriger : ce type de programmation est à privilégier dans la
mesure où le programmeur maîtrise beaucoup mieux ce qui se passe au sein du programme.

Les adresses de variables existantes


Les variables que l’utilisateur définit au sein de son propre programme ont forcément des adresses
valides. Pour rappel, l’adresse d’une variable est accessible au moyen de l’opérateur &.
Exemple
Voici donc un exemple d’initialisation de pointeur tout à fait valide :

VAR *ptr_c : caractère


VAR lettre : caractère
ptr_c → &lettre

Les types sont compatibles, car ptr_c pointe vers un caractère, autrement dit stocke l’adresse
d’une valeur de type caractère, et &lettre est l’adresse d’une variable de type caractère. Que se
passe-t-il exactement dans ce cas ? Continuons le programme pour illustrer les relations entre
les variables ptr_c et lettre.

lettre → ’Y’
AFFICHER((*ptr_c)+1) // cette instruction affiche ’Z’

Explication avec des valeurs numériques


Lors de la définition de la variable lettre, une adresse lui est automatiquement attribuée par
l’ordinateur. La valeur choisie est par exemple, 102628 (ce nombre n’a aucune importance, mais
aide à illustrer l’explication). L’adresse de lettre (&lettre) vaut donc 102628, et lettre vaut
’Y’ suite à son initialisation par l’instruction lettre → ’Y’.
Suite à l’exécution de l’instruction ptr_c → &lettre, le pointeur ptr_c reçoit 102628 : la valeur
de ptr_c est donc 102628.
Que vaut le contenu de ptr_c (*ptr_c) ? Le contenu du pointeur ptr_c est la valeur stockée en
mémoire à l’adresse 102628 (car ptr_c vaut 102628). Il se trouve que cette adresse est celle de
la variable lettre. Ainsi * ptr_c vaut ’Y’. Il n’est donc pas étonnant que (*ptr_c)+1 soit égal
à ’Z’.

Allocation dynamique de mémoire et commande RESERVER()


Le dernier type (et le plus intéressant) d’initialisation de pointeur consiste à effectuer cette initiali-
sation à l’aide d’une nouvelle adresse autorisée. C’est rendu possible par l’emploi d’une nouvelle
commande dont le but est d’obtenir une zone de stockage mémoire dynamiquement, c’est-à-dire
lors de l’exécution du programme.
Cette commande se nomme RESERVER() et sa syntaxe d’utilisation est la suivante :
RESERVER(pointeur)

22

Vous aimerez peut-être aussi