Next: Tableau et pointeur, c'est
Up: Relations entre tableaux et
Previous: Exercice
Sous-sections
Tableau de pointeurs
Pour des raisons de gain de place mémoire, on est parfois amené à créer
des tableaux à deux dimensions dont toutes les lignes n'ont pas la même taille.
Ceci peut se réaliser à l'aide d'un tableau de pointeurs vers des tableaux
de tailles différentes, associé à un autre tableau qui donnera la taille
de chaque ligne.
On obtient alors la structure de données suivante :
Si nous supposons que le type des objets terminaux est int,
pour traduire cette structure de données en langage C, les programmeurs
ont l'habitude de << tricher >>, et de ne pas utiliser le type
tableau de pointeurs vers des tableaux de int, considéré comme
étant trop compliqué (un tel type s'écrit : int (*tab[NB_ELEM])[]).
La solution habituellement retenue, consiste à utiliser le type
tableau de pointeurs vers des int, soit int *tab[NB_ELEM].
Voici un exemple d'une telle déclaration avec initialisation statique du
tableau :
#define NB_ELEM 3
int taille[NB_ELEM] = {1, 2, 3};
int ligne1[] = {10};
int ligne2[] = {20,21};
int ligne3[] = {30,31,32};
int *tab[] = {ligne1, ligne2, ligne3};
Pour une référence à l'élément
j de la ligne
i, on n'a que l'embarras du
choix.
Nous donnons ci-après trois méthodes différentes d'imprimer les éléments du
tableau ligne par ligne.
On utilise un pointeur vers un entier que l'on fait progresser d'élément en
élément dans une ligne :
int i, *p;
for (i = 0; i < NB_ELEM; i++)
{
for (p = tab[i]; p < tab[i] + taille[i]; p++)
printf("%d ",*p); /* accès à l'élément courant par *p */
printf("\n");
}
On utilise un pointeur vers le premier élément d'une ligne ; ce pointeur reste
fixe.
int i, j, *p;
for (i = 0; i < NB_ELEM; i++)
{
for (p = tab[i], j = 0; j < taille[i]; j++)
printf("%d ",p[j]); /* accès à l'élément courant par p[j] */
printf("\n");
}
La dernière méthode est surprenante : pour la comprendre, il suffit de
remarquer que la variable
p dans la seconde solution est inutile,
on peut accéder à l'élément courant par la notation
tab[i][j].
int i, j, *p;
for (i = 0; i < NB_ELEM; i++)
{
for (j = 0; j < taille[i]; j++)
printf("%d ", tab[i][j]); /* accès à l'élément courant par tab[i][j] */
printf("\n");
}
On remarquera que c'est la même notation que celle qui est utilisée quand on
a un vrai tableau à deux dimensions, c'est à dire une structure de données
physiquement complètement différente.
Que l'accès à deux structures de données différentes puissent se réaliser de
la même manière, doit sans doute être considéré comme une faiblesse du langage.
C'est pour les tableaux de caractères à deux dimensions,
que se manifeste le plus souvent l'intérêt de disposer d'un tableau
de lignes de longueurs différentes : les longueurs des chaînes sont
extrêmement variables.
La aussi, les habitudes sont les mêmes, les programmeurs utilisent le type
tableau de pointeurs vers des char
4.1, comme ceci :
char * t[NB_ELEM];
On peut initialiser un tableau de ce type avec des chaînes littérales :
char * mois[] = {"janvier", "février", "mars", "avril", "mai", "juin",
"juillet", "août", "septembre", "octobre", "novembre", "décembre"};
On remarquera que ceci est impossible avec tout autre type que les
char :
il est impossible d'écrire :
int * tab[] = {{1}, {2,3}, {4,5,6}};
Une boucle d'impression des valeurs du tableau
mois pourra être :
#define NBMOIS 12
int i;
for (i = 0; i < NBMOIS ; i++)
printf("%s\n",mois[i]);
Les tableaux de pointeurs vers des chaînes de caractères sont une structure
de données importante, car c'est sur celle-ci que s'appuie la transmission
de paramètres lors de l'exécution d'un programme.
Lorsqu'un utilisateur lance l'exécution du programme
prog avec les
paramètres
param1,
param2, ...
paramn, l'interpréteur de
commandes collecte tous ces mots sous forme de chaînes de caractères,
crée un tableau de pointeurs vers ces chaînes, et lance la procédure
main
en lui passant deux paramètres :
- -
- un entier contenant la taille du tableau ;
- -
- le tableau de pointeurs vers les chaînes.
Pour que le programme puisse exploiter les paramètres passés par l'utilisateur,
la fonction main doit être déclarée de la manière suivante :
int main(int argc, char *argv[])
{
...
}
Les noms
argc (pour
argument count),
ainsi que
argv (pour
argument values), sont des noms
traditionnels, mais peuvent être remplacés par n'importe quels autres noms ;
seuls les types doivent être respectés.
Comme exemple d'utilisation des paramètres, nous donnons le source d'un
programme qui imprime son nom et ses paramètres :
int main(int argc, char *argv[])
{
int i;
printf("Nom du programme : %s\n", argv[0]);
for (i = 1; i < argc; i++)
printf("Paramètre %d : %s\n",i,argv[i]);
}
Next: Tableau et pointeur, c'est
Up: Relations entre tableaux et
Previous: Exercice
Bernard Cassagne
1998-12-09