pointeur
Transcript of pointeur
-
8/9/2019 pointeur
1/12
INFOLANGUE
9.2. Les pointeurs
Dfinition: Pointeur
Unpointeurest une variable spciale qui peut contenir
l'adresse d'une autre variable.En C, chaque pointeur est limit un type de donnes. Il peut contenir l'adresse d'une variable
simple de ce type ou l'adresse d'une composante d'un tableau de ce type.
Si un pointeur P contient l'adresse d'une variable A, on dit que
'P pointe sur A'.
Remarque
Les pointeurs et les noms de variables ont le mme rle: Ils donnent accs un emplacement
dans la mmoire interne de l'ordinateur. Il faut quand mme bien faire la diffrence:
* Unpointeurest une variable qui peut 'pointer' sur diffrentes adresses.
* Le nom d'une variable reste toujours li la mme adresse.
9.2.1. Les oprateurs de base
Lors du travail avec des pointeurs, nous avons besoin
- d'un oprateur 'adresse de': &
pour obtenir l'adresse d'une variable.
- d'un oprateur 'contenu de': *
pour accder au contenu d'une adresse.
- d'une syntaxe de dclaration
pour pouvoir dclarer un pointeur.
L'oprateur 'adresse de' : &
&fournit l'adresse de la variable
L'oprateur& nous est dj 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);
-
8/9/2019 pointeur
2/12
Attention !
L'oprateur& peut seulement tre appliqu des objets qui se trouvent dans la mmoire
interne, c.--d. des variables et des tableaux. Il ne peut pas tre appliqu des constantes ou
des expressions.
Reprsentation schmatique
Soit P un pointeur non initialis
et A une variable (du mme type) contenant la valeur 10 :
Alors l'instruction
P = &A;
affecte l'adresse de la variable A la variable P. En mmoire, A et P se
prsentent comme dans le graphique la fin du chapitre 9.1.2. Dans notre
reprsentation schmatique, nous pouvons illustrer le fait que 'P pointe sur A' par
une flche:
L'oprateur 'contenu de' : *
*dsigne le contenu de l'adresse rfrence par le pointeur
Exemple
Soit A une variable contenant la valeur 10, B une variable contenant la valeur 50 et P un
pointeur non initialis:
-
8/9/2019 pointeur
3/12
Aprs les instructions,
P = &A;B = *P;*P = 20;
- P pointe sur A,
- le contenu de A (rfrenc par *P) est affect B, et
- le contenu de A (rfrenc par *P) est mis 20.
Dclaration d'un pointeur
*dclare un pointeur qui peut recevoir des adresses de
variables du type
Une dclaration comme
int *PNUM;
peut tre interprte comme suit:
"*PNUM est du type int"
ou
"PNUM est un pointeur surint"
ou
"PNUM peut contenir l'adresse d'une variabledu type int"
Exemple
Le programme complet effectuant les transformations de l'exemple ci-dessus peut se prsenter
comme suit:
|main()ou
bien|main()
-
8/9/2019 pointeur
4/12
|{ |{
| /* dclarations */ |/* dclarations */
| short A = 10; | short A, B, *P;
| short B = 50; | /* traitement */
| short *P; | A = 10;
| /* traitement */ | B = 50;
| P = &A; | P = &A;
| B = *P; | B = *P;
| *P = 20; | *P = 20;
| return 0; | return 0;
|} |}
Remarque
Lors de la dclaration d'un pointeur en C, ce pointeur est li explicitement un type de
donnes. Ainsi, la variable PNUM dclare comme pointeur surint ne peut pas recevoir
l'adresse d'une variable d'un autre type que int.
Nous allons voir que la limitation d'un pointeur un type de variables n'limine pas seulement
un grand nombre de sources d'erreurs trs dsagrables, mais permet une srie d'oprations
trs pratiques sur les pointeurs (voir 9.3.2.).
En travaillant avec des pointeurs, nous devons observer les rgles suivantes:
Priorit de * et &
* Les oprateurs * et & ont la mme priorit que les autres oprateurs unaires (la ngation !,
l'incrmentation ++, la dcrmentation --). Dans une mme expression, les oprateurs unaires
*, &, !, ++, -- sont valus de droite gauche.
* Si un pointeur P pointe sur une variable X, alors *P peut tre utilis partout o on peut
crire X.
Exemple
Aprs l'instruction
P = &X;
les expressions suivantes, sont quivalentes:
-
8/9/2019 pointeur
5/12
Y = *P+1 Y = X+1
*P = *P+10 X = X+10
*P += 2 X += 2
++*P ++X
(*P)++ X++
Dans le dernier cas, les parenthses sont ncessaires:
Comme les oprateurs unaires * et ++ sont valus de droite gauche, sans les
parenthses lepointeurP serait incrment, non pas l'objetsur lequel P pointe.
On peut uniquement affecter des adresses un pointeur.
Le pointeur NUL
Seule exception: La valeur numrique 0 (zro) est utilise pour indiquer qu'un pointeur nepointe 'nulle part'.
int *P;
P = 0;
Finalement, les pointeurs sont aussi des variables et peuvent tre utiliss comme telles. Soit
P1 et P2 deux pointeurs surint, alors l'affectation
P1 = P2;
copie le contenu de P2 vers P1. P1 pointe alors sur le mme objet que P2.
Rsumons:
Aprs les instructions:
int A;int *P;P = &A;
A dsigne le contenu
-
8/9/2019 pointeur
6/12
de A
&Adsigne l'adresse
de A
Pdsigne l'adresse
de A
*Pdsigne le contenu
de A
En outre:
&P dsigne l'adresse du pointeur P
*Aest illgal (puisque A n'est pas un
pointeur)
Exercice 9.1
main(){
int A = 1;
int B = 2;int C = 3;int *P1, *P2;P1=&A;P2=&C;*P1=(*P2)++;P1=P2;P2=&B;*P1-=*P2;++*P2;*P1*=*P2;A=++*P2**P1;P1=&A;
*P2=*P1/=*P2;return 0;
}
Copiez le tableau suivant et compltez-le pour chaque instruction du programme ci-dessus.
AB C P1 P2
Init. 1 2 3 / /
P1=&A 1 2 3 &A /
-
8/9/2019 pointeur
7/12
P2=&C
*P1=(*P2)++
P1=P2
P2=&B
*P1-=*P2
++*P2
*P1*=*P2
A=++*P2**P1
P1=&A
*P2=*P1/=*P2
9.3.1. Adressage des composantes d'un tableau
Exercice 9.2
Comme nous l'avons dj constat au chapitre 7, le nom d'un tableau reprsente l'adresse de
son premier lment. En d'autre termes:
&tableau[0] et tableau
sont une seule et mme adresse.
En simplifiant, nous pouvons retenir que le nom d'un tableau est unpointeurconstantsur lepremier lment du tableau.
Exemple
En dclarant un tableau A de type int et un pointeur P surint,
int A[10];int *P;
l'instruction:
P = A; est quivalente P = &A[0];
http://www.ltam.lu/cours-c/prg-c96.htm#Heading204http://www.ltam.lu/cours-c/prg-c96.htm#Heading204 -
8/9/2019 pointeur
8/12
Si P pointe sur une composante quelconque d'un tableau, alors P+1 pointe sur la
composante suivante. Plus gnralement,
P+ipointe sur la i-ime composante
derrire P et
P-ipointe sur la i-ime composante
devant P.
Ainsi, aprs l'instruction,
P = A;
le pointeur P pointe sur A[0], et
*(P+1)dsigne le contenu
de A[1]
*(P+2)dsigne le contenu
de A[2]
... ...
*(P+i)dsigne le contenu
de A[i]
Remarque
Au premier coup d'oeil, il est bien surprenant que P+i n'adresse pas le i-ime octetderrire P,
mais la i-ime composante derrire P ...
Ceci s'explique par la stratgie de programmation
'dfensive' des crateurs du langage C:
Si on travaille avec des pointeurs, les erreurs les plus
perfides sont causes par des pointeurs malplacs et
des adresses mal calcules. En C, le compilateur peut
calculer automatiquement l'adresse de l'lment P+i
en ajoutant P la grandeur d'une composante multiplie par i. Ceci est possible, parce que:
- chaque pointeur est limit un seul type de donnes, et
- le compilateur connat le nombre d'octets des diffrents types.
-
8/9/2019 pointeur
9/12
Exemple
Soit A un tableau contenant des lments du type float et P un pointeur surfloat:
float A[20], X;float *P;
Aprs les instructions,
P = A;X = *(P+9);
X contient la valeur du 10-ime lment de A, (c.--d. celle de A[9]). Une donne
du type float ayant besoin de 4 octets, le compilateur obtient l'adresse P+9 en
ajoutant 9 * 4 = 36 octets l'adresse dans P.
Rassemblons les constatations ci dessus :
Comme A reprsente l'adresse de A[0],
*(A+1)dsigne le contenu
de A[1]
*(A+2)dsigne le contenu
de A[2]
...
*(A+i)dsigne le contenu
de A[i]
Attention !
Il existe toujours une diffrence essentielle entre un pointeur et le nom d'un tableau:
- Unpointeurest une variable,
donc des oprations comme P = Aou P++ sont permises.
- Le nom d'un tableau est une constante,
donc des oprations commeA = P ouA++ sont impossibles.
Ceci nous permet de jeter un petit coup d'oeil
derrire les rideaux:
Lors de la premire phase de la compilation, toutes
les expressions de la forme A[i] sont traduites en
*(A+i). En multipliant l'indice i par la grandeur d'une
composante, on obtient un indice en octets:
= *
-
8/9/2019 pointeur
10/12
Cet indice est ajout l'adresse du premier lment du tableau pour obtenir l'adresse de la
composante i du tableau. Pour le calcul d'une adresse donne par une adresse plus un indice
en octets, on utilise un mode d'adressage spcial connu sous le nom 'adressage index':
= +
Presque tous les processeurs disposent de plusieurs registres spciaux (registres index) l'aide
desquels on peut effectuer l'adressage index de faon trs efficace.
Rsumons Soit un tableau A d'un type quelconque et i un indice pour les composantes de A,
alors
Adsigne l'adresse
deA[0]
A+idsigne l'adresse
deA[i]
*(A+i)dsigne le
contenu deA[i]
Si P = A, alors
Ppointe sur
l'lmentA[0]
P+i pointe surl'lment
A[i]
*(P+i)dsigne le
contenu deA[i]
Formalisme tableau et formalisme pointeur
A l'aide de ce bagage, il nous est facile de 'traduire' un programme crit l'aide du
'formalisme tableau'dans un programme employant le 'formalisme pointeur'.
Exemple
Les deux programmes suivants copient les lments positifs d'un tableau T dans un deuxime
tableau POS.
Formalisme tableau
main(){int T[10] = {-3, 4, 0, -7, 3, 8, 0, -1, 4, -9};int POS[10];
int I,J; /* indices courants dans T et POS */for (J=0,I=0 ; I
-
8/9/2019 pointeur
11/12
if (T[I]>0){POS[J] = T[I];J++;}
return 0;
}
Nous pouvons remplacer systmatiquement la notation tableau[I] par*(tableau + I), ce
qui conduit ce programme:
Formalisme pointeur
main(){int T[10] = {-3, 4, 0, -7, 3, 8, 0, -1, 4, -9};int POS[10];int I,J; /* indices courants dans T et POS */
for (J=0,I=0 ; I0)
{*(POS+J) = *(T+I);J++;}
return 0;}
Sources d'erreurs
Un bon nombre d'erreurs lors de l'utilisation de C provient de la confusion entre soit contenu
et adresse, soit pointeur et variable. Revoyons donc les trois types de dclarations que nousconnaissons jusqu'ici et rsumons les possibilits d'accs aux donnes qui se prsentent.
Les variables et leur utilisationint A;
dclare une variable simple du type int
Adsigne le contenu
de A
&Adsigne l'adresse
de A
int B[];
dclare un tableau d'lments du type int
Bdsigne l'adresse de la premire
composante de B.
(Cette adresse est toujours constante)
B[i]dsigne le contenu de la composante i
du tableau
-
8/9/2019 pointeur
12/12
&B[i]dsigne l'adresse de la composante i du
tableau
en utilisant le formalisme pointeur:
B+idsigne l'adresse de la composante i du
tableau
*(B+i)dsigne le contenu de la composante i
du tableau
int *P;
dclare un pointeursur des lments du type int.
P peut pointersur des variables simples du type
int ou
sur les composantes d'un tableau du
type int.
P dsigne l'adresse contenue dans P
(Cette adresse est variable)
*P dsigne le contenu de l'adresse dansP
Si P pointe dans un tableau, alors
Pdsigne l'adresse de la premire
composante
P+idsigne l'adresse de la i-ime composante
derrire P
*(P+i)dsigne le contenu de la i-ime composante
derrire P
Exercice :
Ecrire un programme qui lit deux tableaux A et B et leurs dimensions N et M au
clavier et qui ajoute les lments de B la fin de A. Utiliser le formalisme
pointeur chaque fois que cela est possible.