Académique Documents
Professionnel Documents
Culture Documents
1
Déclarer une variable, c'est attribuer un nom (l'identificateur) à une zone de
la mémoire centrale.
Cette zone est définie par :
2
Pour accéder à la valeur contenue dans une variable, on utilise
tout simplement son nom.
Mais il peut arriver qu'on veuille accéder à l'adresse d'une variable.
Dans ce cas, on utilise l'opérateur d'adresse & (notation C++)
suivi du nom de la variable.
3
Notion de pointeur
Un pointeur est une variable qui contient l'adresse d'une autre variable.
L'adresse contenue dans un pointeur est celle d'une variable qu'on appelle
variable pointée. On dit que le pointeur pointe sur la variable dont il
contient l'adresse.
Un pointeur est associé à un type de variable sur lequel il peut pointer. Par exemple,
un pointeur sur entier ne peut pointer que sur des variables entières.
4
•Un pointeur est lui-même une variable et à ce titre il possède une adresse.
•Š
Il convient de ne pas confondre l'adresse de la variable pointeur et l'adresse
contenue dans le pointeur (adresse de la variable pointée)
5
Petites révisions...
6
Déclaration d’un pointeur
Par convention, les pointeurs commencent par la lettre p. Il faut déclarer le type
de la variable pointée.
7
En algorithmique en C
Exemple : Exemple :
pvar: pointeur sur entier
int * pvar;
8
Utilisation d’un pointeur
9
10
Soit v une variable de type réel et p un pointeur sur réel. Quelle instruction écrire pour que
p pointe sur v?
(en algorithmique et en C/C++)
11
12
Il est possible d'extraire la valeur d'une variable pointée.
13
14
15
16
Attention à toujours initialiser un pointeur. Un pointeur qui n'est pas initialisé s'appelle un
pointeur pendant.
Un pointeur pendant ne pointe pas nul part mais n'importe où. Si l'on déréférence ce pointeur et
qu'on affecte une nouvelle valeur, on va écraser un emplacement mémoire quelconque,
et on risque de faire planter le programme.
Si on veut que le pointeur pointe nul part, il faut l'initialiser à NIL (not identified link)
ou NULL en C/C++.
C'est l'équivalent de 0 pour les pointeurs. Mais attention, il ne faut jamais déréférencer un
pointeur nul.
Avant de déréférencer un pointeur, il faut toujours s'assurer qu'il n'est pas nul.
17
18
Lors du travail avec des pointeurs, nous avons besoin
- d'un opérateur 'adresse de': &
pour obtenir l'adresse d'une variable.
- d'un opérateur 'contenu de': *
pour accéder au contenu d'une adresse.
- d'une syntaxe de déclaration
pour pouvoir déclarer un pointeur.
L'opérateur 'adresse de' : &
&<NomVariable> fournit l'adresse de la variable <NomVariable>
19
L'opérateur & nous est déjà familier par la fonction scanf, qui a besoin
de l'adresse de ses arguments pour pouvoir leur attribuer de nouvelles
valeurs.
Exemple
int N;
printf("Entrez un nombre entier : ");
scanf("%d", &N);
Attention !
L'opérateur & peut seulement être appliqué à des objets qui se trouvent
dans la mémoire interne, c.-à-d. à des variables et des tableaux. Il ne
peut pas être appliqué à des constantes ou des expressions.
20
21
22
23
24
25
Remarque
26
Quelques opérations élémentaires sur les pointeurs
Priorité de * et &
* Les opérateurs * et & ont la même priorité que les autres opérateurs
unaires (la négation !, l'incrémentation ++, la décrémentation --). Dans
une même expression, les opérateurs unaires *, &, !, ++, -- sont évalués
de droite à gauche.
* Si un pointeur P pointe sur une variable X, alors *P peut être utilisé
partout où on peut écrire X.
27
28
Dans le dernier cas, les parenthèses sont nécessaires:
Comme les opérateurs unaires * et ++ sont évalués de droite à
gauche, sans les parenthèses le pointeur P serait incrémenté,
non pas l'objet sur lequel P pointe.
On peut uniquement affecter des adresses à un pointeur.
29
Le fait qu'un pointeur pointe sur une variable s'appelle indirection
(comme accès indirect). Quand un pointeur pointe sur un autre pointeur, il y a double
indirection.
30
On peut accéder à var par ppvar en utilisant deux fois l'opérateur de déréférencement *
* *ppvar est équivalent à 18 et à *pvar
On pourrait imaginer de la même façon des indirections triples voire quadruples.
31
Transmission de paramètres par adresse
Pour pouvoir modifier la valeur d'un paramètre dans un sous-programme, il fallait passer ce
paramètre non pas "par valeur" "par variable" (ou par référence en C++).
Il existe une autre manière de passer un paramètre permettant de modifier
sa valeur dans un sous-programme:
il s'agit du passage par adresse, (avec le langage C++)
Le passage par adresse consiste à passer, non pas la valeur ni une référence de
la variable paramètre, mais de passer l'adresse de cette variable. Pour cela, lors de l'appel,
l'adresse du paramètre effectif est passée grâce à l'opérateur &.
Dans l'en- tête de la fonction, le paramètre formel est donc un pointeur, déclaré grâce à
l'opérateur *.
Et dans le corps de la fonction, lorsqu'on veut manipuler la valeur de la variable pointée
(le paramètre effectif), on déréférence le paramètre formel grâce à l'opérateur *;
32
Utilisation d'une fonction void qui permet d'échanger les valeurs
de deux paramètres entiers.
33
Lors de l'appel, la valeur pointée par a est x et la valeur pointée par b est
y.
œRemarque:
34
Adressage des composantes d'un tableau
35
Si P pointe sur une composante quelconque d'un tableau,
alors P+1 pointe sur la composante suivante.
Plus généralement:
P+i pointe sur la i-ième composante derrière P et
36
Après l'instruction,
P = A;
37
Comme A représente l'adresse de A[0],
38
Attention !
Il existe toujours une différence essentielle entre un pointeur et le nom
d'un tableau:
39
Résumons
Soit un tableau A d'un type quelconque et i un indice pour les
composantes de A, alors:
40
Exemple
Formalisme Tableau
Int main()
{
int T[10] = {-3, 4, 0, -7, 3, 8, 0, -1, 4, -9};
int POS[10];
int I,J; // i indice courant dans T et j dans POS
for (J=0,I=0 ; I<10 ; I++)
if (T[I]>0)
{
POS[J] = T[I];
J++;
}
return 0;
}
41
Formalisme Pointeur
Int main()
{
int T[10] = {-3, 4, 0, -7, 3, 8, 0, -1, 4, -9};
int POS[10];
int I,J; // i indice courant dans T et j dans POS
for (J=0,I=0 ; I<10 ; I++)
if (*(T+I)>0)
{
*(POS+J) = *(T+I);
J++;
}
return 0;
}
42
Sources d'erreurs
int B[];
déclare un tableau d'éléments du type int
B désigne l'adresse de la première composante de B.
(Cette adresse est toujours constante)
B[i] désigne le contenu de la composante i du tableau
&B[i] désigne l'adresse de la composante i du tableau
43
en utilisant le formalisme pointeur:
B+i désigne l'adresse de la composante i du tableau
*(B+i) désigne le contenu de la composante i du tableau
int *P;
déclare un pointeur sur des éléments du type int.
P peut pointer sur des variables simples du type int
ou sur les composantes d'un tableau du type int.
61
Lien entre enregistrements grâce à un pointeur
Dans un enregistrement, un des champs peut très bien être un pointeur, par exemple sur
un autre enregistrement
62
63
64
A partir d'un élève, on peut connaître les caractéristiques de son
instituteur grâce au pointeur contenu dans l'enregistrement de l'élève.
Le pointeur réalise un lien entre un élève et son instituteur.
Mais l'enregistrement instituteur ne possède pas de pointeur vers la liste
de ses élèves. A partir de l'instituteur, on ne peut pas accéder aux champs
des élèves.
Un pointeur est donc un lien univoque (dans un seul sens)
Plusieurs pointeurs peuvent pointer sur un même enregistrement (ici,
deux élèves ont le même instituteur), mais un pointeur ne peut pointer
que sur une seule variable (enregistrement) à la fois.
65
Comment représenteriez-vous le lien réalisé par le pointeur grâce au modèle entité-
association ?
Un pointeur réalise une association (1,n) mais dans un seul sens. On peut naviguer du
1 vers le n mais pas dans le sens inverse.
66
Allocation dynamique de la mémoire
Il y a deux façons d’allouer un emplacement mémoire pour une variable :
Soit par une déclaration, telle qu’on l’a vu jusqu’à présent
Soit par une allocation dynamique explicite, ce que nous allons voir maintenant
67
68
69
Désallouer la mémoire
70
Pour éviter la saturation de la mémoire, il est donc nécessaire de désallo uer les
emplacements alloués dans le tas. Pour cela, on utilise l’opérateur delete en C++ ou
désallouer en algo, suivi du pointeur qui pointe sur l’emplacement à désallouer.
71
72
73
74
75
76
77
78
79
80
81