• Aucun résultat trouvé

Pointeurs, tableaux et chaines de caract`eres

– Un seul pointeur par zone m´emoire : En r`egle g´en´erale, il faut ´eviter (autant que faire se peut...) que plusieurs variables pointent la mˆeme zone m´emoire allou´ee.

– Eviter les fuites de m´emoire : La perte du pointeur associ´e `a un secteur m´emoire rend impossible la lib´eration du secteur `a l’aide de free. On qualifie cette situation de fuite m´emoire, car des secteurs demeurent r´eserv´es sans avoir ´et´e d´esallou´es. Cette situation perdure jusqu’`a la fin du programme principal.

5.3

Pointeurs, tableaux et chaines de caract`eres

L’usage des pointeurs en C est essentiellement tourn´e vers la manipulation des tableaux et des chaines de caract`eres.

5.3.1 Tableaux unidimensionnels

Un tableau en C est un pointeur constant (c’est-`a-dire non modifiable). Dans la d´eclaration :

int Tab[10];

Tabest un pointeur constant vers une plage-m´emoire de taille 10*sizeof(int), dont la valeur est l’adresse du premier ´el´ement du tableau : Tab a pour valeur &Tab[0]. On peut donc se servir d’un pointeur pour parcourir le tableau comme dans le code suivant :

int Tab[5]={1,2,3,6,4}; int *p;

p=Tab;

for (int i = 0; i<N;i++) { printf("%d \n",*p); p++;

}

qui est ´equivalent `a :

int Tab[5]={1,2,3,6,4}; for (int i = 0; i<N;i++) {

printf("%d \n",Tab[i]); }

qui est encore ´equivalent `a :

int Tab[5]={1,2,3,6,4}; int *p;

p=Tab;

for (int i = 0; i<N;i++) { printf("%d \n",p[i]); }

Les deux diff´erences principales entre tableaux est pointeurs sont les suivantes :

– un pointeur doit toujours ˆetre initialis´e, soit par un appel aux fonctions malloc— ou calloc, soit par affectation d’une expression d’adresse (du type p=&i;),

– un tableau ne peut pas ˆetre une Lvalue (ne peut jamais figurer `a gauche d’un op´erateur d’af- fectation). En particulier, il ne supporte pas l’arithm´etique des pointeurs (on ne peut pas ´ecrire Tab++;).

D’autre part, la manipulation de tableaux plutˆot que de pointeurs a deux inconvenients majeurs, du fait qu’ils sont des pointeurs constants :

– On ne peut pas cr´eer des tableaux dont la taille est une variable du programme,

– on ne peut pas cr´eer de tableaux bidimensionnels dont les lignes n’ont pas toutes la mˆeme taille. Ces op´erations deviennent possibles lorsque la m´emoire est allou´ee dynamiquement, avec malloc ou calloc, et donc que l’on a `a faire `a de vrais pointeurs.

Ainsi, pour d´efinir un tableau `a n ´el´ements, o`u n est une variable du programme, on utilise :

int n; int *Tab;

Tab=(int *)malloc(n*sizeof(int));

Le pointeur Tab s’utilisera ensuite comme un tableau de n ´el´ements de type int. En particulier, son ie´el´ement est donn´ee par l’expression Tab[i].

5.3.2 Tableaux et pointeurs multidimensionnels

Un tableau multidimensionnel est un tableau de tableaux. Il s’agit donc d’un pointeur constant qui pointe vers un pointeur constant. Par exemple, dans la d´eclaration de tableau suivante :

int Tab[N][M];

L’´el´ement Tab est un pointeur vers un objet qui est lui-mˆeme de type pointeur sur des entiers. Tab a une valeur constante, ´egale `a l’adresse du premier ´el´ement du tableau : &Tab[0][0]. Les pointeurs Tab[i], pour i variant de 0 `a N-1 sont des pointeurs constants pointant respectivement sur le premier ´el´ement des lignes i : Tab[i] a donc pour valeur &Tab[i][0].

Par exemple, supposons que l’on souhaite repr´esenter `a l’aide d’un tableau la matrice `a coefficients entiers suivante :

 1 2 3 4 5 6



On initialise par exemple le tableau ainsi :

int Tab[2][3]={{1,2,3},{4,5,6}};

La m´emoire sera par exemple organis´ee ainsi :

Objet Valeur Adresse Tab 4687351800 3218448700 Tab[0] 4687351800 3218448704 Tab[1] 4687351812 3218448708 Tab[0][0] 1 4687351800 Tab[0][1] 2 4687351804 Tab[0][2] 3 4687351808 Tab[1][0] 4 4687351812 Tab[1][1] 5 4687351816 Tab[1][2] 6 4687351820

On peut ´egalement d´efinir des tableaux tridimensionnels et mˆeme `a plus de 3 dimensions (en utilisant une d´eclaration du type type tab[N1][N2]...[Nn] ;). Par exemple, si on souhaite d´ecrire la famille de matrices suivante :

5.3. Pointeurs, tableaux et chaines de caract`eres A0 = 1 2 3 4 5 6  , A2 = 3 2 1 6 5 4  , A3= 1 1 1 4 1 1  , A4= 0 0 0 1 0 0  . `

a l’aide d’un tableau multidimensionnel, on peut la d´eclarer ainsi :

int A[4][2][3];

A[0]={{1,2,3},{4,5,6}}; A[1]={{3,2,1},{6,5,4}}; A[2]={{1,1,1},{4,1,1}}; A[3]={{0,0,0},{1,0,0}};

Les tableaux multidimensionnels sont cependant contraignants : tous les sous-tableaux doivent avoir la mˆeme taille. On ne pourrait par exemple pas utiliser un tableau pour stocker proprement la famille de matrices suivante :

A0 =  1 2 3 4 5 6  , A2 =  2 1 5 4  , A3 =  1 1 1 , A4 =   0 0 0 1 0 0 1 0 0  .

Pour stocker ce type de donn´ees, on peut en revanche utiliser des pointeurs multidimensionnels. Ces pointeurs poss`edent plusieurs avantages par rapport aux taleau multidimensionnels. Outre le fait que l’on puisse stocker des ´el´ements de taille diff´erentes, on peut ´egalement allouer dynamiquement la m´emoire d´edi´ee `a chaque “sous-pointeur”.

Pour d´eclarer un pointeur multidimensionnel, on proc`ede comme pour les tableaux. D´efinir un pointeur bidimensionnel Nom pointeur sur des objets de type type , c’est d´efinir un pointeur sur des objets de type type * . On d´eclarera donc un pointeur didimensionnel via l’instruction :

type ** Nom pointeur;

De mˆeme, on d´eclarera un pointeur tridimensionnel ainsi : type *** Nom pointeur ;

Par exemple, si on souhaite stocker et initialiser, `a l’aide d’un pointeur de pointeurs, les premi`eres lignes triangle de Pascal, qui contient les coefficiants binomiaux :

1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 . . .

o`u chaque coefficient est obtenu en faisant la somme des deux qui sont au dessus de lui. Pour d´eclarer et initialiser les 10 premi`eres lignes du triangle, on proc`ede comme suit :

int i,j; int n=10; int ** Pascal;

/*Allocation de la m´emoire*/

Pascal =(int **)malloc(n*sizeof(int *)); for (i=0;i<n;i++){

Pascal[i]=(int *) malloc((i+1)*sizeof(int)); }

/*Initialisation des valeurs*/ Pascal[0][0]=1; for (i=1;i<n;i++){ Pascal[i][0]=1; for(j=1;j< i;j++){ Pascal[i][j]=Pascal[i-1][j-1]+Pascal[i-1][j]; } Pascal[i][i]=1; }

5.3.3 Pointeurs et chaines de caract`eres

Les chaines de caract`eres sont des tableaux `a une dimension d’objets de type char qui se terminent par le caract`ere nul (’\0’). On peut manipuler toute chaine de caract`ere `a l’aide d’un pointeur vers des objets de type char. A une chaine d´efinie par :

char * s;

on pourra par exemple affecter la valeur suivante :

s="Bonjour";

et on pourra faire subir `a s toute op´eration valide sur les pointeurs, comme par exemple s++. La quantit´e s+3 d´esignera la chaine de caract`eres jour et s+7 la chaine de caract`eres vide.

B o n j o u r ’\0’

s s+3 s+7