Informatique 2A Langage C 3 ème séance
Objectifs de la séance 3 Les pointeurs
Introduction Dans la mémoire de l’ordinateur, les données sont stockées sous forme binaire. B01C … B01F La mémoire est divisée en « cases » de taille 8 bits, appelées octets (bytes en anglais) Chacune de ces cases est repérée par son adresse, qui est un nombre hexadécimal.
Introduction En fait, cette « déclaration de variable » réalise deux opérations : float a; - Définition d’une variable pouvant être utilisée dans le programme pour manipuler des données - Allocation d’un espace mémoire où sera stocké le contenu de la variable. a B01C … B01F
Problématique Transmission d’une variable par valeur : float a,b; a=5;b=a; fonc(a); À chaque fois, on copie la valeur d’une variable dans une autre. En particulier, une fonction ne peut pas modifier la valeur d’une variable passée en argument float a; a=5; … fonc(a); printf(«%f\n»,a); fonc(float a) {… a=0; … } On affiche « 5 » ! C’est parce qu’une fonction travaille toujours sur une « copie » des variables, qui sont stockées à une autre adresse.
Les pointeurs Solution : - Transmettre à la fonction l’adresse de la variable plutôt que sa valeur Un pointeur est une variable qui contient l’adresse d’une autre variable. Pour avoir accès à l’adresse d’une variable existante : opérateur & float n; Déclaration d’un pointeur : - Pour manipuler cette adresse, on a donc besoin de définir une variable la contenant : quel est son type ? float *p; p est un « pointeur sur un float » C’est l’adresse de la première case mémoire contenant la donnée &n : représente l’adresse de la variable n Pour avoir accès à la valeur de la variable pointée par p : opérateur * *p représente le contenu de la variable pointée par p
Exemple int n; int *p; … n=5; printf(«%d\n »,n); p=&n; printf(«%d\n »,*p); *p=1; printf(«%d\n »,n); printf(«%d\n »,*p); printf(«%x %x\n »,p,&n); printf(«%x %x\n »,p+1,&n+2 ); 5 5 *p désigne le contenu de la case mémoire pointée par p 1 1 BC01 BC01 (adresse en hexa) BC05 BC09
main( ) { double n; double *p; n=5; printf(«%lf\n»,n); p=&n; printf(«%lf\n»,*p); *p=1; printf(«%lf\n»,n); printf(«%lf\n»,*p); printf(«%x %x\n»,p,&n); printf(«%x %x\n»,p+1,&n+2 );}
Tableaux et pointeurs Autre exemple : déclaration d’un tableau : - Définition d’une variable pouvant être utilisée dans le programme pour manipuler des données - Allocation d’un espace mémoire de 100 cases contigües de 4 octets int tab[100]; En fait, un tableau n’est rien d’autre qu’un pointeur ! int tab[100]; for(i=0;i<n;i++) tab[i]=i; printf(«%d\n »,tab[0]); printf(«%d\n »,*tab); printf(«%d %d\n »,*(tab+1),tab[1]); printf(«%x %x\n»,tab,tab+1); La variable tab est un pointeur qui contient l’adresse de la première donnée contenue dans le tableau AB08 AB0C
Tableaux et pointeurs Avantage : on n’a pas à se préoccuper de l’allocation de mémoire. Inconvénient : on doit connaître la dimension de la variable (nombre d’octets) au moment où on la déclare. Conséquence : on doit connaître la taille d’un tableau à la compilation du programme int n; int tab[n]; … n=100; for(i=1;i<n;i++) tab[i]=0; Autre exemple : déclaration d’un tableau : - Définition d’une variable pouvant être utilisée dans le programme pour manipuler des données - Allocation d’un espace mémoire de 100 cases contigües de 4 octets int tab[100];
Allocation dynamique Solution : - Déclarer une variable contenant une adresse (pointeur) - Allouer l’espace mémoire correspondant à la variable (donc à son adresse) de manière dynamique #include... int dim; int *tab;... dim = 100; tab=malloc(dim*sizeof(int)); for(i=0;i<dim;i++) tab[i]=0; - Fonction d’allocation : malloc(nb octets) - sizeof(type) : retourne le nombre d’octets d’une variable
#include... int dim; int *tab;... dim=100; tab=malloc(dim*sizeof(int)); for(i=0;i<n;i++) tab[i]=0; Allocation dynamique Intérêt : la dimension d’un tableau n’a pas besoin d’être connue pour déclarer la variable qui permet de la manipuler - Il faut aussi libérer l’espace alloué après utilisation : La fonction est: Mais : avant d’utiliser un tableau, il faut absolument allouer son espace mémoire ! … free(tab); free (pointeur) Mais en général, le programme « plante » ici ! Pas de problème à la compilation
#include... int dim; int *tab;... dim=100; tab=malloc(dim*sizeof(int)); for(i=0;i<n;i++) tab[i]=0; Allocation dynamique Intérêt : la dimension d’un tableau n’a pas besoin d’être connue pour déclarer la variable qui permet de la manipuler - Il faut aussi libérer l’espace alloué après utilisation : La fonction est: Mais : avant d’utiliser un tableau, il faut absolument allouer son espace mémoire ! … free(tab); free (pointeur)
Opérations sur les pointeurs - L’opérateur + permet de se déplacer dans la mémoire à partir de l’adresse contenue dans le pointeur. Si p pointe sur une donnée de taille T, p+5 pointe sur la case mémoire située 5T cases plus loin int *tab; tab=malloc(100*sizeof(int)); for (i=0;i<100;i++) *(tab+i)=3*i; printf(«%d,%d,%d\n»,*tab,*(tab+1),*(tab+99)); Autre écriture possible printf(«%d,%d,%d\n»,tab[0],tab[1],tab[99]);
Autres opérations - L’opérateur - permet d’aller dans l’autre sens. - Les opérateurs ++ et -- permettent d’incrémenter et de décrémenter un pointeur. Pointeur NULL : par convention, il pointe sur l’adresse #0000 float *p; p = NULL; Exemple : la fonction malloc renvoie un pointeur sur l’espace mémoire alloué, si l’allocation a pu se faire le pointeur NULL si l’allocation n’a pas pu se faire if (malloc(dim*sizeof(float))!=NULL) for(i=0;i<n;i++) tab[i]=0; else printf(« Allocation impossible\n »);