Previous Next Up Index Contents

9.3.1. Adressage des composantes d'un tableau


Comme nous l'avons déjà constaté au chapitre 7, le nom d'un tableau représente l'adresse de son premier élément. En d'autre termes:

&tableau[0] et tableau

sont une seule et même adresse.

En simplifiant, nous pouvons retenir que le nom d'un tableau est un pointeur constant sur le premier élément du tableau.

Exemple

En déclarant un tableau A de type int et un pointeur P sur int,

   int A[10];
   int *P;
l'instruction:

P = A; est équivalente à P = &A[0];

Si P pointe sur une composante quelconque d'un tableau, alors P+1 pointe sur la composante suivante. Plus généralement,


P+i

pointe sur la i-ième composante derrière P et


P-i
pointe sur la i-ième composante devant P.

Ainsi, après l'instruction,

   P = A;

le pointeur P pointe sur A[0], et

*(P+1)

désigne le contenu de A[1]
*(P+2)
désigne le contenu de A[2]
...
...
*(P+i)
désigne le contenu de A[i]

Remarque

Au premier coup d'oeil, il est bien surprenant que P+i n'adresse pas le i-ième octet derrière P, mais la i-ième composante derrière P ...

Remarque avancée

Ceci s'explique par la stratégie de programmation 'défensive' des créateurs du langage C:

Si on travaille avec des pointeurs, les erreurs les plus perfides sont causées par des pointeurs malplacés et des adresses mal calculées. En C, le compilateur peut calculer automatiquement l'adresse de l'élément P+i en ajoutant à P la grandeur d'une composante multipliée par i. Ceci est possible, parce que:

- chaque pointeur est limité à un seul type de données, et

- le compilateur connaît le nombre d'octets des différents types.

Exemple

Soit A un tableau contenant des éléments du type float et P un pointeur sur float:

   float A[20], X;
   float *P;
Après les instructions,
   P = A;
   X = *(P+9);
X contient la valeur du 10-ième élément de A, (c.-à-d. celle de A[9]). Une donnée du type float ayant besoin de 4 octets, le compilateur obtient l'adresse P+9 en ajoutant 9 * 4 = 36 octets à l'adresse dans P.

Rassemblons les constatations ci dessus :

Comme A représente l'adresse de A[0],

*(A+1)

désigne le contenu de A[1]


*(A+2)
désigne le contenu de A[2]


...



*(A+i)
désigne le contenu de A[i]

Attention !

Il existe toujours une différence essentielle entre un pointeur et le nom d'un tableau:

Attention!

- Un pointeur est une variable,
donc des opérations comme P = A ou P++ sont permises.

- Le nom d'un tableau est une constante,
donc des opérations comme A = P ou A++ sont impossibles.

Remarque avancée

Ceci nous permet de jeter un petit coup d'oeil derrière les rideaux:

Lors de la première phase de la compilation, toutes les expressions de la forme A[i] sont traduites en *(A+i). En multipliant l'indice i par la grandeur d'une composante, on obtient un indice en octets:

<indice en octets> = <indice élément> * <grandeur élément>

Cet indice est ajouté à l'adresse du premier élément du tableau pour obtenir l'adresse de la composante i du tableau. Pour le calcul d'une adresse donnée par une adresse plus un indice en octets, on utilise un mode d'adressage spécial connu sous le nom 'adressage indexé':

<adresse indexée> = <adresse> + <indice en octets>

Presque tous les processeurs disposent de plusieurs registres spéciaux (registres index) à l'aide desquels on peut effectuer l'adressage indexé de façon très efficace.

Résumons Soit un tableau A d'un type quelconque et i un indice pour les composantes de A, alors


A

désigne l'adresse de
A[0]

A+i
désigne l'adresse de
A[i]

*(A+i)
désigne le contenu de
A[i]

Si P = A, alors

P

pointe sur l'élément
A[0]

P+i
pointe sur l'élément
A[i]

*(P+i)
désigne le contenu de
A[i]

Formalisme tableau et formalisme pointeur

A l'aide de ce bagage, il nous est facile de 'traduire' un programme écrit à l'aide du 'formalisme tableau' dans un programme employant le 'formalisme pointeur'.

Exemple

Les deux programmes suivants copient les éléments positifs d'un tableau T dans un deuxième tableau POS.

Formalisme tableau

main()
{
 int T[10] = {-3, 4, 0, -7, 3, 8, 0, -1, 4, -9};
 int POS[10];
 int I,J;  /* indices courants dans T et POS */
 for (J=0,I=0 ; I<10 ; I++)
     if (T[I]>0) 
        {
         POS[J] = T[I];
         J++;
        }
 return 0;
}

Nous pouvons remplacer systématiquement la notation tableau[I] par *(tableau + I), ce qui conduit à ce programme:

Formalisme pointeur

main()
{
 int T[10] = {-3, 4, 0, -7, 3, 8, 0, -1, 4, -9};
 int POS[10];
 int I,J;  /* indices courants dans T et POS */
 for (J=0,I=0 ; I<10 ; I++)
     if (*(T+I)>0) 
        {
         *(POS+J) = *(T+I);
         J++;
        }
 return 0;
}

Sources d'erreurs

Un bon nombre d'erreurs lors de l'utilisation de C provient de la confusion entre soit contenu et adresse, soit pointeur et variable. Revoyons donc les trois types de déclarations que nous connaissons jusqu'ici et résumons les possibilités d'accès aux données qui se présentent.

Les variables et leur utilisation int A;
déclare une variable simple du type int


A

désigne le contenu de A

&A
désigne l'adresse de A

int B[];
déclare un tableau d'éléments du type int


B

désigne l'adresse de la première composante de B.


(Cette adresse est toujours constante)

B[i]
désigne le contenu de la composante i du tableau

&B[i]
désigne l'adresse de la composante i du tableau

en utilisant le formalisme pointeur:

B+i

désigne l'adresse de la composante i du tableau

*(B+i)
désigne le contenu de la composante i du tableau

int *P;
déclare un pointeur sur des éléments du type int.

P peut pointer

sur des variables simples du type int ou


sur les composantes d'un tableau du type int.




P
désigne l'adresse contenue dans P


(Cette adresse est variable)

*P
désigne le contenu de l'adresse dans P

Si P pointe dans un tableau, alors

P

désigne l'adresse de la première composante

P+i
désigne l'adresse de la i-ième composante derrière P

*(P+i)
désigne le contenu de la i-ième composante derrière P


Exercice 9.2

Ecrire un programme qui lit deux tableaux A et B et leurs dimensions N et M au clavier et qui ajoute les éléments de B à la fin de A. Utiliser le formalisme pointeur à chaque fois que cela est possible.


Previous Next Up Index Contents

Feedback - Copyright © 1993,1996,1997 F.Faber