Faculté des Sciences de Tunis Leila Ben Othman Programmation C Première année LCE/LCS Année universitaire: 2020 - 2021 Chapitre 6 Les pointeurs Plan 1 Les pointeurs en C Les opérateurs & et * Opérations sur les pointeurs Applications 2 Pointeurs et tableaux 3 Pointeurs et chaînes de caractères 4 Allocation dynamique de la mémoire Les tableaux dynamiques 5 Pointeur et structures Les pointeurs en C Principe Dénition Un pointeur est une variable spéciale qui sert à contenir l'adresse mémoire d'une autre variable. • Accès direct à une variable int X ; X =2; Pour modier a valeur de X , on manipule directement la variable X . • Accès indirect à une variable X int ; =2; (adresse de ) Pour manipuler , on manipulera X P Leila Ben Othman, FST 2020-2021 X X 4 / 33 P. Les pointeurs en C Déclaration P c P c int * ; // On déclare un pointeur sur un entier char * ; // On déclare un pointeur sur un caractère • À la Déclaration, le pointeur ne pointe nulle part (sur rien) ⇒ P contient la valeur NULL ou la valeur numérique 0. • Comparer P à 0 est possible car • Pour acher le contenu de P ==0 ⇔ P ==NULL. P (pas très utile en pratique): printf("Le contenu de P %p", P); • Lorsque P contient la valeur NULL, le compilateur achera sinon, il achera une valeur indiquant une adresse mémoire. Leila Ben Othman, FST 2020-2021 5 / 33 nil, Les pointeurs en C Les opérateurs & et * L'opérateur &: adresse de x x int ; // On déclare un entier int * ; // On déclare un pointeur sur un entier =& ; // On indique que pointe sur la variable P P x P P x • L'opérateur & est l'opérateur d'adresse. • P =&x indique que P contient l'adresse de x . • P ne contient plus la valeur NULL, mais une adresse mémoire de la variable x . Leila Ben Othman, FST 2020-2021 6 / 33 Les pointeurs en C Les opérateurs & et * L'opérateur *: contenu de • L'opérateur * indique le contenu de la variable pointée. P • * : indique le contenu de la variable pointée par x variable ) Exemple 1 int x,y; int *P; x=10; P=&x; *P=20;⇔ x=20 Leila Ben Othman, FST 2020-2021 7 / 33 P (ici, c'est la Les pointeurs en C Opérations sur les pointeurs Aectation Exemple 2 int *p1,*p2; int x; p1=&x; p2=p1; // p1 et p2 pointent sur la même variable : Toute modication du contenu de p1 entraîne une modication du contenu de p2 puisqu'ils pointent sur la même variable. Attention Leila Ben Othman, FST 2020-2021 8 / 33 Les pointeurs en C Opérations sur les pointeurs Incrémentation/Décrémentation Exemple 3 int *p; int x; p=&x; p++; // ⇔ p=p+1 : p pointe sur l'entier suivant p++/p- -: incrémente/décrémente l'adresse contenue dans p de manière qu'elle désigne l'objet suivant/précédent. Ici, dans notre exemple, on incrémente p pour pointer sur l'entier suivant (possible mais n'a pas un intérêt sauf dans le cas de tableau ou de chaînes de caractères). Leila Ben Othman, FST 2020-2021 9 / 33 Les pointeurs en C Opérations sur les pointeurs Comparaison • On peut également comparer deux pointeurs (p1==p2, p1>p2), sachant que p1 et p2 sont deux pointeurs sur des objets de même type, avec les opérateurs : <, >, <=, >=, ==, !=. • La comparaison de deux pointeurs qui pointent dans le même tableau est équivalente à la comparaison des indices correspondants. Si les pointeurs ne pointent pas dans le même tableau, alors le résultat est donné selon leurs positions relatives dans la mémoire. Leila Ben Othman, FST 2020-2021 10 / 33 Les pointeurs en C Opérations sur les pointeurs Priorités des opérateurs • Les opérateurs * et & ont la même priorité que les opérateurs !,++ et (priorité de niveau 2). Dans une même expression, ces opérateurs sont évalués de droite à gauche. Exemple int *p; int x=5; p=&x; y=*p+5; // ⇔ y=x+5 *p=*p+6; // ⇔ x=x+6 *p+=4; // ⇔ x+=4 ++*p; // ⇔ ++x (*p)++; // ⇔ x++ 6= *(p++)⇔ *p++; Leila Ben Othman, FST 2020-2021 11 / 33 Les pointeurs en C Applications Application 1 Somme de deux entiers avec les pointeurs #include <s td i o . h> v o i d main ( ) { int a ,b , c ; i n t ∗ p1 , ∗ p2 ; p r i n t f ( " d o n n e r deux e n t i e r s " ) ; s c a n f ( "%d%d" ,&a ,&b ) ; p1=&a ; p2=&b ; // l a somme de deux e n t i e r s a v e c l e s p o i n t e u r s c=∗ p1+∗ p2 ; p r i n t f ( " l a somme e s t %d" , c ) ; } Leila Ben Othman, FST 2020-2021 12 / 33 Les pointeurs en C Applications Application 2 Permutation de deux entiers avec les pointeurs #include <s td i o . h> v o i d main ( ) { int a ,b , c ; i n t ∗ p1 , ∗ p2 ; p r i n t f ( " d o n n e r deux e n t i e r s " ) ; s c a n f ( "%d%d" ,&a ,&b ) ; p1=&a ; p2=&b ; // p e r m u t a t i o n de deux e n t i e r s a v e c l e s p o i n t e u r s c=∗ p1 ; ∗ p1=∗ p2 ; ∗ p2=c ; p r i n t f ( " a=%d , b=%d" , a , b ) ; } Leila Ben Othman, FST 2020-2021 13 / 33 Pointeurs et tableaux Pointeurs et tableaux (1) • En C, le nom d'un tableau est premier élément du tableau • • • un pointeur constant sur le . On a donc les équivalences suivantes: T[0]⇔ *T T[1]⇔*(T+1) T[i]⇔*(T+i) • On a également les équivalences: • • • T ⇔ &T[0] T+1⇔&T[1] T+i⇔ &T[i] Leila Ben Othman, FST 2020-2021 14 / 33 Pointeurs et tableaux Pointeurs et tableaux (2) • Comme le nom T d'un tableau est un pointeur constant, les instructions suivantes sont donc • • • interdites : T++ T- -; T=P (même si P est un pointeur sur un objet de même type que les éléments de T) • Pour parcourir un tableau, on peut utiliser un deuxième pointeur, comme suit: int T[10]; int *P; P=T; P++; P- -; Leila Ben Othman, FST 2020-2021 15 / 33 Pointeurs et tableaux Application - Somme des éléments d'un tableau (1) version 1 version 2 #include <s td i o . h> #include <s td i o . h> v o i d main ( ) { i n t T[ 5 ] = { 2 , 4 , 1 , 1 3 , 1 0 } ; i n t i , s =0; f o r ( i =0; i <5; i ++) s=s+T [ i ] ; p r i n t f ( " l a somme e s t %d" , s ) ; } Leila Ben Othman, FST 2020-2021 16 / 33 v o i d main ( ) { i n t T[ 5 ] = { 2 , 4 , 1 , 1 3 , 1 0 } ; i n t s =0; i n t ∗p ; f o r ( p=T ; p<T+5; p++) s=s +( ∗ p ) ; p r i n t f ( " l a somme e s t %d" , s ) ; } Pointeurs et tableaux Application - Somme des éléments d'un tableau (2) version 3 #include <s td i o . h> v o i d main ( ) { i n t T[ 5 ] = { 2 , 4 , 1 , 1 3 , 1 0 } ; i n t i , s =0; f o r ( i =0; i <5; i ++) s=s + ∗ (T+i ) ; p r i n t f ( " l a somme e s t %d" , s ) ; } Leila Ben Othman, FST 2020-2021 17 / 33 Pointeurs et chaînes de caractères Pointeurs et chaînes Attention, ces deux déclarations sont diérentes: 1 char ch1[10]="Bonjour";// ch1 est un pointeur constant sur le premier caractère de la chaîne. 2 char *ch2="Bonjour";// ch2 est un pointeur sur une chaîne constante. • Les instructions suivantes sont interdites ch1=ch2; ch1++; ch1=ch1+i; ch2[0]='A'; • Les instructions suivantes sont permises: ch1[0]='A'; ch2=@d'une autre chaîne; ch2="Salut"; Leila Ben Othman, FST 2020-2021 18 / 33 : Pointeurs et chaînes de caractères Application - Parcours d'une chaîne (1) version 1 - classique #include <s td i o . h> #include <s t r i n g . h> v o i d main ( ) { c h a r ch [ 1 0 ] = " B o n j o u r " ; int i =0; f o r ( i =0; i <s t r l e n ( ch ) ; i ++) p r i n t f ( "%c " , ch [ i ] ) ; } Leila Ben Othman, FST 2020-2021 19 / 33 Pointeurs et chaînes de caractères Application - Parcours d'une chaîne (2) version 2 - pointeurs #include <s td i o . h> #include <s t r i n g . h> v o i d main ( ) { c h a r ch [ 1 0 ] = " B o n j o u r " ; c h a r ∗ pc ; f o r ( pc=ch ; pc<ch+s t r l e n ( ch ) ; pc++) p r i n t f ( " c=%c \n" , ∗ pc ) ; } Leila Ben Othman, FST 2020-2021 20 / 33 Pointeurs et chaînes de caractères Application - Parcours d'une chaîne (3) version 3 - pointeurs #include <s td i o . h> #include <s t r i n g . h> v o i d main ( ) { c h a r ch [ 1 0 ] = " B o n j o u r " ; for ( int i =0; i <s t r l e n ( ch ) ; i ++) p r i n t f ( " c=%c \n" , ∗ ( ch+i ) ) ; } Leila Ben Othman, FST 2020-2021 21 / 33 Pointeurs et chaînes de caractères Application - Parcours d'une chaîne (4) version 4 - pointeurs #include <s td i o . h> #include <s t r i n g . h> v o i d main ( ) { c h a r ch [ 1 0 ] = " B o n j o u r " ; int i =0; w h i l e ( ∗ ( ch+i )!= ' \0 ' ) { p r i n t f ( "%c " , ∗ ( ch+i ) ) ; i ++; } } Leila Ben Othman, FST 2020-2021 22 / 33 Pointeurs et chaînes de caractères Application - Parcours d'une chaîne (5) version 5 - pointeurs #include <s td i o . h> #include <s t r i n g . h> v o i d main ( ) { c h a r ch [ 1 0 ] = " B o n j o u r " ; c h a r ∗ pc ; pc=ch ; w h i l e ( ∗ pc != ' \0 ' ) { p r i n t f ( "%c " , ∗ pc ) ; pc++; } } Leila Ben Othman, FST 2020-2021 23 / 33 Pointeurs et chaînes de caractères Fonctions utiles sur les chaînes 1 La fonction strlen fournit en résultat la longueur d'une chaîne dont on lui a transmis l'adresse en paramétre (sans compter le caractère nul '\0' nal). • 2 Exemple strlen ("bonjour") vaudra 7; char * adr = "salut"; l'expression strlen (adr) vaudra 5. strcpy(dest,source): recopie la chaîne située à l'adresse source dans l'emplacement d'adresse dest (y compris le '\0' nal). Il est nécessaire que la taille du second emplacement soit susante pour accueillir la chaîne à recopier. • Exemple char source[10]="Bonjour"; char dest[10]; strcpy(dest,source); Leila Ben Othman, FST 2020-2021 24 / 33 Pointeurs et chaînes de caractères Fonctions utiles sur les chaînes 3 int strcmp (chaine1, chaine2): compare chaine1 à chaine2 et retourne un entier: • > 0 si chaine1 > chaine2 • 0 si chaine1==chaine2 • < 0 si chaine1 < chaine2 • Exemple: char *c1="Bonjour"; char c2[10]="Bonjour"; if (strcmp(chaine1, chaine2) == 0) printf("Les deux chaînes sont identiques"); else printf("Les deux chaînes sont diérentes"); Leila Ben Othman, FST 2020-2021 25 / 33 Pointeurs et chaînes de caractères Fonctions utiles sur les chaînes 4 strcat(chaine1,chaine2) ajoute chaine2 à la n de chaine1. • Exemple char ch1[10]="Bonjour"; char ch2[10]= " Monsieur"; printf("Avant strcat: %s",ch1); /*ch1 contient "Bonjour"*/ strcat(ch1,ch2); printf("Après strcat: %s",ch1); /*ch1 contient "Bonjour Monsieur"*/ Leila Ben Othman, FST 2020-2021 26 / 33 Allocation dynamique de la mémoire Allocation dynamique (1) • Déclaration statique d'un tableau: int T[10]={1,2,3,4,5} ⇒ ici, on réserve au moment de la déclaration de l'espace mémoire pour stocker 10 entiers. (10*sizeof(int)) octets seront réservées pour le stockage de T. • Inconvénients • • • • : Nous avons des données dont nous ne pouvons pas prévoir le nombre et la grandeur lors de la programmation. On ne peut plus ajouter des cases au tableau. Réserver toujours l'espace maximal: du gaspillage de la mémoire. Il nous faut donc un moyen de gérer la mémoire lors de l'exécution du programme. : Réservation de l'espace mémoire au moment de l'exécution du programme et non pas au moment de la déclaration, on parle d'Allocation dynamique de la mémoire. Solution Leila Ben Othman, FST 2020-2021 27 / 33 Allocation dynamique de la mémoire Allocation dynamique (2) • L'allocation dynamique désigne le fait qu'une variable est allouée dynamiquement au cours de l'exécution du programme. • Le langage C met à la disposition du développeur la fonction sizeof() qui eectue le calcul de la taille nécessaire. • Les fonctions de la gestion dynamique de la mémoire (malloc et free) se trouvent dans la bibliothèque <stdlib.h>. Leila Ben Othman, FST 2020-2021 28 / 33 Allocation dynamique de la mémoire Allocation dynamique (3) : l'allocation en C se fait à l'aide de la fonction malloc(). La fonction malloc de la bibliothèque <stdlib> nous aide à à réserver de la mémoire au cours d'un programme. • Allocation • Syntaxe: malloc( <N> ) fournit l'adresse d'un bloc en mémoire de <N> octets libres ou la valeur zéro s'il n'y a pas assez de mémoire. • Exemple int * p ; //pointeur sur entier p= malloc(sizeof(int)); //alloue un espace mémoire pouvant contenir un entier et aecte son adresse à p. • Si nous voulons réserver de la mémoire pour des données d'un type dont la grandeur varie d'une machine à l'autre, nous avons besoin de la grandeur eective d'une donnée de ce type. L'opérateur sizeof nous aide alors à préserver la portabilité du programme. NB: Leila Ben Othman, FST 2020-2021 29 / 33 Allocation dynamique de la mémoire Allocation dynamique (3) • Libération: la libération d'un espace alloué se fait à l'aide de la fonction free(). Exemple ... free(p) ; Leila Ben Othman, FST 2020-2021 30 / 33 Allocation dynamique de la mémoire Les tableaux dynamiques Tableaux dynamiques v o i d main ( ) { int n , i ; i n t ∗T ; p r i n t f ( " Donner n" ) ; s c a n f ( "%d" ,&n ) ; T=( i n t ∗ ) m a l l o c ( s i z e o f ( i n t ) ∗ n ) ; f o r ( i =0; i <n ; i ++) { p r i n t f ( "T[%d]=" , i ) ; s c a n f ( "%d" ,&T [ i ] ) ; } f o r ( i =0; i <n ; i ++) p r i n t f ( " \nT[%d]=%d" , i , T [ i ] ) ; f r e e (T ) ; } Leila Ben Othman, FST 2020-2021 31 / 33 Allocation dynamique de la mémoire Les tableaux dynamiques Tableaux dynamiques Fonction qui permet de créer (dynamiquement) un tableau de n entiers et le retourner. int ∗ remplir_tab ( int n) { i n t ∗T , i ; T=( i n t ∗ ) m a l l o c ( s i z e o f ( i n t ) ∗ n ) ; f o r ( i =0; i <n ; i ++) { p r i n t f ( "T[%d]=" , i ) ; s c a n f ( "%d" ,&T [ i ] ) ; } return T; on ajoute un cast (int*) pour forcer le type de retour de malloc au type du pointeur. NB: Leila Ben Othman, FST 2020-2021 32 / 33 Pointeur et structures Pointeur et structures struct personne { char nom[20] ; int age; }; • On déclare une variable de type pointeur vers une telle structure de la manière suivante : struct personne *p ; • Exemple struct personne pers; // pers est une variable de type struct personne struct personne *p; // p est un pointeur vers une struct personne p = &pers; (*p).age=20 ;// parenthèses obligatoires OU p -> age=20 ; // -> opérateur d'accès Leila Ben Othman, FST 2020-2021 33 / 33