Documente Academic
Documente Profesional
Documente Cultură
A. EL ALLAOUI
1
Les pointeurs
Aujourd’hui, vous allez étudier :
● La définition d’un pointeur
● L’utilisation des pointeurs
● La déclaration et l’initialisation des pointeurs
● L’utilisation des pointeurs avec des variables simples et
des tableaux
● Opérateurs unaires pour manipuler les pointeurs
● Passage de paramètres de fonction par référence
● Le passage des tableaux à une fonction avec les
pointeurs
2
● Utilisation des pointeurs avec les chaines de caractères
Les Pointeurs en C
Les pointeurs jouent un rôle très important dans le langage C.
Ils permettent de manipuler les données dans vos programmes.
p=5A0F3 p i
En accédant à cette adresse, on peut accéder indirectement à la variable et donc la modifier.
La mémoire centrale d’un ordinateur est composée d’un très grand nombre
d’octets. Chaque octet est repéré par un numéro appelé adresse de l’octet.
adresse bits
Octet 0
Octet 1
Octet 2
p Adress p 5 A 0 F 3
Octet 2n+2
i 5A0F3 0 0 0 0 0 1 1 1
Octet 2n+1
5
Les pointeurs: pourquoi ?
• Les pointeurs sont nécessaires pour:
– effectuer les appels par référence (i.e. écrire
des fonctions qui modifient certains de leurs
paramètres)
6
L’étape suivante consiste à stocker l’adresse de vari dans la variable p_vari
en langage C, p_vari pointe sur vari, ou p_vari est un pointeur vers vari
p_vari vari
En résumé
10
Exemple 3
#include <stdio.h>
int main(void)
{
int x=2;
int *p = &x; /* x et *p deviennent synonymes */
printf("La valeur de x est %d\n", *p); /* affiche 2 */
x=5;
printf("La nouvelle valeur de x est %d\n", *p );
/* doit afficher la valeur 5 */
return 0;
} /* doit afficher la valeur 5 */
11
Opérateurs unaires pour manipuler les pointeurs,
& (adresse de) et * (contenu)
Exemple: int i = 8;
printf("VOICI i: %d\n",i);
printf("VOICI SON ADRESSE EN HEXADECIMAL: %p\n",&i);
nom_de_Pointeur = &nom_de_variable
void main(void)
p c
{
0x1132 'a'
char c = 'a', d = 'z';
0x1132
char *p;
p d
0x91A2 'z'
*p = c; 0x91A2
p = &c;
printf("%c\n", *p);
p = &d; L’opérateur * (“valeur pointée par”)
printf("%c\n", *p);
} a
z 12
#include <stdio.h> Exercice
void main() {
int *p, x, y;
p = &x; /* p pointe sur x */
x = 10; /* x vaut 10 */
y = *p - 1; printf(" y= *p - 1 =? = %d\n" , y); y vaut ?
*p += 1; printf(" *p += 1 =? *p = x= ? = %d %d\n" , *p, x); x vaut ?
(*p)++; printf(" (*p)++ =? *p = x= ? = %d %d alors y=%d \n" , *p, x, y);
incrémente aussi de 1 la variable pointée par p, donc x vaut ??.
y vaut 9
14
* et ++
*p++ signifie: int a[]={0,1,5};
*p++ trouver la valeur pointée int*p; !
p=a;//&a[0]==a
*p++ passer à l’adresse suivante Int b=*p++;// p 100 104 108
(*p)++ signifie: a 0 1 5
*++p signifie: a 0 2 5
a 0 2 5
15
Exercice
Conseils
À faire
Veillez à bien comprendre ce que représente un pointeur
et comment il travaille. Le langage C et les pointeurs vont de pair.
À ne pas faire
N’utilisez pas un pointeur qui n’a pas été initialisé. Les résultats
pourraient être désastreux
17
Pointeurs et types de variables
Les différents types de variables du langage C n’occupent pas tous la même
mémoire (int prend quatre octets, une variable double en prend huit, etc)
18
Voici la déclaration et l’initialisation des pointeurs vers ces trois variables :
int *p_vint;
char *p_vchar;
double *p_vdouble;
/* des instructions peuvent être insérées ici */
p_vint = &vint;
p_vchar = &vchar;
p_vdouble = &vdouble;
19
Passage des paramètres par valeur et par
adresse
Syntaxe qui conduit à une erreur: Syntaxe correcte:
a et b:
#include <stdio.h> variables #include <stdio.h>
locales à
void ech(int x,int y) void ech(int *x,int *y)
main(). La
{ {
int tampon; fonction ech int tampon;
tampon = x; ne peut donc tampon = *x;
x = y; pas modifier *x = *y;
y = tampon; leur valeur. *y = tampon;
} On le fait }
donc en
void main() passant par void main()
{ {
l'adresse de
int a = 5 , b = 8; int a = 5 , b = 8 ;
ech(a,b); ces variables. ech(&a,&b);
printf(“ a=%d\n ”, a) ; a = ? printf(“ a=%d\n ”, a) ; a=?
printf(“ b=%d\n ”, b) ;
b=?
printf(“ b=%d\n ”, b) ; b=?
} }
PASSAGE DES PARAMETRES PASSAGE DES PARAMETRES
PAR VALEUR PAR ADRESSE
20
Passage de paramètre par valeur
Lorsqu’on passe un paramètre à une fonction, la fonction ne peut pas modifier la
variable. La variable est automatiquement recopiée et la fonction travaille sur une
copie de la variable. La modification de la copie n’entraîne pas une modification de
la variable originale. C’est le passage de paramètre par valeur.
Exemple:
#include <stdio.h>
void NeModifiePas(int x)
{
x = x+1; /* le x local est modifié, pas le x du main */
}
int main(void)
{
int x=1;
NeModifiePas(x);
printf("%d", x); /* affiche 1 : valeur de x inchangée */
return 0;
} 21
Passage de paramètre par adresse
L’idée du passage par adresse est que, pour modifier une variable par un
appel de fonction, il faut passer en paramètre non pas la variable, mais
un pointeur qui pointe sur la variable.
22
Exemple (PASSAGE DE PARAMÈTRE PAR ADRESSE)
#include <stdio.h>
/* la fonction suivante prend en paramètre un pointeur */
void Modifie(int *p)
{
*p = *p+1; /* p pointe sur x, la copie de p aussi */
/* le x du main est modifié */
}
int main(void)
{
int x=1; /* la varible x n’est pas un pointeur */
int *p;
p = &x; /* pointeur qui pointe sur x */
Modifie(p);
printf("%d", x); /* affiche 2 */
return 0;
}
23
Exemple (PASSAGE DE PARAMÈTRE PAR ADRESSE)
RQ: L’utilisation explicite d’un pointeur dans le main est superflue, on peut
passer directement l’adresse de x à la fonction, sans avoir besoin de
définir une variable de type pointeur dans le main.
#include <stdio.h>
void Modifie(int *p) /* paramètre de type pointeur */
{
*p = *p+1; /* ce pointeur p a pour valeur &x (x du main) */
}
int main()
{
int x=1;
Modifie(&x); /* on passe directement l’adresse de x */
printf("%d", x); /* affiche 2 */
return 0;
}
Exemple
La fonction scanf, qui lit des variables au clavier, doit modifier le contenu
de ces variables. Pour cette raison, les variables sont passées à scanf par24
adresse, ce qui explique la nécessité des & devant les variables.
Pointeurs et tableaux
Les pointeurs sont très utiles pour travailler avec les variables, mais ils le
sont encore plus quand on les utilise avec les tableaux. En fait, les index
de tableaux ne sont rien d’autre que des pointeurs.
Les éléments d’un tableau sont stockés dans des emplacements mémoire
séquentiels, le premier élément ayant l’adresse la plus basse.
26
Stockage des éléments d’un tableau
Conclusion
Vous pouvez constater, à partir de ces exemples, qu’un pointeur devra
être incrémenté de quatre pour accéder à des éléments successifs d’un
tableau de type int, et de huit dans le cas d’un tableau de type double.
Généralement
Pour accéder à des éléments successifs d’un tableau contenant un
type de donnée particulier, le pointeur devra être incrémenté de la
valeur sizeof (typedonnée).
void main(){
int i , dim; // compteur et taille du tableau
long* tableau; // pointeur pour stocker l’adresse du tableau
0 0 0 0 t[2][4],
1 1 1 1
t[2] est l’adresse
2 2 2 2 du début du vecteu
les notations suivantes sont 4 4 4 d’indice 2, c’est un
4 pointeur vers t[2][0]
totalement équivalentes : 5 5 5 5
t[0] équiva &t[0][0]
t[1] équiva &t[1][0]
Espace de stockage du tableau 30
Les opérateurs réalisables sur des pointeurs
Pointeur arithmétique
Nous venons de voir que le pointeur du premier élément d’un tableau doit être
incrémenté d’un nombre d’octets égal à la taille des données du tableau pour
pointer sur l’élément suivant. Pour pointer sur un élément quelconque en
utilisant une notation de type pointeur, on utilise le pointeur arithmétique.
Incrémenter les pointeurs
Incrémenter un pointeur consiste à en augmenter la valeur. Si vous
incrémentez un pointeur de 1, le pointeur arithmétique va augmenter sa valeur
pour qu’il accède à l’élément de tableau suivant.
Exemple
Si ptr_int pointe sur un élément de tableau de type int, l’instruction suivante :
ptr_int++; incrémente la valeur de ce pointeur de 4 pour qu’il pointe sur
l’élément int suivant.
Exemple
ptr_int - - ;
ptr_int - = 2;
32
Les opérateurs réalisables sur des pointeurs
La comparaison de pointeurs
Les opérateurs de comparaison = =, !=, >, <, >=et <= peuvent aussi être
utilisés. Les premiers éléments d’un tableau ont toujours une adresse plus
basse que les derniers. Ainsi, si ptr1et ptr2 sont deux pointeurs d’un même
tableau, la comparaison :
ptr1 < ptr2 : est vraie si ptr1 pointe sur un élément d’index plus petit que
ptr2.
Par exemple, voici, en parallèle, deux suites d’instructions réalisant la
même action : mise à 1 des 10 éléments du tableau t :
33
Les opérateurs réalisables sur des pointeurs
34
Le Tableau vous donne la liste des six opérations possibles avec les pointeurs.
Description
Opérateur
Affectation Vous pouvez attribuer une valeur à un pointeur. Cette valeur doit
correspondre à une adresse obtenue avec l’opérateur d’adresse (&,), ou à
partir d’un pointeur constant.
Adresse de Vous pouvez utiliser l’opérateur d’adresse (&)pour trouver l’adresse d’un
pointeur et obtenir un pointeur vers un pointeur.
Incrément On peut ajouter un nombre entier à la valeur d’un pointeur pour pointer
sur un emplacement mémoire différent.
Décrément On peut soustraire un entier à la valeur d’un pointeur pour pointer sur un
emplacement mémoire différent.
Différence Vous pouvez soustraire un entier de la valeur d’un pointeur pour pointer
sur un emplacement mémoire différent.
Comparaison Ces opérateurs ne sont valides que pour deux pointeurs d’un même
tableau. 35
Précautions d’emploi
38
Les fonctions de concaténation de chaînes
Exemple :
#include <stdio.h>
#include <string.h>
main()
{
char ch1[50] = "bonjour" ;
char * ch2 = " monsieur" ;
printf ("avant : %s\n", ch1) ;
strcat (ch1, ch2) ; Notez la différence entre les deux
printf ("après : %s", ch1) ; déclarations (avec initialisation) de
} chacune des deux chaînes Ch1 et ch2.
La première permet de réserver un
emplacement plus grand que la
constante chaîne qu’on y place
initialement.
RESULTAT
avant : bonjour
après : bonjour monsieur
39
Les fonctions de concaténation de chaînes
La fonction strncat
Cette fonction dont l’appel se présente ainsi :
strncat (but, source, lgmax) (string.h)
travaille de façon semblable à strcat en offrant en outre un contrôle
sur le nombre de caractères qui seront concaténés à la chaîne
d’arrivée (but).
40
Les fonctions de concaténation de chaînes
Exemple : fonction strncat
#include <stdio.h>
#include <string.h>
main()
{
char ch1[50] = "bonjour" ;
char * ch2 = " monsieur" ;
printf ("avant : %s\n", ch1) ;
strncat (ch1, ch2, 6) ;
printf ("après : %s", ch1) ;
}
avant : bonjour
après : bonjour monsi
41
Les fonctions de copie de chaînes
La fonction strcpy
strcpy ( but, source ) (string.h)
recopie la chaîne située à l’adresse source dans l’emplacement
d’adresse destin but. Là encore, il est nécessaire que la taille du
second emplacement soit suffisante pour accueillir la chaîne à recopier,
sous peine d’écrasement intempestif.
Cette fonction fournit comme résultat l’adresse de la chaîne but.
42
Les fonctions de copie de chaînes
La fonction strncpy
43
Les fonctions de copie de chaînes
La fonction strncpy
strncpy ( but, source, lgmax )
L’exemple suivant illustre les deux situations :
Fonctions de recopie de chaînes : strcpy et strncpy
#include <stdio.h>
#include <string.h>
main()
{
char ch1[20] = "123456789 10 11 12" ;
char ch2[20] ;
printf (« Donnez un mot : ") ;
gets (ch2) ;
strncpy (ch1, ch2, 6) ;
printf (" ch1 : %s", ch1) ;
}
Donnez un mot : ahmed alioui
ch1 : ahmed 789 10 11 12
44
Les fonctions de comparaison de chaînes
Il est possible de comparer deux chaînes en utilisant l’ordre des
caractères définis par leur code.
compare deux chaînes dont on lui fournit l’adresse et elle fournit une
valeur entière définie comme étant :
● positive si chaîne1 > chaîne2(c’est-à-dire si chaîne1arrive après
chaîne2, au sens de l’ordre défini par le code des caractères) ;
● nulle si chaîne1 = chaîne2(c’est-à-dire si ces deux chaînes
contiennent exactement la même suite de caractères) ;
● négative si chaîne1 < chaîne2.
45
Les fonctions de comparaison de chaînes
Par exemple (quelle que soit l’implémentation) :
#include <stdio.h>
#include <string.h>
int main () {
char password[] = "123456";
char tmp_password[80];
do {
printf ("Tapez votre mot de passe: ");
gets (tmp_password);
} while (strcmp(password,tmp_password) != 0);
printf ("Bienvenu!");
return 0;
} 46
Les fonctions de comparaison de chaînes
La fonction strncmp :
strncmp ( chaîne1, chaîne2, lgmax )
travaille comme strcmp mais elle limite la comparaison au nombre maximal
de caractères indiqués par l’entier lgmax.
Par exemple :
strncmp ("bonjour", "bon", 4) est positif
tandis que :
strncmp ("bonjour", "bon", 2) vaut zéro.
47
Les fonctions de comparaison de chaînes
48
Les fonctions de recherche dans une chaîne
49
Les fonctions de recherche dans une chaîne
50
La fonction strlen
La fonction strlen fournit en résultat la longueur
d’une chaîne dont on lui a transmis l’adresse en
argument.
Cette longueur correspond tout naturellement au
nombre de caractères trouvés depuis l’adresse
indiquée jusqu’au premier caractère de code nul, ce
caractère n’étant pas pris en compte dans la longueur.
Par exemple, l’expression :
strlen ("bonjour")
vaudra 7; de même, avec :
char * adr = "salut" ;
l’expression :
strlen (adr)
vaudra 5.
51
Les fonctions de conversion
Conversion d’une chaîne en valeurs numériques
53
Les fonctions de conversion
Conversion de valeurs numériques en chaîne
La norme ne prévoit pas de fonctions de conversion d’une valeur
numérique en chaîne, c’est-à-dire de fonctions jouant le rôle symétrique
des fonctions atoi, atol, et atof.
En revanche, elle prévoit une fonction sprintf, symétrique de sscanf.
Elle permet de convertir en chaîne une succession de valeurs
numériques, en y incorporant, le cas échéant, d’autres caractères.
placera dans tab, la chaîne suivante (elle sera bien terminée par un
caractère \0) :
55
Exercice
Écrire un programme qui lit un verbe du premier groupe (se
termine avec "er") au clavier et qui affiche la conjugaison au
présent de l'indicatif de ce verbe.
Contrôlez s'il s'agit bien d'un verbe qui se termine avec "er"
avant de conjuguer.
56