La présentation est en train de télécharger. S'il vous plaît, attendez

La présentation est en train de télécharger. S'il vous plaît, attendez

CINI – Li115 1 Semaine 10 Les pointeurs ● Notion d'adresse ● Déclaration et utilisation de pointeurs ● "Types pointeur" et initialisation des pointeurs.

Présentations similaires


Présentation au sujet: "CINI – Li115 1 Semaine 10 Les pointeurs ● Notion d'adresse ● Déclaration et utilisation de pointeurs ● "Types pointeur" et initialisation des pointeurs."— Transcription de la présentation:

1 CINI – Li115 1 Semaine 10 Les pointeurs ● Notion d'adresse ● Déclaration et utilisation de pointeurs ● "Types pointeur" et initialisation des pointeurs ● Fonctions : passage de paramètres par référence ● Suppression des variables globales

2 CINI – Li115 2 Notion d'adresse adresse : localisation d'une variable en mémoire 123 int var_a = 123 (stockée à l'adresse @var_a) @var_a pointeur p = adresse de var_a pointeur : variable qui a pour valeur une adresse. on ne s'intéresse pas directement à la valeur d'un pointeur. on s'intéresse à la variable se trouvant à l'adresse contenue par le pointeur Notation pour la suite : @a pour adresse de la variable de nom a

3 CINI – Li115 3 Déclaration *var_pointeur; var_pointeur variable de type pointeur pointeur sur une variable de type int *mon_pointeur; déclaration de la variable mon_pointeur de type pointeur sur un entier réservation de la place mémoire pour stocker une adresse Pas de réservation mémoire pour stocker l'entier

4 CINI – Li115 4 Utilisation Récupérer l'adresse d'une variable : &une_variable Accès à une valeur à partir d'un pointeur : *var_pointeur Attention : on accède à une valeur de type correspondant à la déclaration de mon_pointeur Déclarations ● *var_pointeur; ● une_variable; Exemple :int ma_variable = 123; int *mon_pointeur = &ma_variable; int aux = *mon_pointeur;

5 CINI – Li115 5 -7 Utilisation de son adresse pour accéder à une variable int *p; ? p(adr = @p)i(adr = @i) ? int i; p = &i; @i *p = -7; -7 adresse d'un entier valeur entière CINI_print_string("Valeur : "); CINI_print_int(*p); i = 65; Valeur : - 7 CINI_print_string("Valeur : "); CINI_print_int(*p); Valeur : 65 p i @i 65 p i

6 CINI – Li115 6 Exemples d'utilisation int main(){ int * p1; char * p2; float * p3; int i = 12; char c = 'a'; float f = 12.9; p1 = &i; p2 = &c; p3 = &f; CINI_print_string("Affichage de la valeur de i : "); CINI_print_int(i); CINI_print_string(" ou "); CINI_print_int(*p1); CINI_newline(); CINI_print_string("Affichage de la valeur de c : "); CINI_print_char(c); CINI_print_string(" ou "); CINI_print_char(*p2); CINI_newline(); CINI_print_string("Affichage de la valeur de f : "); CINI_print_float(f); CINI_print_string(" ou "); CINI_print_float(*p3); CINI_newline(); return 0; } Affichage de la valeur de i : 12 ou 12 Affichage de la valeur de c : a ou a Affichage de la valeur de f : 12.900000 ou 12.900000

7 CINI – Li115 7 Utilisation de plusieurs pointeurs int *p1, *p2; ? p1(adr = @p1)a(adr = @a) ? int a,b; p1 = &a; *p1 = -3; ? p2(adr = @p2)b(adr = @b) ? p1 = &b; *p1 = -7; p2 = p1; *p2 = 9; ? p1a ? ? p2 b ? @a-3 ? p1a ? ? p2 b ? @a-3@b -7 p1a ? ? p2 b ? -3@b -7@b9

8 CINI – Li115 8 Types pointeur *pointeur; *pointeur est de type var; &var adresse d'une variable de type Si ≠ alors * ≠ * *pointeur et var de même type pointeur et &var de même type Soient int *p1; float *p2; *p1 (de type int) et *p2 (de type float) ne sont pas de même type p1 et p2 ne sont pas de même type

9 CINI – Li115 9 Initialisation d'un pointeur valeur d'un pointeur = adresse d'une variable adresse d'une variable : - déterminée lors de l'exécution - ne peut pas être modifiée - l'utilisateur ne peut pas la choisir Initialisation d'un pointeur : - à partir d'une variable (&nom_variable) - à partir d'un autre pointeur (correctement initialisé), s'ils pointent sur une variable de même type (pointeur1 = pointeur2) (ne jamais initialiser avec un littéral (valeur numérique), il est impossible de savoir s'il s'agit bien de l'adresse d'une variable)

10 CINI – Li115 10 Initialisation d'un pointeur Exemples : #include int main(){ int * p1, *p2; char * p3, *p4; float * p5, *p6; int i = 12; char c = 'a'; float f = 12.9; p1 = &i; p3 = &c; p5 = &f; p2 = p1; p4 = p3; p6 = p5; return 0; }

11 CINI – Li115 11 Pointeurs : règles de bonne conduite La valeur d'un pointeur doit toujours correspondre à l'adresse d'une variable déclarée Initialisation par une instruction de la forme ● mon_pointeur = &ma_variable; ● avec mon_pointeur et ma_variable déclarées comme suit : ● *mon_pointeur; ● ma_variable; Initialisation par une instruction de la forme ● mon_pointeur1 = mon_pointeur2; ● avec mon_pointeur1 et mon_pointeur2 déclarées comme suit : ● *mon_pointeur1, *mon_pointeur2; ● et mon_pointeur2 a pour valeur l'adresse d'une variable déclarée

12 CINI – Li115 12 Récapitulatif ● Déclaration : * nom_pointeur; ● Indirection : opérateur & (donne l'adresse de la variable) ● nom_pointeur = & nom_variable; – Avec *mon_pointeur; – ma_variable; ● Déréférencement : opérateur * (donne la valeur pointée) ● * nom_pointeur ; → retourne une valeur de type ● Initialisation : ● nom_pointeur = & nom_variable; – Avec *mon_pointeur; – ma_variable; ● mon_pointeur1 = mon_pointeur2; – Avec *mon_pointeur1, *mon_pointeur2; – Et mon_pointeur2 initialisé.

13 CINI – Li115 13 Utilisation des pointeurs int main(){ float * p_f1, * p_f2, * p_f3 ; float f1 = 13.5, f2 =24.6; p_f1 = &f1; p_f2 = &f2; CINI_print_float(*p_f1); CINI_print_string(" "); CINI_print_float(*p_f2); CINI_print_string(" "); CINI_print_float(f1); CINI_print_string(" "); CINI_print_float(f2); CINI_newline(); p_f3 = p_f1; p_f1 = p_f2; p_f2 = p_f3; CINI_print_float(*p_f1); CINI_print_string(" "); CINI_print_float(*p_f2); CINI_print_string(" "); CINI_print_float(f1); CINI_print_string(" "); CINI_print_float(f2); CINI_newline(); return 0 ; } 13.50000 24.60000 13.500000 24.600000 24.60000 13.50000 13.500000 24.600000 Les valeurs pointées par p_f1 et p_f2 ont été échangées. Les valeurs de p_f1 et p_f2 ont été échangées. Les valeurs de f1 et f2 sont inchangées.

14 CINI – Li115 14 Utilisation des pointeurs ● Que se passe-t-il en mémoire ? int main(){ float * p_f1, * p_f2, * p_f3 ; float f1 = 13.5, f2 =24.6; p_f1 = &f1; p_f2 = &f2; CINI_print_float(*p_f1); CINI_print_string(" "); CINI_print_float(*p_f2); CINI_print_string(" "); CINI_print_float(f1); CINI_print_string(" "); CINI_print_float(f2); CINI_newline(); p_f3 = p_f1; p_f1 = p_f2; p_f2 = p_f3; CINI_print_float(*p_f1); CINI_print_string(" "); CINI_print_float(*p_f2); CINI_print_string(" "); CINI_print_float(f1); CINI_print_string(" "); CINI_print_float(f2); CINI_newline(); return 0 ; } main p_f1 p_f2 adr : @f1 p_f3 f1 f2 24.6 13.5 adr : @f2 @f1@f2 @f1 @f2 @f1

15 CINI – Li115 15 Utilisation des pointeurs int main(){ float * p_f1, * p_f2 ; float f1 = 13.5, f2 =24.6, f3; p_f1 = &f1; p_f2 = &f2; CINI_print_float(*p_f1); CINI_print_string(" "); CINI_print_float(*p_f2); CINI_print_string(" "); CINI_print_float(f1); CINI_print_string(" "); CINI_print_float(f2); CINI_newline(); f3 = *p_f1; *p_f1 = *p_f2; *p_f2 = f3; CINI_print_float(*p_f1); CINI_print_string(" "); CINI_print_float(*p_f2); CINI_print_string(" "); CINI_print_float(f1); CINI_print_string(" "); CINI_print_float(f2); CINI_newline(); return 0; } 13.50000 24.60000 13.500000 24.600000 24.60000 13.50000 Les valeurs pointées par p_f1 et p_f2 ont été échangées. Les valeurs de f1 et f2 ont été échangées. Mais les valeurs de p_f1 et p_f2 sont inchangées.

16 CINI – Li115 16 Un nouvel exemple ● Que se passe-t-il en mémoire ? main p_f1 p_f2 adr : @f1 f3 f1 f2 24.6 13.5 adr : @f2 @f1@f2 int main(){ float * p_f1, * p_f2 ; float f1 = 13.5, f2 =24.6, f3; p_f1 = &f1; p_f2 = &f2; CINI_print_float(*p_f1); CINI_print_string(" "); CINI_print_float(*p_f2); CINI_print_string(" "); CINI_print_float(f1); CINI_print_string(" "); CINI_print_float(f2); CINI_newline(); f3 = *p_f1; *p_f1 = *p_f2; *p_f2 = f3; CINI_print_float(*p_f1); CINI_print_string(" "); CINI_print_float(*p_f2); CINI_print_string(" "); CINI_print_float(f1); CINI_print_string(" "); CINI_print_float(f2); CINI_newline(); return 0 ; } adr : @f3 13.524.6 13.5

17 CINI – Li115 17 Retour sur le passage de paramètres ● Jusqu'à présent les paramètres utilisés dans nos fonctions étaient passés par valeur (ou par copie) : ● dans la fonction, on travaille sur une copie des valeurs passées en paramètre ● les modifications réalisées sur ces valeurs ne sont donc pas répercutées en dehors de la fonction ● Exemple : #include void ajouteN(int val, int n){ val = val + n; } int main(){ int val = 45,n = 3; CINI_print_int(val); CINI_print_string(" "); CINI_newline(); ajouteN(val, n); CINI_print_int(val); CINI_print_string(" "); CINI_newline(); return 0; } 4545 4545

18 CINI – Li115 18 AjouteN : exécution main val n 45 3 ajoute N val n 3 45 à l'appel ajouteN(val, n) 48 après l'appel ajouteN(val, n) val = val + n;

19 CINI – Li115 19 Passage par valeur et par référence ● Comment faire pour que la valeur de la variable val du main soit modifiée après l'appel à ajouteN ? – → passer en paramètre non pas la valeur de val mais son adresse, c'est le passage par référence ● Exemple : #include void ajouteN(int* valAd, int n){ *valAd = *valAd + n; } int main(){ int val = 45,n = 3; CINI_print_int(val); CINI_print_string(" "); CINI_newline(); ajouteN(&val, n); CINI_print_int(val); CINI_print_string(" "); CINI_newline(); return 0; } 4545 4848

20 CINI – Li115 20 AjouteN : exécution main val n 3 ajoute N valAd n 3 45 à l'appel ajouteN(&val, n) après l'appel ajouteN(&val, n) @val adr : @val 48 *valAd = *valAd + n;

21 CINI – Li115 21 Fonctions : passage de paramètres par référence Variables accessibles dans une fonction - variables globales, locales ou paramètres - variables dont on a l'adresse (et qui se trouvent encore dans la pile) Passer une adresse en paramètre - passage par référence - permet de lire et de modifier la valeur de la variable dont on a l'adresse

22 CINI – Li115 22 Calcul de la multiplication sans fonction #include int main() { int val1,val2,mult; /* saisie de val1 et val2 */... mult = val1 * val2 ; CINI_print_int(mult); CINI_newline(); return 0; }

23 CINI – Li115 23 Calcul de la multiplication avec une fonction qui retourne le résultat #include int main() { int val1,val2,mult; /* saisie de val1 et val2 */... mult = multiplication1(val1,val2) ; CINI_print_int(mult); CINI_newline(); return 0; } int multiplication1(int a, int b) { return a*b; }

24 CINI – Li115 24 Calcul de la multiplication avec une fonction qui ne retourne pas de valeur Il faut récupérer le résultat grâce à un paramètre #include int main() { int val1,val2,mult; /* saisie de val1 et val2 */... multiplication2(val1,val2,&mult) ; CINI_print_int(mult); CINI_newline(); return 0; } void multiplication2(int a, int b, int *res) { *res = a*b; }

25 CINI – Li115 25 Multiplication : exécution main val1 val2mult adr : @mult après saisie 45 3 multiplication2 a bres 3 45 @mult à l'appel multiplication2(val1,val2,&mult)

26 CINI – Li115 26 main val1 val2mult adr : @mult après saisie 45 3 multiplication2 a bres 3 45 @mult *res = a * b 135 après appel de mutiplication2 45 3 multiplication2 a bres @mult *res = a * b

27 CINI – Li115 27 Calcul de la division euclidienne fonction qui calcule le quotient et le reste de la division de deux entiers positifs a = b * quotient + reste (reste < a) la fonction calcule deux résultats : - obligation de transmettre (au moins) un des résultats par un paramètre - nous choisissons de transmettre les deux résultats en paramètres la fonction prend 4 paramètres : - les entiers a et b - les adresses des variables représentant le quotient et le reste

28 CINI – Li115 28 Calcul de la division euclidienne #include void div_euclid(int a, int b, int *q, int *r) { } int main() { int val1,val2,quot,res; /* saisie de val1 et val2 */... CINI_print_int(quot); CINI_newline(); CINI_print_int(res); CINI_newline(); return 0; } div_euclid(val1,val2,&quot,&res) ; *q = a / b; *r = a % b;

29 CINI – Li115 29 Division euclidienne : exécution main val1 val2 quot après saisie 67 7 div_euclid a b q 7 67 @quot à l'appel div_euclid(val1,val2,&quot,&res) res r @res

30 CINI – Li115 30 main val1 val2 quot après saisie 67 7 div_euclid a b q 7 67 @quot à l'appel div_euclid(val1,val2,&quot,&res) res r @res *q = a / b 9 *r = a % b 4 après appel de div_euclid 67 7 div_euclid a b q @quot à l'appel div_euclid(val1,val2,&quot,&res) r @res *q = a / b *r = a % b Division euclidienne : exécution

31 CINI – Li115 31 Cas d'utilisation du passage par référence ● Le passage par référence est utilisé : ● Si on souhaite modifier une variable déclarée en dehors de la fonction : on passe l'adresse de cette variable en paramètre Par exemple : exemple précédent sur la multiplication → on souhaite modifier une variable déclarée dans la fonction main. ● Si on souhaite que la fonction retourne plusieurs résultats : ajouter autant de paramètres que de résultats Par exemple : fonction calculant le reste et le quotient de la division euclidienne (cf. exemple précédent), fonction calculant les racines d'un polynôme du second degré, fonction calculant le min et le max d'un tableau,... ● Afin d'éviter la recopie de structures importantes (plus de détails dans les UE LI215 et LI213) : on passe en paramètre l'adresse de la structure plutôt que la structure complète → gain en efficacité.

32 CINI – Li115 32 Fonctions et pointeurs : règles de bonne conduite Une fonction ne produit jamais comme résultat l'adresse d'une de ses variables locales (aussi bien comme valeur d'un paramètre passé par référence qu'en valeur de retour) Pourquoi ? Variable locale à une fonction accessible tant que la fonction n'est pas finie son adresse n'est plus pertinente une fois la fonction finie (et l'espace associé libéré dans la pile) L'adresse est alors inutilisable de là où l'appel à la fonction a été effectué

33 CINI – Li115 33 Vers la suppression des variables globales Remplacer chaque variable globale par une variable locale (déclarée dans la fonction main en général) Ajouter un paramètre aux fonctions (autres que main) qui utilisaient la variable globale - passage par valeur si la fonction ne fait que lire la valeur de la variable - passage par référence si la fonction modifie la valeur de la variable

34 CINI – Li115 34 Variables globales : exemple #include int a, b; void f() { b = a*2; } void g() { b = b*a; a = a*2; } int main() { a=2; b=7; f(); g(); CINI_print_int(a); CINI_newline(); CINI_print_int(b); CINI_newline(); return 0; } Affichage 4 8 ab 27 b est modifiée par f() 4 a et b sont modifiées par g() 84

35 CINI – Li115 35 Variables globales : suppression #include int a, b; void f() { b = a*2; } void g() { b = b*a; a = a*2; } int main() { a=2; b=7; f(); g(); CINI_print_int(a); CINI_newline(); CINI_print_int(b); CINI_newline(); return 0; } void f(int v1, int *p1) { *p1 = v1*2; } f(a,&b); void g(int *p1, int *p2) { *p2 = *p2 * *p1; *p1 = *p1 * 2; } g(&a,&b); int a=2, b=7;

36 CINI – Li115 36 Variables globales ou paramètres par référence ? Une variable globale est utilisable partout dans le programme Plus d'inconvénients que d'avantages => NE PAS UTILISER DE VARIABLES GLOBALES mais il est difficile de comprendre comment la valeur d'une variable globale évolue - compréhension du programme difficile - modification du programme difficile - localisation d'une erreur difficile lorsqu'elle porte sur la valeur d'une variable globale


Télécharger ppt "CINI – Li115 1 Semaine 10 Les pointeurs ● Notion d'adresse ● Déclaration et utilisation de pointeurs ● "Types pointeur" et initialisation des pointeurs."

Présentations similaires


Annonces Google