Du fait de la conversion d'un identificateur de type tableau en l'adresse du premier élément, lorsqu'un tableau est passé en paramètre effectif, c'est cette adresse qui est passée en paramètre. Le paramètre formel correspondant devra donc être déclaré comme étant de type pointeur.
Voyons sur un exemple.
Soit à écrire une procédure imp_tab
qui est chargée
d'imprimer un tableau d'entiers qui lui est passé en paramètre.
On peut procéder de la manière suivante :
void imp_tab(int *t, int nb_elem) /* définition de imp_tab */ { int i; for (i = 0; i < nb_elem; i++) printf("%d ",*(t + i)); }Cependant, cette méthode a un gros inconvénient. En effet, lorsqu'on lit l'en-tête de cette procédure, c'est à dire la ligne :
void imp_tab(int *t, int nb_elem)il n'est pas possible de savoir si le programmeur a voulu passer en paramètre un pointeur vers un int (c'est à dire un pointeur vers un seul int), ou au contraire si il a voulu passer un tableau, c'est à dire un pointeur vers une zone de n int. De façon à ce que le programmeur puisse exprimer cette différence dans l'en-tête de la procédure, le langage C admet que l'on puisse déclarer un paramètre formel de la manière suivante :
void proc(int t[]) { ... /* corps de la procédure proc */ }car le langage assure que lorsqu'un paramètre formel de procédure ou de fonction est déclaré comme étant de type tableau de X, il est considéré comme étant de type pointeur vers X.
Si d'autre part, on se souvient que la notation *(t + i) est
équivalente à la
notation t[i], la définition de imp_tab
peut s'écrire :
void imp_tab(int t[], int nb_elem) /* définition de imp_tab */ { int i; for (i = 0; i < nb_elem; i++) printf("%d ",t[i]); }Cette façon d'exprimer les choses est beaucoup plus claire, et sera donc préférée. L'appel se fera de la manière suivante :
#define NB_ELEM 10 int tab[NB_ELEM]; int main() { imp_tab(tab,NB_ELEM); }
#define NB_ELEM 10 void imp_tab(int t[NB_ELEM]) { ... }