Vous êtes sur la page 1sur 6

Les pointeurs

Formation langage C - 1re Anne

18/01/00

Principe et usage des pointeurs en langage C


1. Adressage de la mmoire de lordinateur
Lorsque lon lance lexcution dun programme, toutes les instructions de ce programme et ses donnes sont charges dans la mmoire de l'ordinateur. De faon trs approximative, on peut considrer cette dernire comme une suite de cases, chacune de ces cases pouvant contenir une variable. Chacune de ces cases a un numro dordre (adresse) dans la mmoire de lordinateur et un contenu (valeur de la variable). Soit le programme suivant : main demo(){ char premier=a, .. Une vue partielle de la mmoire au lancement de ce programme donnerait ("approximativement") Adresse case mmoire Case 0 Case 1 .. Case 10345 Contenu case mmoire peu importe ! Nom variable stocke .peu importe !

.premier

2. Dfinition dun pointeur


Une variable de type pointeur est une variable qui contient l'adresse mmoire o est stocke une autre variable. Par exemple en reprenant l'exemple prcdent et en supposant que la variable panneau est un pointeur qui pointe vers la variable premier on aurait: Adresse case mmoire Case 0 Case 1 .. Case 10345 Contenu case mmoire peu importe ! Nom variable stocke .peu importe !

.premier

Case 108945

10345

.panneau

panneau contient l'adresse laquelle est stocke la variable premier, c'est donc est un pointeur vers premier.

3. Dclaration dun pointeur


On dclare une variable de type pointeur en prcisant vers quel type de variable elle pointe, et en la prcdent par * ; ainsi par exemple: char * verschar; int * versint; ; float *versfloat; FILE * versfile; int (* versfonc) (int, float); verschar est une variable pointeur vers une variable de type char versint est une variable pointeur vers une variable de type int versfloat est une variable pointeur vers une variable de type float versfile est une variable pointeur vers un descripteur de fichier versfonc est une variable pointeur vers une fonction retournant un entier et ayant pour paramtres une variable entire et une variable de type float

Les pointeurs

Formation langage C - 1re Anne

18/01/00

4. Oprateur & et * , initialisation d'un pointeur


Un pointeur, pour pouvoir tre utilis, doit tre initialis (juste aprs sa dclaration le pointeur contient une adresse alatoire c'est dire pointant vers une adresse invalide). Pour obtenir l'adresse de la variable vers laquelle on doit pointer on peut utiliser l'oprateur & Ainsi l'exemple ci dessous: main(){ int aaa=0; int * versint; aaa=5; versint=&aaaa;

/* la variable entire aaa est dclare */ /* la variable versint est dclare comme pointeur vers un entier, et contient initialement une valeur alatoire */ /* aaa est initialise la valeur 5 */ /* l'adresse de la variable aaa est mise dans versint qui est maintenant un pointeur valide */

Reprenons l'exemple ci-dessous en dtaillant l'tat de la mmoire diffrentes tapes: Etape 1: le programme est charg en mmoire et n'a pas commenc son excution Adresse case mmoire Case 0 Case 1 .. Case 078960 Contenu case mmoire peu importe ! Nom variable stocke .peu importe !

.aaa

Case 089000

VALEUR ALEATOIRE .versint

Contenu de la mmoire aprs excution de la ligne aaa=5 ; Adresse case mmoire Case 0 Case 1 .. Case 078960 Contenu case mmoire peu importe ! Nom variable stocke .peu importe !

.aaa

Case 089000

VALEUR ALEATOIRE .versint

Contenu de la mmoire aprs excution de la ligne versint=&aaa; Adresse case mmoire Case 0 Case 1 .. Case 078960 Contenu case mmoire peu importe ! Nom variable stocke .peu importe !

.aaar

Case 089000

078960

.versint

L'oprateur * mis devant un pointeur permet d'obtenir le contenu de la variable pointe par le pointeur; ainsi aprs excution du code prcdent, un printf("%d",*verint) afficherait 5

Les pointeurs

Formation langage C - 1re Anne

18/01/00

Autre exemple: main(){ int aaa,bbb; int * versint; aaa=5; versint=&aaaa; bbb=*versint;

/* les variables entire aaa et bbb sont dclares */ /* la variable versint est dclare comme pointeur vers un entier, et contient initialement une valeur alatoire */ /* aaa est initialise la valeur 5 */ /* l'adresse de la variable aaa est mise dans versint qui est maintenant un pointeur valide */ /* bbb prend pour valeur le contenu de la variable pointe par versint c.a.d la valeur contenue dans aaa */

Exemples dutilisation
1. Utilisation dans les procdures
En C, il est ncessaire de programmer de faon modulaire en utilisant des procdures,; Voici un exemple d'utilisation de procdure: void increment(int bbb) { bbb=bbb+1; printf("\n bbb vaut %d\n",bbb); return; } main(){ int aaa; /* la variable entire aaa est dclare */ aaa=5; /* aaa est initialise la valeur 5 */ increment(aaa); /* appel de incrment avec la variable aaa comme paramtre */ printf("%d",aaa); /* affichage de la valeur contenue dans aaa donc 5 */ } Droulons l'excution du programme: aaa est initialise 5 appel increment en lui "passant" aaa comme paramtre le contenu de aaa est recopi dans le variable bbb locale la procdure increment bbb est incrment de 1 on sort de la procdure increment on affiche le contenu de aaa qui vaut 5

Chaque fois que l'on appelle une procdure, les paramtres passs la procdure au moment de l'appel sont recopis dans des variables locales la procdure (on parle de passage de paramtres par valeur)

Les pointeurs

Formation langage C - 1re Anne

18/01/00

Pour pouvoir modifier la variable aaa depuis la procdure, il faut passer l'adresse de aaa la procdure en paramtre, adresse qui sera recopie dans une variable pointeur locale la procdure incrment; le programme devient alors: void increment(int* bbb) { /* la variable bbb est un pointeur vers un entier */ *bbb=*bbb+1; /* le contenu de la variable pointe par bbb est incrment de 1 */ printf("\n bbb pointe vers une variable entiere contenant %d\n",*bbb); return; } main(){ int aaa; /* la variable entire aaa est dclare */ aaa=5; /*la variable aaa est initialise la valeur 5 */ increment(&aaa); /* appel de incrment avec l'adresse de la variable aaa comme paramtre*/ printf("%d",aaa); /* la variable aaa contient maintenant 6 */ } Droulons l'excution du programme: aaa est initialise 5 appel increment en lui "passant" l'adresse de aaa comme paramtre (&aaa), l'adresse de aaa est recopie dans le pointeur vers entier bbb local la procdure increment, la variable dont l'adresse est contenu dans bbb est incrment de 1 (*bbb=*bbb+1) (donc le contenu de la variable aaa est incrment de 1) on sort de la procdure increment, on affiche le contenu de aaa qui vaut maintenant 6 NB: Ceci explique que lorsqu'on utilise la procdure scanf pour initialiser le contenu de variables, toutes les variables passes scanf doivent tre prcdes par & (i.e. on passe l'adresse des variables initialiser avec les valeurs saisies par l'utilisateur)

2. Utilisation dans les tableaux


En C, on peut dfinir des tableaux; ces tableaux sont stocks comme une suite de variable du mme type; Ainsi la dclaration d'un tableau de 100 entiers: int montableau[100]; Ces 100 entiers sont stocks de manire conscutives, on peut utiliser un pointeur pour parcourir ce tableau Soit le code: int i,montableau[100]; int * versint; versint=&montableau[0]; for (i=0;i<100;i++) *(versint+i)=i; Ce code initialise les 100 entiers du tableau, chacun avec une valeur diffrente (t[n] vaut n). Il est noter que que l'identificateur d'un tableau peut aussi tre considr comme un pointeur vers le 1er lment du tableau ; ainsi l'identificateur montableau est donc aussi un pointeur vers le 1er entier du tableau de 100 entiers, on aurait pu donc tout aussi bien crire: int montableau[100]; int i,* versint; versint=montableau; for (i=0;i<100;i++) *(versint+i)=i;

Les pointeurs

Formation langage C - 1re Anne

18/01/00

3. Allocation de mmoire dynamique


Un des problmes du C est que l'allocation des tableaux est statique (on doit connatre la taille maximum du tableau au moment de la compilation). Pour contourner ce problme, il est possible de demander au systme de nous allouer une portion de la mmoire, le systme nous rendant un pointeur vers cette zone. On utilise pour cela la fonction malloc qui prend comme paramtre la taille en octets de la zone mmoire souhaite . Par exemple pour s'allouer une zone de 100 entiers int * mazone; mazone=(int * ) malloc(100*sizeof(int)); /* dclaration d'un pointeur vers entier */ /* sizeof(int) donne la taille en octets d'une variable de type int ; (*int) convertit le pointeur vers void retourn par malloc en pointeur vers un entier; mazone contient maintenant un pointeur vers une zone mmoire suffisante pour stocker 100 entiers et pas un de plus */

Il est noter que malloc retourne un pointeur vers void ; pour pouvoir mettre l'adresse retourne dans un pointeur vers un entier, il faut convertir (en anglais "cast") l'adresse retourne par malloc en pointeur vers un entier ceci est ralis dans le code ci-dessus par l'opration (int *) Pour initialiser ces 100 entiers, on pourrait modifier le programme comme ci-aprs: int * mazone,i; mazone=(int * ) malloc(100*sizeof(int)); /*allocation d'une zone de stockage pour 100 entiers */ for (i=0;i<100;i++) *(mazone+i)=i; Dans le code ci-dessus mazone contient l'adresse du 1er entier , mazone+1 pointe sur le deuxime entier, mazone+n sur l'entier n-1(n<100). Attention: il ne faut jamais perdre l'adresse du dbut de la zone alloue par malloc sous peine de ne plus pouvoir y accder; vous trouverez ci dessous un exemple dnerie!!! En effet dans l'exemple ci-dessous, on s'alloue une zone de mmoire, et aprs on modifie le pointeur sens y donner accs en y mettant une autre adresse:

int a=5; int * mazone; mazone=(int * ) malloc(100*sizeof(int)); mazone=&a

/* mazone contient l'adresse du dbut d'un bloc suffisant pour stocker 100 entiers */ /* mazone contient maintenant l'adresse de a on ne sait plus o commence la zone de 100 entiers */

Il est noter qu'une faon plus srieuse de coder consisterait tester le code de retour de mallocEn effet, si le systme ne peut vous allouer de la mmoire (memoire sature par exemple), le pointeur retourn vaut NULL et est donc inutilisable par exemple:

int * mazone; mazone=(int * ) malloc(100*sizeof(int)); if(mazone==(int *)NULL) { /* si mazone vaut NULL , le malloc n'a pas march le systme a refus d'allouer la zone de 100 entiers */ printf("\nallocation mmoire refuse\n"); exit(-1); };

Les pointeurs

Formation langage C - 1re Anne

18/01/00

Problmes frquemment rencontrs avec les pointeurs


1. Core dump ou segmentation fault
Lorsqu'un programme se plante en gnrant un "core dump" (cration d'un fichier core contenant l'image de la mmoire utilise par le programme au moment o il s'est plant), c'est gnralement parce que l'on a utilis un pointeur incorrectement initialis Le top 3 des erreurs induisant un core dump : oublier le & devant les variables passes comme paramtres scanf utiliser un pointeur pour stocker/accder des donnes avant d'avoir initialis le pointeur (l'initialisation du pointeur est effectue en y mettant soit l'adresse d'une variable dj existante, soit l'adresse d'une zone alloue par malloc) essayer de mettre plus de donnes dans la zone alloue que prvu initialement (stockage du 101me entier dans une zone alloue par malloc pour 100 entiers)

Pour dpanner il suffit au choix : De regarder attentivement son code (ventuellement rajout de printf pour savoir o on en est au moment du "core dump") Ou bien De compiler avec l'option de debuggage (-g), de rexcuter votre programme pour rgnrer un fichier core; puis de lancer le debuggeur; Avec xxgdb utiliser la commande bt (a donnera la ligne o le programme s'est plant) Avec ddd utiliser le menu status->backtrace

Vous aimerez peut-être aussi