Aller au contenu principal

Tableaux

1. Pourquoi utiliser un tableau ?​

Supposons que l'on souhaite mémoriser les températures mesurées pendant 10 heures.

Sans tableau, il faudrait déclarer 10 variables :

float t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;

C'est rapidement difficile à manipuler.

Un tableau permet de regrouper plusieurs valeurs de même type sous un même nom :

float temperatures[10];

On dispose alors de 10 cases :

indice
↓
temperatures[0] températures[1] ... températures[9]
│ │ │
▼ ▼ ▼
18.5 19.2 21.7

Un tableau possède donc :

  • un nom ;
  • un type ;
  • un nombre d'éléments ;
  • un indice permettant d'accéder à chaque élément.

2. Déclarer un tableau

La syntaxe est :

type nom[nombre_elements];

Exemples :

int valeurs[10];
float mesures[100];
double tensions[50];
char texte[20];

Le tableau :

float mesures[100];

contient exactement 100 valeurs de type float.

Attention : les indices commencent à 0​

Pour un tableau de 10 éléments :

float mesures[10];

les indices vont de :

0 1 2 3 4 5 6 7 8 9

et non de 1 à 10.

Le dernier élément est donc :

mesures[9]

3. Accéder à un élément

On utilise l'opérateur [].

float temperatures[5];

temperatures[0] = 18.5;
temperatures[1] = 19.2;
temperatures[2] = 20.1;

On peut ensuite lire les valeurs :

printf("%.1f\n", temperatures[0]);
printf("%.1f\n", temperatures[1]);

Un élément d'un tableau se comporte comme une variable ordinaire.

Par exemple :

temperatures[2] = temperatures[0] + 1.5;

4. Initialiser un tableau

On peut initialiser un tableau lors de sa déclaration :

int valeurs[5] = {10, 20, 30, 40, 50};

On obtient :

indice 0 1 2 3 4
↓ ↓ ↓ ↓ ↓
valeur 10 20 30 40 50

Il est également possible de laisser C déterminer le nombre d'éléments :

int valeurs[] = {10, 20, 30, 40, 50};

Le compilateur déduit ici que le tableau contient 5 éléments.

Initialisation partielle​

int valeurs[5] = {10, 20};

Les éléments non explicitement initialisés valent zéro :

10 20 0 0 0

5. Parcourir un tableau

On utilise généralement une boucle for :

int valeurs[5] = {10, 20, 30, 40, 50};

for (int i = 0; i < 5; i++) {
printf("%d\n", valeurs[i]);
}

La variable i joue le rôle d'indice.

On peut visualiser l'exécution :

i = 0 → valeurs[0]
i = 1 → valeurs[1]
i = 2 → valeurs[2]
i = 3 → valeurs[3]
i = 4 → valeurs[4]

La condition :

i < 5

est particulièrement importante.

Il ne faut jamais faire :

i <= 5

car valeurs[5] n'existe pas.


6. Exemple : calculer la somme

Les tableaux deviennent particulièrement intéressants lorsqu'on les combine avec des algorithmes.

float mesures[5] = {12.5, 13.2, 11.8, 14.1, 12.9};

float somme = 0;

for (int i = 0; i < 5; i++) {
somme += mesures[i];
}

printf("Somme = %.2f\n", somme);

On peut ensuite calculer la moyenne :

float moyenne = somme / 5;

printf("Moyenne = %.2f\n", moyenne);

7. Mesures d'un capteur

Supposons qu'un convertisseur analogique-numérique fournisse 8 mesures.

int mesures[8] = {
1023, 1018, 1025, 1021,
1019, 1024, 1022, 1020
};

Calculons la valeur moyenne :

int somme = 0;

for (int i = 0; i < 8; i++) {
somme += mesures[i];
}

float moyenne = (float)somme / 8;

printf("Moyenne = %.2f\n", moyenne);

Le cast :

(float)somme

permet d'obtenir une division réelle.

C'est un bon exemple pour faire le lien avec les mesures physiques.


8. Trouver le minimum et le maximum

On peut parcourir un tableau pour rechercher une valeur particulière.

float mesures[6] = {
12.4, 15.2, 11.8, 16.3, 14.7, 13.1
};

float minimum = mesures[0];
float maximum = mesures[0];

for (int i = 1; i < 6; i++) {

if (mesures[i] < minimum) {
minimum = mesures[i];
}

if (mesures[i] > maximum) {
maximum = mesures[i];
}
}

printf("Minimum = %.1f\n", minimum);
printf("Maximum = %.1f\n", maximum);

Pourquoi commencer à i = 1 ?​

Parce que nous avons déjà utilisé :

mesures[0]

pour initialiser minimum et maximum.


9. Taille d'un tableau

Une difficulté importante en C est que le tableau ne connaît pas automatiquement son nombre d'éléments dans toutes les situations.

Lorsqu'on est directement dans le même bloc où le tableau est déclaré, on peut utiliser :

sizeof

Exemple :

int valeurs[] = {10, 20, 30, 40, 50};

size_t nombre = sizeof(valeurs) / sizeof(valeurs[0]);

printf("Nombre d'elements : %zu\n", nombre);

Pourquoi ?

sizeof(valeurs)

donne la taille totale du tableau en octets.

Et :

sizeof(valeurs[0])

donne la taille d'un élément.

Donc :

nombre d'éléments =
taille totale / taille d'un élément

C'est une idiome très importante en C :

sizeof(tableau) / sizeof(tableau[0])

10. Attention aux dépassements de tableau

C est particulièrement permissif.

Le compilateur n'empêche généralement pas ceci :

int valeurs[5];

valeurs[10] = 123;

Pourtant valeurs[10] n'existe pas.

Le programme écrit alors potentiellement dans une autre zone de mémoire.

C'est un exemple classique de dépassement de tableau (buffer overflow).

Il faut donc toujours garantir que l'indice respecte :

0 <= indice < nombre_elements

11. Tableaux et constantes

Pour éviter de répéter une taille dans le programme, on peut utiliser une constante :

#define NB_MESURES 10

float mesures[NB_MESURES];

for (int i = 0; i < NB_MESURES; i++) {
mesures[i] = 0;
}

12. Tableaux et fonctions

C'est probablement la notion la plus importante à introduire après le parcours.

On peut vouloir écrire une fonction qui calcule la moyenne :

float moyenne(float mesures[], int nombre)
{
float somme = 0;

for (int i = 0; i < nombre; i++) {
somme += mesures[i];
}

return somme / nombre;
}

Utilisation :

int main(void)
{
float mesures[] = {
12.5, 13.2, 11.8, 14.1, 12.9
};

float m = moyenne(mesures, 5);

printf("Moyenne = %.2f\n", m);
}

On passe donc :

moyenne(mesures, 5);

et non :

moyenne(mesures);

car la fonction doit également connaître le nombre d'éléments.


13. Modifier un tableau dans une fonction

Une fonction peut modifier directement les éléments du tableau.

Par exemple, convertir une série de tensions :

void multiplier(float valeurs[], int nombre, float coefficient)
{
for (int i = 0; i < nombre; i++) {
valeurs[i] *= coefficient;
}
}

Puis :

float tensions[] = {1.2, 2.4, 3.1, 4.7};

multiplier(tensions, 4, 2.0);

Le tableau contient maintenant :

2.4 4.8 6.2 9.4

Le passage d'un tableau à une fonction est différent du passage d'une simple variable.


14. Tableaux de caractères

Un cas particulier très important est le tableau de char.

char nom[20];

Un tableau de caractères peut contenir une chaîne de caractères :

char nom[] = "Dupont";

En mémoire, on trouve :

D u p o n t \0

Le caractère spécial :

'\0'

marque la fin de la chaîne.

On pourra alors utiliser :

printf("%s\n", nom);

15. Tableaux à deux dimensions

Par exemple, une matrice :

float matrice[3][4];

On a :

colonne
0 1 2 3
┌────┬────┬────┬────┐
0 │ │ │ │ │
├────┼────┼────┼────┤
1 │ │ │ │ │
├────┼────┼────┼────┤
2 │ │ │ │ │
└────┴────┴────┴────┘
↑
ligne

On accède à un élément avec :

matrice[ligne][colonne]

Par exemple :

matrice[1][2] = 3.14;

16. Parcourir un tableau à deux dimensions

On utilise deux boucles imbriquées :

int matrice[3][4];

for (int ligne = 0; ligne < 3; ligne++) {

for (int colonne = 0; colonne < 4; colonne++) {

printf("%d ", matrice[ligne][colonne]);
}

printf("\n");
}

On peut naturellement utiliser cela pour représenter :

  • une matrice mathématique ;
  • des coefficients ;
  • des données de capteurs ;
  • une image en niveaux de gris ;
  • un tableau de mesures temps × capteur.

17. Exemple complet : acquisition de mesures

Énoncé :

Un système embarqué acquiert 10 mesures de tension en volts.

Écrire un programme qui :

  1. stocke les mesures dans un tableau ;
  2. affiche toutes les mesures ;
  3. calcule la tension moyenne ;
  4. recherche la tension minimale ;
  5. recherche la tension maximale.

Par exemple :

#include <stdio.h>

#define NB_MESURES 10

int main(void)
{
float tensions[NB_MESURES] = {
4.95, 5.02, 5.01, 4.98, 5.04,
5.00, 4.97, 5.03, 5.01, 4.99
};

float somme = 0;
float minimum = tensions[0];
float maximum = tensions[0];

for (int i = 0; i < NB_MESURES; i++) {

printf("Mesure %d : %.2f V\n", i, tensions[i]);

somme += tensions[i];

if (tensions[i] < minimum) {
minimum = tensions[i];
}

if (tensions[i] > maximum) {
maximum = tensions[i];
}
}

printf("\n");
printf("Moyenne : %.2f V\n", somme / NB_MESURES);
printf("Minimum : %.2f V\n", minimum);
printf("Maximum : %.2f V\n", maximum);

return 0;
}

Les notions à retenir​

NotionExemple
Déclarationfloat mesures[10];
Accèsmesures[3]
Premier élémentmesures[0]
Dernier élémentmesures[9]
Initialisationint t[] = {1, 2, 3};
Parcoursfor (int i = 0; i < 10; i++)
Taille en octetssizeof(mesures)
Nombre d'élémentssizeof(mesures) / sizeof(mesures[0])
Tableau 2Dfloat m[3][4];
Élément d'une matricem[1][2]
Tableau dans une fonctionfloat moyenne(float t[], int n)