3. Tableaux
Les tableaux en langage C ressemblent à ce que vous avez appris en Java. Mais vous devez être attentifs aux nombreuses différences qui risquent de vous poser problèmes.
En C, la taille des tableaux est fixée à la compilation. C'est le résultat d'une expression entière constante qui ne peut en aucun cas être modifiée en cours d'exécution. Nous verrons plus tard qu'il existe une autre forme de tableau, dynamique, qui permet de gérer la taille de la table en cours d'exécution de l'application.
Comme il a été écrit dans l'introduction, le langage C ne réalise que très peu de contrôle, notamment en ce qui concerne la gestion des tableaux. Ni à la compilation, ni durant l'exécution, il n'y a vérification que l'indice numéro de l'élement dans le tableau reste dans les limites de l'index ensemble des indices possibles (de 0 à taille-1). Il n'y aura notamment pas d'avertissement si vous utilisez un indice négatif, ni si vous dépassez la limite de la table.
Définition d'un tableau
Pour définir un tableau dans un programme C vous devez spécifier le type des éléments, le nom du tableau et sa taille. Notez que l'index d'un tableau commence toujours à la valeur 0.
Une seule syntaxe est reconnue :
int table[4]; // définition d'une table de 4 int d'indices compris entre 0 et 3double monTableau[N*M]; // valable si M et N sont connus à la compilation
Notez que la dimension d’un tableau ne peut être qu’une constante ou une expression constante (cf. flag vla du compilateur cc), telles que:
#define N 50 // définition d'une constante N...int t[N];float h[2*N-1];
Remarquez qu’une constante symbolique, définie à l’aide du mot-clé const, ne constitue pas une expression constante. Elle ne convient donc pas pour définir la taille d'un tableau.
Une table peut être initialisée lors de sa définition. Les valeurs doivent alors être spécifiées entre accolades, comme dans l'exemple :
int table[4] = {1, 123, -15, 8};
Dans ce cas, il faut rester attentif au fait que la taille de la table doit être suffisante pour éviter une erreur de compilation. Par contre, si la taille est supérieure au nombre de valeurs d'initialisation, les derniers éléments sont initialisés à la valeur 0. Par exemple : dans la définition suivante,
int table[4] = {1, 3};
les 2 derniers éléments (aux indices 2 et 3) de la table sont automatiquement initialisés à 0.
Autre possibilité, utiliser une taille implicite pour la table, valant le nombre d'éléments donnés en initialisation, comme dans l'exemple suivant :
int table[] = {1, 5, -67};
La table aura dès lors une dimension de 3.
Utilisation
L'accès à un élément d'un tableau se fait en spécifiant le nom de la table et la valeur de l'indice noté entre les caractères '[' et ']'.
table[2]++; // post incrémentation du 3ème élément du tableau
Le langage C n'a pas prévu de conserver la taille d'un tableau dans une structure particulière. Cette spécificité du langage a comme conséquences:
-
Qu'il est impossible d'obtenir la taille sans programmer explicitement sa gestion ;
-
Que le compilateur n'offre aucun contrôle quant aux valeurs utilisées comme indice, que cette valeur soit négative ou supérieure à la taille de la table. Il est dès lors très facile de désigner, et donc de modifier, un emplacement situé avant ou après le tableau ! Un tel dépassement de capacité peut constituer une grande faille de sécurité. A vous, donc, de vérifier que les indices des tableaux ne dépassent pas les limites de leur domaine de validité.
Puisque l'index commence toujours à 0, les valeurs possibles pour un indice sont comprises entre 0 et la taille -1.
Tableaux multidimensionnels
Un tableau à 2 dimensions est considéré en C comme un tableau de tableaux ce qui implique que les indices doivent s'indiquer chacun entre crochets '[' et ']'. L'instruction
int matrice[4][3];
est la définition d'un tableau de 4 sous-tableaux (4 lignes), chacun contenant 3 int (3 colonnes). En mémoire, ces 12 éléments sont stockés consécutivement.
L'initialisation d'un tableau multidimensionnel se fait en initialisant chaque sous-tableau. Les sous-tableaux non explicitement initialisés le sont à 0.
int matrice[3][5] = {{1, 3, 5}, {2, 4}};
L'accès à un des éléments de cette matrice se réalise en indiquant les 2 indices, comme dans l'exemple suivant qui initialise le dernier élément de la table déclarée précédemment à 5 :
matrice[2][4] = 5;
Une erreur fréquente est l'utilisation d'une notation semblable à celle employée en mathématique, en séparant les indices par une virgule. Cette écriture
matrice[2, 1]; // équivaut à matrice[1]
est acceptée par le compilateur mais a toutefois une signification différente de ce que vous avez appris en mathématique. Cette notation est en fait équivalente à matrice[1], qui référence la seconde ligne du tableau. En effet, en C, l’opérateur virgule signifie que les expressions qui l'entourent sont évaluées séquentiellement de gauche à droite, donc « 2,1 » vaut 1. (Nous verrons dans le chapitre suivant que matrice[1] correspond à un pointeur vers un int.)