next up previous contents index
suivant: Allocation dynamique monter: main précédent: L'opérateur & et le   Table des matières   Index


Pointeurs et tableaux

Ces deux types de données présentent des similarités et des différences importantes. Si l'on définit


  int t[4];
  int *p;

il y a allocation de mémoire, dans le premier cas, pour 4 entiers, et dans le second, pour une adresse. On a vu cependant que la valeur de t était l'adresse du bloc alloué. On peut donc affecter cette adresse à p, ce qui a pour effet que *p et t[0] désigneront le même objet :


  p = t;


\begin{figurette}
% latex2html id marker 4791\begin{center}
\leavevmode
\fb...
...} \caption {Affectation d'un tableau à un pointeur} \end{center} \end{figurette}

L'affectation inverse t = p est illégale car t est une constante, pas une variable. Au niveau des valeurs, pointeurs d'int et tableaux d'int sont de même type. En outre, si t est déclaré comme un tableau d'éléments constants, l'affectation ou l'initialisation p = t ne peut se faire que si le pointeur est aussi un pointeur vers un objet constant (sinon, la constance de l'objet est perdue par affectation) :


  const int t[4];
  const int *p = t;
  int *q = t;                // ERREUR

Ce qui est vrai pour l'affectation et l'initialisation l'est également pour le passage d'argument des fonctions. Une fonction void g(int *p) sur des pointeurs peut être appelée avec un tableau en argument, g(t), puisque ceci correspond à une initialisation de la forme int *p = t;.

Contrairement à ce nous venons d'écrire pour l'affectation t = p;, qui est illégale, il se trouve que dans la situation inverse, une fonction void f(int t[]) sur les tableaux, peut être appelée avec un pointeur en argument, f(p). Ceci provient du fait que ce n'est pas l'objet tableau qui est passé en argument, mais seulement son adresse, et que cette adresse est une valeur de type int*. Les deux déclarations suivantes de fonctions sont donc exactement équivalentes :


void f(int t[]);           // ÉQUIVALENT 
void f(int *t);            // ÉQUIVALENT

Il en est de même des deux définitions suivantes, pour des tableaux bidimensionnels (les paranthèses autour de *t sont obligatoires) :


void g(int t[][3]);        // ÉQUIVALENT 
void g(int (*t)[3]);       // ÉQUIVALENT

L'accès par indexation à un tableau (unidimensionnel) et la déréférenciation sont aussi des opérations équivalentes : si p est un pointeur, *p équivaut à p[0], *(p+1) équivaut à p[1], etc. Inversement si t est un tableau, t équivaut à &t[0], t+1 équivaut à &t[1], etc. Par exemple, les initialisations suivantes du pointeur p sont équivalentes et permettent de désigner le sous-tableau décalé, commençant par le deuxième élément de t :


  double t[4];
  double *p = &t[1];       // ÉQUIVALENT
  double *p = t+1;         // ÉQUIVALENT

Il en résulte des équivalences analogues pour des tableaux pluridimensionnels :


  int t[2][3] = {
    {1, 2, 3},
    {4, 5, 6}
  };
  
  int (*p)[3] = t+1;             // *p désigne la seconde ligne de t

  cout << p[0][2] << endl;       // ÉQUIVALENT
  cout << (*p)[2] << endl;       // ÉQUIVALENT 
  cout << t[1]2[] << endl;       // ÉQUIVALENT


\begin{figurette}
% latex2html id marker 4799\begin{center}
\leavevmode
\fb...
...
} \caption {Pointeur sur un élément d'un tableau} \end{center} \end{figurette}


next up previous contents index
suivant: Allocation dynamique monter: main précédent: L'opérateur & et le   Table des matières   Index
R Lalement