Vous êtes sur la page 1sur 16

Chapitre 6: Les pointeurs

En C, les pointeurs jouent un rle primordial dans la dfinition de fonctions. Ils prsentent un moyen, entre autres, de changer le contenu de variables dclares dans d'autres fonctions. Ainsi le traitement de tableaux et de chanes de caractres dans des fonctions serait impossible sans l'utilisation de pointeurs. En outre, les pointeurs nous permettent d'crire, avec une certaine discipline, des programmes clairs, simples, compacts, efficients et fournissent souvent la seule solution raisonnable un problme. Ils permettent par exemple deffectuer les appels par rfrence, de manipuler des structures de donnes dynamiques comme les listes, les arbres, etc. et finalement dallouer dynamiquement de la place mmoire. Cependant, il faut tre trs attentif en utilisant cet outil puissant, car les pointeurs ne doivent pas tre employs ngligemment. En effet, il est assez facile de crer des pointeurs qui pointent n'importe o et malheureusement parfois sur des zones mmoires utilises par le systme.

6.1. Un pointeur: qu'est-ce que c'est ?


La mmoire est dcoupe en octets. Chaque octet est repr par son numro d'ordre, ou adresse. Un pointeur pointe vers un octet en indiquant son adresse. En pratique, un pointeur est une variable qui contient une valeur de type adresse et pas la valeur de la variable. Cest donc une variable dont le contenu est l'adresse mmoire d'une autre variable, c'est-dire la position en mmoire de cette autre variable. Un pointeur permet donc de retrouver la valeur d'une variable (par son adresse) et d'y accder en la rfrenant (et donc, par rfrence). On dit aussi que le pointeur renvoie ou pointe vers la variable concerne, cela via son contenu consistant en ladresse de cette variable. Exemple 1 Pointeur p: Adresse 5A0F3: valeur 5A0F3 (adresse hexadcimale de la case mmoire o se trouve la valeur de i) valeur 35 (correspondant la valeur d'un entier i)

p 5A0F3 60C19 Mmoire

i 35 5A0F3

Noms des variables Valeurs des variables Adresses mmoires

Un pointeur contenant ladresse dune variable, donc pointant vers celle-ci Si un pointeur p contient l'adresse d'une variable i , on dit que 'p pointe sur i'.

Chap. 6: Les pointeurs

65

Remarque Les pointeurs et les noms de variables ont le mme rle: Ils donnent accs un emplacement dans la mmoire interne de l'ordinateur. Il faut quand mme bien faire la diffrence: Un pointeur est une variable qui peut pointer sur diffrentes adresses. Le nom d'une variable reste toujours li la mme adresse. Il faut signaler que lon parle parfois de pointeur dont la valeur est constante (adresse constante). Par exemple, les noms des tableaux sont des pointeurs constants quivalents ladresse de la premire composante du tableau concern.

6.2. Dclaration de pointeurs


Un pointeur doit tre dclar par rapport un certain type de variables (char, int, float,). La dclaration dune variable de type pointeur seffectue comme pour une variable, en utilisant le symbole * devant lidentificateur du pointeur. Cela se fait par l'instruction: type *nom_du_pointeur; Par exemple, on peut dclarer les pointeurs suivants : int *p, *q ; /* 2 pointeurs p et q vers des entiers */ char *s; /* 1 pointeur s vers un caractre */ /* 1 pointeur pr pointant sur float */ float *pr; double **tab; /* 1 pointeur tab pointant sur un pointeur qui pointe sur
un flottant double */

L'oprateur * dsigne en fait le contenu de l'adresse.

6.3. Valeurs pointes et adresses.


La manipulation des pointeurs ncessite une bonne matrise des deux oprateurs & et * . Lors de lutilisation des pointeurs, nous avons besoin : - d'un oprateur 'adresse de': & pour obtenir l'adresse d'une variable, - d'un oprateur 'contenu de': * pour accder au contenu d'une adresse, - d'une syntaxe de dclaration pour pouvoir dclarer un pointeur. L'oprateur & nous est dj familier par la fonction scanf, qui a besoin de l'adresse de ses arguments pour pouvoir leur attribuer de nouvelles valeurs. Pour fixer les ides, prenons un exemple: int i = 35; int *p; p = &i; printf ("%d",*p);

/* dclaration : p est un pointeur pointant sur un entier */ /* initialisation du pointeur p, affecte l'adresse de la variable i. p pointe maintenant vers la zone mmoire o est stocke la variable i*/ /*affiche la valeur pointe par p, donc 35*/ Introduction au Langage de Programmation C

Mohammed BENJELLOUN

Chap. 6: Les pointeurs

66

p contient ladresse de la variable i alors que *p contient le contenu de la variable, donc 35. On peut donc accder la valeur de la variable en passant par son adresse et en utilisant loprateur contenu de. Remarque : Comme pour les autres variables, la valeur dune variable pointeur est indfinie lors de la dclaration et le reste tant quon ne lui affecte pas explicitement une valeur. Dans la reprsentation schmatique, nous pouvons illustrer le fait que 'p pointe sur i' par une flche: p: 5A0F3 35 :i

Il est mme possible de modifier les valeurs pointes. Les instructions suivantes donneront par exemple: int i = 35, j; int *p, *q; p = &i; j = *p; *p = 10; i= 20; (*p)++; q = p; i=50 ; *(q+1)= 29;

/* p=&i = 0x0012ff7c et *p = 35 */ /* j = 35 */ /* *p=i=10 */ /* i=*p=20 */ /* est quivalent i++, donc i=*p= 21 */ /* p et q pointent maintenant ensemble vers la mme adresse 0x0012ff7c */ /* i=*p=*q= 50 */ /* on range 29, 4 cases mmoire plus loin *p=*q=i reste 50 */

- p pointe sur i, - le contenu de i (rfrenc par *p) est affect j, et - le contenu de i (rfrenc par *p) est mis 10, - le contenu de p est mis 20, - le contenu de p est mis 21, - le contenu de q est mis 21. - p et q pointent vers la mme adresse et leur contenu est gal 21. - le contenu de p et de q est mis 50. - le contenu de p et de q nest pas chang par *(q+1)= 29; . Les oprateurs * et & ont la mme priorit que les autres oprateurs unaires (la ngation !, l'incrmentation ++, la dcrmentation --). Dans une mme expression, les oprateurs unaires *, &, !, ++, -- sont valus de droite gauche. Nous conseillons au programmeur de faire attention lors de lutilisation des oprateurs unaires ++ et --, notamment avec les pointeurs. Ainsi *p++ est diffrent de (*p)++.

Mohammed BENJELLOUN

Introduction au Langage de Programmation C

Chap. 6: Les pointeurs

67

Si au lieu de : i= 20; (*p)++; on avait crit : i= 20; *p++;


/* i=*p=20 */ // est quivalent *p puis p++ : i=20 *p= ? le nouveau p ne pointe pas vers i /* i=*p=20 */ /* est quivalent i++, donc i=*p= 21 */

Comme les oprateurs unaires * et ++ sont valus de droite gauche, sans les parenthses, le pointeur p serait incrment, donc ne pointerait plus sur i, mais sur une valeur peut-tre inconnue de lutilisateur.

6.4. Pointeurs et arguments de fonctions


Les pointeurs sont fort utiles lors du passage de paramtres modifiables dans des fonctions (paramtres d'entre/sortie et paramtres de sortie). Rappelons ici que les paramtres sont passs en rgle gnrale par valeur. Ceci implique qu' l'entre de la fonction, une copie de la valeur de ces paramtres est faite. La fonction travaille elle-mme sur cette copie, et donc, en aucun cas, ne modifie la valeur originale. Nous avons vu que si nous voulons sortir les modifications dune variable vers la fonction appelante, linstruction return est notre disposition. Mais dans le cas o il sagit de retourner plusieurs variables, il faut trouver une autre solution. Soit par exemple, la fonction suivante: void echange (int a, int b) { int tmp=a; a = b; b = tmp; } C'est une fonction syntaxiquement correcte, qui a certainement comme but d'intervertir les valeurs des variables entires a et b. Malheureusement, code comme telle, elle n'aura aucun effet! En effet, ce sont des copies (en variables temporaires locales) des variables a et b qui seront interverties, mais pas les originaux! Les instructions: int x = 5, y = 10; printf("%d %d\n", x, y); echange ( x, y); printf("%d %d\n", x, y);

/* affiche 5 /* affiche 5

10 */ 10 */

donneront le mme affichage avant et aprs l'appel la fonction echange, c'est--dire que celle-ci n'aura pas fait son boulot!
Mohammed BENJELLOUN
Introduction au Langage de Programmation C

Chap. 6: Les pointeurs

68

Utiliser linstruction return peut ventuellement nous sortir une valeur, mais pas les deux. Nous avons vu cependant un exemple o les paramtres sont modifiables: il s'agit des tableaux. En fait, ceux-ci sont passs par l'adresse de leur composante 0, comme nous le verrons par la suite. Contrairement au passage par valeur, le passage par rfrence ou par adresse, n'effectue pas de copie du paramtre: il passe une rfrence sur celui-ci. En consquence, une fonction passant des paramtres par rfrence ne pourra jamais prendre (en paramtre) une constante, mais uniquement une variable. Ce mode de passage peut donc tre intressant, surtout si un paramtre est important en terme de taille (un tableau, une structure, ...). Cest le mode quil faut utiliser si nous voulons modifier les paramtres dune fonction. Ceci se fait en C de manire explicite, en utilisant les pointeurs. Le programme suivant nous donne l'criture correcte de notre fonction echange. Son appel dans la fonction main affiche les rsultats escompts.
#include <stdio.h> void echange (int *pa, int *pb){ int tmp=*pa; *pa = *pb; *pb = tmp; printf("%d %d\n", *pa, *pb); } void main(){ int x=5, y=10; printf("%d %d\n",x,y); echange ( &x, &y); printf("%d %d\n",x,y); } // affiche 10 5

// affiche 5 // affiche 10

10 5

Programme 6.1 Nous attirons lattention sur la manire dcrire len-tte de la dfinition et lappel de la fonction : Dfinition : void echange (int *pa, int *pb) Appel : echange ( &x, &y); Lappel de la fonction seffectue en lui passant les adresses ou les rfrences des variables. A travers ces rfrences, ce sont les objets dsigns par x et y qui seront manipuls dans la fonction et qui seront donc modifis. C'est d'ailleurs pour cela que nous avions utilis l'criture : scanf ("%d", &n); pour lire une variable entire n. On saisit ici le contenu de l'adresse &n c'est--dire lentier n lui-mme. On peut donc aussi procder ainsi: TYPE *adr; scanf("%Desc_TYPE",adr); On saisit ici le contenu de l'adresse adr.
Mohammed BENJELLOUN
Introduction au Langage de Programmation C // TYPE: int, float, char, ... // Desc_TYPE : d, f, c,

Chap. 6: Les pointeurs

69

Programme 6.2 : Cet exemple a t trait auparavant dans le chapitre consacr aux fonctions (Programme 5.2). Maintenant que nous connaissons les pointeurs, ce programme devient :
#include <stdio.h> void Modifier(int *v); void main(void) { int v = 5; Modifier(&v); printf("main: var = %d\n", v); } void Modifier(int* v) { *v *= 100; printf("Modifier: *v = %d son adresse=%p\n", *v, v); son Modifier*/ }

// Variable locale main // Appel de la fonction Modifier /* Affiche la valeur de v aprs passage dans la fonction Modifier*/

// Modifie la copie /* Affiche la valeur de *v et de adresse v dans la fonction

Lexcution de ce programme donne le rsultat suivant :


Modifier: *v = 500 son adresse = 0012FF7C main: var = 500

donc la modification effectue par la fonction Modifier est transmise main. Il faut noter aussi la manire dafficher une adresse (%p ou %X) : printf("Modifier: *v = %d son adresse=%p\n", *v, v); affiche Modifier: *v = 500 son adresse = 0012FF7C printf("Modifier: *v = %d son adresse=%X\n", *v, v); affiche Modifier: *v = 500 son adresse = 12FF7C

6.5. Pointeurs et tableaux


En C, il existe une relation trs troite entre les tableaux et les pointeurs. Cela est d au fait que le nom dun tableau reprsente un pointeur sur le premier lment du tableau. Comme les tableaux sont stocks de manire contigu en mmoire, chaque opration avec des indices de tableaux peut aussi tre exprime l'aide de pointeurs. Ainsi, accder la composante suivante du tableau peut seffectuer en passant l'adresse suivante. Rappelons galement que, comme paramtre de fonction, un tableau est en fait pass par l'adresse de sa premire composante. Il est donc modifiable, car pass implicitement par adresse.

Mohammed BENJELLOUN

Introduction au Langage de Programmation C

Chap. 6: Les pointeurs

70

6.5.1. Oprateur d'indexation La smantique de l'oprateur d'indexation consiste dire qu'aprs les dclarations : int T[N]; int i; T[i] est quivalent *(T + i). T est une constante reprsentant ladresse de llment T[0] (T=&T[0]). Lexpression *T dsigne T[0]. Laccs un lment du tableau peut se faire non seulement par le nom du tableau accompagn dun indice, mais aussi par un pointeur manipul par des oprations spcifiques de pointeurs. Si le pointeur p repre l'lment d'indice i du tableau T, p + j (de mme p-j) est une valeur de type pointeur qui repre l'lment d'indice i + j (i j) du tableau T (en supposant qu'ils existent). Si on a : #define N 100 int T[N]; int * p ; p = &T[0];
/* p repre le premier lment de T*/

Dans linstruction ci-dessus, remarquez que nous rangeons dans p ladresse du premier lment du tableau. Il aurait t incorrect dcrire : p = &T ; car T est un nom du tableau et est vu par le compilateur comme une constante ; alors que loprateur & sapplique une variable pour en fournir ladresse. En revanche, nous aurions pu crire : p=T ; L'expression p + N est valide, mais p - 1 et p + N + 1 ne le sont pas. Aprs les dclarations int T[10]; int * p; on peut crire p = &T[4]; et utiliser l'oprateur d'indexation sur p, p[0] tant T[4], p[1] tant T [5], etc. p peut donc tre utilis comme un sous-tableau de T.
Mohammed BENJELLOUN
Introduction au Langage de Programmation C

Chap. 6: Les pointeurs

71

Voici encore un autre exemple de manipulation de pointeurs : #define N 10 int T[N]; int *p,*q,*r,*s; p = &T[0]; q = p + (N-1); r = &T[N-1]; s = r - (N-1);
/* p repre le premier lment de T quivalent p=T */ /* q repre le dernier lment de T */ /* r repre le dernier lment de T */ /* s repre le premier lment de T */

Programme 6.3:
#include <stdio.h> void main() { int T[6] = { 2, 6, 4, 5, 10, 8 }; int *p; p = T; printf("%d\n", *p); p++; printf("%d\n", *p); p += 4; printf("%d\n", *p); }

// p repre le premier lment de T // affiche 2 // affiche 6 // affiche 8

Ce programme peut tre reprsente par le graphique suivant :

1000 T p Adresse mmoire

p++ p+=4 2 6 4 5 10 8 1000 1004 1008 1012 1016 1020

Mohammed BENJELLOUN

Introduction au Langage de Programmation C

Chap. 6: Les pointeurs

72

Programme 6.4 :
#include <stdio.h> void main(){ int T[6] = { 2, 4, 6, 8, 10, 12 }; int *p, i; printf("T = %p, &T[0] = %p\n", T, &T[0]); p =T; printf( "for1 ...\n"); for (i=0; i<6 ; i++){ printf("p+%d = %p, p[%d]= %3d *(p+%d) = %3d\n", i,p+i, i, p[i], i, *(p+i)); } printf( "END for1 ...\n"); *p++ = 15; printf( "for2 ...\n"); for (i=0; i<6 ; i++){ printf("T[%d]=%3d,p+%d = %p, p[%d]= %3d *(p+%d) = %3d\n", i, T[i], i,p+i, i, p[i], i, *(p+i)); } printf( "END for2 ...\n"); }

Lexcution de ce programme donne le rsultat suivant :


T = 0012FF68, &T[0] = 0012FF68 for1 ... p+0 = 0012FF68, p[0]= 2 *(p+0) = p+1 = 0012FF6C, p[1]= 4 *(p+1) = p+2 = 0012FF70, p[2]= 6 *(p+2) = p+3 = 0012FF74, p[3]= 8 *(p+3) = p+4 = 0012FF78, p[4]= 10 *(p+4) = p+5 = 0012FF7C, p[5]= 12 *(p+5) = END for1 ... 2 4 6 8 10 12

for2 ... T[0]= 15, p+0 = 0012FF6C, p[0]= 4 T[1]= 4, p+1 = 0012FF70, p[1]= 6 T[2]= 6, p+2 = 0012FF74, p[2]= 8 T[3]= 8, p+3 = 0012FF78, p[3]= 10 T[4]= 10, p+4 = 0012FF7C, p[4]= 12 T[5]= 12, p+5 = 0012FF80, p[5]= 1245120 END for2 ...

*(p+0) = 4 *(p+1) = 6 *(p+2) = 8 *(p+3) = 10 *(p+4) = 12 *(p+5) = 1245120

6.5.2. Passage de tableau comme pointeur en paramtre Du fait de la conversion d'un identificateur de type tableau en l'adresse du premier lment, lorsqu'un tableau est pass en paramtre effectif, c'est cette adresse qui est passe en paramtre. Le paramtre formel correspondant devra donc tre dclar comme tant de type pointeur. Le passage dun tableau comme paramtre, peut tre dclar soit comme tableau, soit comme pointeur. Les dfinitions suivantes sont quivalentes :
Mohammed BENJELLOUN
Introduction au Langage de Programmation C

Chap. 6: Les pointeurs

73

void Fonction(int Tab[], int dim){ } void Fonction(int *p, int dim){ } Examinons une fonction dont l'objet est de calculer la somme des composantes d'un vecteur. Nous pouvons crire classiquement cette fonction comme: int somvec ( int n, int x [] ){ int s = 0; int i; for (i=0; i<n; i++) s += x[i]; return s; } Nous pouvons galement, de manire rigoureusement quivalente, l'crire comme: int somvec ( int n, int *x ){ int s = 0; int i; for (i=0; i<n, x++; i++) s += *x; return s; } Si nous avons un vecteur entier x[5] aux valeurs successives 1,2,3,4,5, les appels: somvec ( 5, x); somvec ( 5, &x[0]); somvec (4, &x[1]); somvec (4, x); seront tous corrects, et donneront comme retour les valeurs respectives 15, 15, 14 et 10. Ce qui ne serait par contre pas correct, ce sont les appels somvec (5, &x); somvec (5, x[0]);
//adresse de l'adresse de la composante 0! // passage de la valeur de x[0] et non de son adresse

Ces expressions par pointeur dans l'criture de fonctions procdant sur des tableaux seront fortement exploites avec l'utilisation des chanes de caractres, comme nous allons le voir par la suite. Remarque : On a vu que lon peut remplacer par exemple void Fonction(int Tab[], int dim) par void Fonction(int *p, int dim)

Mohammed BENJELLOUN

Introduction au Langage de Programmation C

Chap. 6: Les pointeurs

74

Cependant, cela peut prsenter un inconvnient. En effet, lorsqu'on lit l'en-tte de cette fonction, il n'est pas possible de savoir si le programmeur a voulu passer en paramtre un pointeur vers un int (c'est--dire un pointeur vers un seul int), ou au contraire sil a voulu passer un tableau, c'est--dire un pointeur vers une zone de plusieurs int.

6.5.3. Pointeurs et chanes de caractres Les chanes constantes de caractres sont, comme on lavait dj vu, un cas particulier de tableaux char et possdent une adresse mmoire. Laffectation suivante : char *p= "Hello world"; (equivalent char *p; p="Hello world";) signifie que lon dfinit une variable pointeur p de type char* laquelle on affecte, comme valeur initiale, non pas la chane "Hello world", mais ladresse de cette dernire. Nous pouvons reprsenter p par ce graphique: p 'H' 'e' 'l' 'l' 'o' ' ' 'w' 'o' 'r' 'l' 'd' '\0'

Les instructions suivantes montrent comment afficher toute la chane de caractres en partant de p : char * p = "Hello world"; for (p = p; *p != '\0'; p++) { printf("%c ", *p); // Affiche : H e l l o w o r l d } Nous conseillons de n'utiliser ce type de dclaration char *p= "Hello world"; que pour des chanes constantes, qui ne seront pas modifies en cours de programme. Cela signifie que la fonction suivante (par exemple) provoquera une erreur l'excution sur certaines machines : p[0] = toupper(p[0]);
//fonction toupper : conversion des minuscules ! majuscules

L'utilisation du mot-cl const permet de dtecter cette erreur la compilation : const char *p= "Hello world"; En plus si p change de valeur, le tableau de dpart ne sera plus accessible, et donc la mmoire qu'il occupait serait perdue. char * p = "Hello world"; p= "Salut"; while (*p != '\0'){ printf("%c ", *p++); }

// Affiche : S a l u t

Mohammed BENJELLOUN

Introduction au Langage de Programmation C

Chap. 6: Les pointeurs

75

Voici un autre exemple o laffectation dune nouvelle valeur un pointeur sur une chane de caractres constante, fait perdre la chane constante initiale. D'autre part, un pointeur sur char a l'avantage de pouvoir pointer sur des chanes de n'importe quelle longueur: char * p = "Hello world"; char * q= "Salut"; q=p ; //(1) //(2) //(3)

La reprsentation graphique de ces instructions est la suivante : (1) p (2) q (3) p

'H' 'e' 'l' 'l' 'o' ' ' 'w' 'o'

'r'

'l' 'd' '\0'

'S' 'a' 'l' 'u' 't' '\0 '

'H' 'e' 'l' 'l' 'o' ' ' 'w' 'o'

'r'

'l' 'd' '\0'

'S' 'a' 'l' 'u' 't' '\0 '

Les affectations discutes ci-dessus ne peuvent pas tre effectues avec des tableaux de caractres. En effet, les chanes de caractres dclares comme pointeurs peuvent tre initialises avec =, affectes avec =. Lorsquelles sont dclares comme tableaux, elles peuvent tre initialises avec =, mais pas affectes avec =. Les instructions suivantes provoquent une erreur la compilation : char tab[] = "Hello world"; tab= "Salut"; Dans ce cas, le compilateur alloue un tableau de 11 caractres qu'il initialise avec les caractres H, e, l, l, o, , w, o, r, l, d, et \0. Toute occurrence de tab sera convertie en type pointeur vers char. Laffectation dans ce cas doit tre effectue par la fonction que lon a dj vue strcpy. Le code suivant corrige lerreur : char tab[] = "Hello world"; strcpy(tab,"Salut"); Afficher ce qui se trouve dans le tableau tab, peut tre ralis, par : soit : printf("%s\n", tab) ; soit : puts(tab) ; soit : for (i = 0; tab[i] != '\0'; i++) { printf("%c", tab[i]); }

Mohammed BENJELLOUN

Introduction au Langage de Programmation C

Chap. 6: Les pointeurs

76

Remarque : NULL est une constante symbolique de type pointeur qui joue le rle d'adresse indfinie. Cela sert pour tester si un pointeur pointe vers un objet ou pas. NULL est gale 0 dans <stdio.h>. Lorsqu'on veut prciser qu'un pointeur p ne pointe sur rien, on lui affecte la valeur particulire NULL : p=NULL; Il ne faut jamais tenter d'accder une zone mmoire inaccessible, car cela peut amener des erreurs l'excution, comme dans le code suivant : int *p=NULL; printf("%d\n",*p); // Erreur l'excution : Segmentation fault. L'accs l'adresse NULL est toujours interdit.

6.6. Allocation dynamique de la mmoire


Nous avons vu que l'utilisation de tableaux nous force rserver plus de places en mmoire que ce quil en faut. Si nous gnrons ces donnes, dont nous ne pouvons pas prvoir le nombre et la taille lors de la programmation, il nous faut, en plus de lutilisation des pointeurs, des moyens pour rserver et librer de la mmoire au fur et mesure que nous en avons besoin. Nous parlons alors de l'allocation dynamique de la mmoire. Cette gestion dynamique de la mmoire est possible, grce aux fonctions suivantes : void * malloc(taille) : cette fonction de la librairie <stdio> alloue dynamiquement, en mmoire, un espace de taille octets. Elle retourne un pointeur sur le premier octet ainsi allou. Il est de type "void" (c'est--dire vers un objet de type "non prcis"). Il importe alors de dfinir le type de donne qui sera contenu dans cet espace mmoire. Cela est spcifi devant lappel de la fonction. Prenons l'exemple de la squence dappel suivante : s = (char *) malloc(30 * sizeof(char)); La conversion est ralise ici grce la mention (char *) qui transforme la valeur retourne par malloc en une adresse vers un char (pour que l'affectation s=... soit valide.). Cette instruction permet une rservation dynamique d'un espace mmoire de 30 octets, qui permettra de stocker une chane d'au plus 29 caractres utiles (il faut prvoir la place du caractre \0). L'oprateur sizeof nous aide prserver la portabilit du programme. Ainsi sizeof(char) (qui vaut d'ailleurs 1) nous donne le nombre doctets quun caractre occupe en mmoire. Si cette allocation na pu tre satisfaite, par manque de place par exemple, malloc retourne NULL ; sinon elle retourne l'adresse du premier octet de la zone alloue.

Mohammed BENJELLOUN

Introduction au Langage de Programmation C

Chap. 6: Les pointeurs

77

void free(void *ptr) : cette fonction libre la zone mmoire pointe par ptr, dans le cas o cette zone mmoire a t alloue dynamiquement par un appel la fonction malloc. On utilisera en principe cette fonction autant de fois que la fonction malloc. Si ptr pointe sur le dbut d'une zone mmoire alloue dynamiquement, free(ptr) libre cette zone mmoire. Il ne faut jamais librer une zone mmoire dj libre. Le systme pourrait alors gnrer des erreurs de nature imprvisible. Pour pouvoir utiliser les fonctions malloc et free, il est ncessaire dinclure le fichier d'en-tte standard stdlib.h : #include <stdlib.h> En plus de la fonction malloc, il existe dautres fonctions pour rserver de la mmoire. Il sagit de : char * calloc( unsigned N, unsigned taille_type); Rserve N lments de taille_type octets chacun. Elle retourne un pointeur sur le premier octet ainsi allou ou NULL si lallocation na pu tre satisfaite. L'espace allou est initialis 0. char *s; s = (char *)calloc(250, sizeof(char));

// rserve 250 octets initialiss '\0'

void * realloc( void *block, unsigned taille); Cette fonction permet de changer la taille affecte au bloc de mmoire fourni par un prcdent appel malloc() ou calloc(). Le programme suivant nous donne un aperu sur la manire dallouer et de librer la mmoire:
#include <stdio.h> #include <stdlib.h> #define alloue(nb,type)

(type *)malloc(nb*sizeof(type))

void main(){ float *adr1; int *adr2 adr1 = alloue(4, float); adr2 = alloue(10, int); *adr1 = -37.28; *adr2 = 123; printf("adr1 = %p adr2 = %p r1 = %f r2 = %d\n",adr1,adr2,*adr1,*adr2); free(adr1); // Libration de la mmoire free(adr2); }

Programme 6.5

Mohammed BENJELLOUN

Introduction au Langage de Programmation C

Chap. 6: Les pointeurs

78

Ce quil faut au moins retenir : Quand une fonction1 appelle une autre fonction2 et que la premire a besoin des modifications des variables passes en paramtres de la seconde, il faut passer les paramtres par adresse. Ceci se fait de manire explicite, en utilisant les pointeurs. Quand le paramtre de la fonction est un pointeur, la dclaration et lappel de la fonction, en comparaison un paramtre traditionnel, se font comme suit : dclaration : func(int x) func(int *px) appel : func( y) func(&y) Attention aux erreurs suivantes :
int i = 35; int *p; p = &i; //OK printf ("%d",*p); int *pt=NULL; printf("%d\n",*pt); int i = 35; int *p; *p = i; //Erreur printf ("%d",*p);

//Erreur : L'accs l'adresse NULL est toujours interdit

(*p)++

est diffrent de

*p++

Pour rserver de la mmoire un pointeur, on utilise par exemple la fonction malloc. Dans un programme, il faut autant de fonctions free que de fonctions malloc.

Exercices
6.1. Les oprations daffectation suivantes sont-elles correctes ?
a. b. c. d. e. f. int a,*p ; a=*p ; *p=&a; *p=*(&a); a=p; p=&a; a=(int)p;

6.2. Quaffiche le programme suivant? Pourquoi ?


#include <stdio.h> void main() { int *p, x, y; p = &x; x = 10; y = *p - 1; printf(" y= *p - 1 =? = %d\n" , y); *p += 1; printf(" *p += 1 =? *p = x= ? = %d %d\n" , *p, x); (*p)++; printf(" (*p)++ =? *p = x= ? = %d %d alors y=%d \n" , *p, x, y); *p=0;

Mohammed BENJELLOUN

Introduction au Langage de Programmation C

Chap. 6: Les pointeurs printf(" *p=0 x=? = %d\n" , x); *p++; *p=20; printf(" *p++ x=? = %d\n" , x); }

79

6.3. Que faut-il ajouter ce programme pour quil puisse fonctionner correctement ?
void main() { int *p ; *p = 10; printf(" *p = %d\n" , *p); }

6.4. Transformer lexercice 5.3. en remplaant les fonctions MIN et MAX par une seule fonction MIN_MAX qui dtermine le minimum et le maximum dun vecteur de nombres rels entrs au clavier. Ces deux valeurs doivent tre transmises au main. 6.5. Ecrire la fonction Crypt de cryptage d'un caractre pour que le programme suivant puisse : dcaler chaque lettre de Tab de 5, ainsi un a sera remplac par un f, un b par un g, etc. On ne cryptera que les lettres majuscules et minuscules sans toucher ni la ponctuation ni la mise en page. On supposera que les codes des lettres se suivent de a z et de A Z.
void main() { char *p, Tab[80]; printf("\n Une phrase ...: "); gets(Tab); p=Tab; while(*p) Crypt(p++); printf("\nResultat :"); printf(Tab); }

Exemple : Les sanglots longs des violons de l'automne Deviendra : Qjx xfslqtyx qtslx ijx antqtsx ij q'fzytrsj ...

6.6. Complter le programme suivant qui saisit 10 entiers et les range partir de l'adresse adr_deb. Rechercher le maximum, l'afficher ainsi que son adresse.
#define imax 10 void main() { int *adr_deb, *adr_max, max; adr_deb=(int*)malloc(imax *sizeof(in));

. .
printf("Le maximum:%d, Son adresse:%p\n",max, adr_max);

.
}

Mohammed BENJELLOUN

Introduction au Langage de Programmation C

Vous aimerez peut-être aussi