Analyse et programmation 1
Les tableaux
Thèmes abordés
• Les tableaux, pour quoi faire ? L i i
• Les principes
– Déclaration, initialisation.
– Utilisation : lecture, modification.
– Recommandations.
• Les tableaux de taille variable.
• Les tableaux à plusieurs dimensions.
Les tableaux
Pour quoi faire ?
• Exemple : un programme permettant de saisir 10 entiers
#i l d < tdi h>
#include <stdio.h>
#include <stdlib.h>
int main() {
int entier1, entier2, entier3, entier4, entier5, entier6, entier7, entier8, entier9, entier10;
printf("Saisie de l'entier 1:");
scanf("%d", &entier1);
printf("Saisie de l'entier 2:");
Analyse et programmation 1 - Les tableaux 2
scanf("%d", &entier2);
. . .
system("PAUSE");
return 0;
}
• Comment gérer le cas de 1000 entiers ?
Les tableaux
Pour quoi faire ?
• Solution avec une boucle
#i l d tdi h
#include <stdio.h>
#include <stdlib.h>
int main() {
int i;
int entier1, entier2, entier3, entier4, entier5, entier6, entier7, entier8, entier9, entier10;
for (i = 1; i <= 10; i++) {
{
printf("Saisie de l'entier %d:", i);
scanf("%d", &entier i);
}
system("PAUSE");
return 0;
}
• Comment désigner la variable n° i ?
Syntaxe incorrecte !
Déclaration de tableaux
• Définition
– Un tableau est une variableUn tableau est une variable.
– Contenant une collection de valeurs de même type.
– Comme toutes les variables, le tableau a un nom.
– Chaque élément du tableau est désigné par ce nom et par sa position.
• Exemple
int entiers[10];
Analyse et programmation 1 - Les tableaux 4
index 0 1 2 3 4 5 6 7 8 9
valeur 10 45 21 37 98 -5 12 45 -20 37
Principes
Déclaration de tableaux - observations
• Forme générale
type nom[taille];
type nom[taille];
– type: n’importe quel type valide.
– nom : identificateur valide.
– taille: doit être une expression constante (pas une constante)
• La taille d’un tableau est fixée à sa déclaration.
• Taille en mémoire d’un tableau de N éléments de taille T :
N x sizeof(T) – Exemples :
int entiers[10];
double reels[20];
• Les indices d’un tableau de taille n vont de 0 à n-1.
// taille : 10 x 4 = 40 // taille : 20 x 8 = 160
Principes
Initialisation de tableaux
• Initialisation d’un tableau lors de sa déclaration
int entiers[5] = {10 20 30 40 50};
int entiers[5] = {10, 20, 30, 40, 50};
• Initialisation partielle
int entiers[5] = {10, 20};
– Seules les valeurs indiquées seront initialisées.
– Les autres sont (selon l’implémentation)
• Soit initialisées à 0 (Visual C++ 2005).
• Soit non initialisées (contenu imprévisible).
Analyse et programmation 1 - Les tableaux 6
( p )
• Dimensionnement par l’initialisation
int entiers[] = {10, 20, 30, 40, 50};
Utilisation
Accéder aux éléments du tableau
• Lecture d’une valeur du tableau
valeur tableau[index];
valeur = tableau[index];
• Modification d’une valeur du tableau
tableau[index] = valeur;
• Exemples
int entiers[10];
entiers[0] = 10;
entiers[1] = 45;
entiers[2] = entiers[0] + 11;
Accéder aux éléments du tableau - exemple
#include <stdio.h>
#include <stdlib.h>
int main() {
int i;
int entiers[10];
// Saisie des valeurs for (i = 1; i <= 10; i++) {
printf("Saisie de l'entier %d:", i);
scanf("%d", &entiers[i - 1]);
Analyse et programmation 1 - Les tableaux 8
sca ( %d , &e t e s[ ]);
}
// Affichage des valeurs du tableau for (i = 1; i <= 10; i++)
printf("Entier %d: % d\n", i, entiers[i - 1]);
system("PAUSE");
return 0;
}
• Exemple
int entiers[10];
Recommandation
Attention aux limites d’indice
int entiers[10];
• Que se passe t il si on accède à l’élément n° 10, ou 11 ?
• Lecture ou écriture d’une zone mémoire hors du tableau.
index 0 1 2 3 4 5 6 7 8 9 10 11 12 1
valeur 10 45 21 37 98 -5 12 45 -20 37
• Aucun contrôle par le compilateur.
• Conséquences
– Lecture : Valeur inattendue.
– Ecriture : Corruption de la mémoire.
• Qu’affiche ce programme ? int main()
Recommandation
Attention aux limites d’indice – illustration des effets
int main() {
int i;
int entiers[10];
i = 0;
entiers[12] = 12345;
printf("%d\n", i);
system("PAUSE");
Analyse et programmation 1 - Les tableaux 10
system( PAUSE );
return 0;
}
• Testé sous Visual Studio 2005 : – Ce programme affiche 12345
Utilisation
Accéder aux éléments du tableau – exemple modifié
• Recommandation
– Préférer des variables de boucle allant de 0 à n – 1.
. . . int main() {
int i;
int entiers[10];
// Saisie des valeurs for (i = 0; i < 10; i++) {
printf("Saisie de l'entier %d:", i + 1);
scanf("%d" &entiers[i]);
scanf("%d", &entiers[i]);
}
// Affichage des valeurs du tableau for (i = 1; i <= 10; i++)
printf("Entier %d: % d\n", i + 1, entiers[i]);
system("PAUSE");
return 0;
}
Accéder à la taille du tableau
• Problème : répétition de la taille du tableau.
. . . int main() {
int i;
int entiers[10];
// Saisie des valeurs for (i = 0; i < 10; i++) . . .
• Que se passe-t-il si on modifie la taille après coup ? – Nécessité de modifier toutes les boucles du programme.
Analyse et programmation 1 - Les tableaux 12
– Risque d’oubli avec des conséquences fatales.
– Il n’existe pas de fonction en C pour lire la taille d’un tableau.
– Solutions possibles en utilisant l’opérateur sizeof.
Utilisation
Accéder à la taille du tableau
• Solution recommandée : utiliser un #define
#
#include <stdio.h>
#include <stdlib.h>
#define TAILLE_ENTIERS 10
int main() {
{
int i;
int entiers[TAILLE_ENTIERS];
for (i = 0; i < TAILLE_ENTIERS; i++) {
Utilisation
Passage de tableau en paramètre de fonction
• Déclaration
void initialiser tableau(double tableau[10], double valeur);
void initialiser_tableau(double tableau[10], double valeur);
• Particularités
– Il serait peu efficace de passer tous les éléments sur la pile.
– Ce ne sont pas les valeurs du tableau qui sont transmises.
– C’est son adresse.
– Conséquence
• La fonction peut modifier le contenu du tableau passé en paramètre.
Autre forme
Analyse et programmation 1 - Les tableaux 14
• Autre forme
void initialiser_tableau(double tableau[], double valeur);
– La taille n’étant pas contrôlée, il n’est pas nécessaire de l’indiquer dans la déclaration.
– On peut passer en paramètre le nombre d’éléments à utiliser.
Utilisation
Passage de tableau en paramètre de fonction – autres formes
• Sans préciser la taille
void initialiser tableau(double tableau[] double valeur);
void initialiser_tableau(double tableau[], double valeur);
– La taille n’étant pas contrôlée, il n’est pas nécessaire de l’indiquer dans la déclaration.
– On peut passer en paramètre le nombre d’éléments à utiliser.
• En utilisant la syntaxe des pointeurs
void initialiser_tableau(double * tableau, double valeur);
• Particularités du C
– Le nom d’un tableau désigne son adresse.
– Un pointeur peut être indicé comme un tableau !
Passage de tableau en paramètre de fonction – taille variable
• Exemple
void initialiser tableau(double tableau[]
void initialiser_tableau(double tableau[], int nombre_elements, double valeur) {
int i;
for (i = 0; i < nombre_elements; i++) tableau[i] = valeur;
}
Analyse et programmation 1 - Les tableaux 16
Utilisation
Passage de tableau en paramètre de fonction – const
• Un tableau est passé par adresse
Donc la fonction pe t modifier ses éléments – Donc, la fonction peut modifier ses éléments.
– Pour certaines fonctions, le tableau est un paramètre d’entrée :
• La fonction lit seulement les valeurs des éléments.
• On souhaite interdire qu’elle les modifie.
• On souhaite mettre en évidence que c’est un paramètre d’entrée.
• Utilisation du mot réservé const
– Permet de dénoter que les éléments pointés sont en lecture seule.Permet de dénoter que les éléments pointés sont en lecture seule.
double moyenne(const double valeurs[], int nombre);
Utilisation
Quelques opérations avec les tableaux
• Opérateurs
Se ls sont s pportés : l’accès a ec [] la taille a ec si eof – Seuls sont supportés : l’accès avec [], la taille avec sizeof.
– L’affectation = n’est pas supportée sur les tableaux.
• Quelques opérations courantes avec les tableaux :
– Initialiser.
– Saisir les valeurs.
– Afficher les valeurs.
Copier un tableau dans un autre
Analyse et programmation 1 - Les tableaux 18
– Copier un tableau dans un autre.
– Rechercher la position d’une valeur.
– Calculer la valeur minimale ou maximale.
– Trier les valeurs.
Utilisation
Exemple : rechercher la position d’une valeur
int position(int tableau[], int taille, int valeur) {
{
int i;
for (i = 0; i < taille; i++) if (tableau[i] == valeur)
return i;
return -1; // signaler que la valeur n'a pas été trouvée }
Exemple : trier les valeurs d’un tableau (tri à bulle) void trier_tableau(int tableau[], int taille) {
{
int i, j, tmp;
for (i = 0; i < taille - 1; i++) for (j = i + 1; j < taille; j++)
if (tableau[i] > tableau[j]) {
// échanger les valeurs d'indice i et j tmp = tableau[i];
Analyse et programmation 1 - Les tableaux 20
tmp tableau[i];
tableau[i] = tableau[j];
tableau[j] = tmp;
} }
Utilisation
Exemple : trier les valeurs d’un tableau - illustration des permutations
9 3 14 8 1
i = 0
3 9 14 8 1
j = 1 3 9 14 8 1
j = 1
1 9 14 8 3
j = 4
1 9 14 8 3
i = 1 j = 3 j = 4
1 8 14 9 3
1 3 14 9 8
1 3 14 9 8
i = 2 j = 3 j = 4
1 3 9 14 8
1 3 8 14 9
1 3 8 14 9
i = 3
j = 4 1 3 8 9 14
Les tableaux à 2 dimensions
Application : collection de mesures de différents capteurs Mesure
CCapteur de températ
1 2 3 4 5 6 7 8 9 10 11 12 13
1 7.5 12 13.5 15 12 9 7 10 12 12 13.5 14 3
2 12 9 7 10 12 13.5 14 9 16 8.5 9 4 6
3 12 13.5 13.5 14 9 13.5 15 13.5 7 10 5 7 8
4 15 12 9 12 9 7 15 12 9 17 13 12 16
Analyse et programmation 1 - Les tableaux 22
ture 5 9 14 9 13.5 14 9 9 14 12 9 13.5 14 12.5
6 13.5 0 12 9 15 12 13.5 13.5 14 22 11 14 11
7 12 12 13.5 14 17 15 12 9 12 9 7 10 9
8 14 13 12 9 7 10 14 8 11 13 14 8 9
Les tableaux à 2 dimensions
Application : algèbre linéaire – calcul matriciel
• Matrice
Nombres organisés en lignes et en colonnes – Nombres organisés en lignes et en colonnes
– Applications :
• traitement d’image, infographie, robotique, filtrage, etc…traitement d image, infographie, robotique, filtrage, etc…
Utilisation
• Déclaration
#define NOMBRE CAPTEURS 8
#define NOMBRE_CAPTEURS 8
#define NOMBRE_MESURES 13
double temperature[NOMBRE_CAPTEURS][NOMBRE_MESURES];
• Initialisation
double matrice[3][4] = { { 1.4, 2.3, 3.3, 5.4 },
{ 3.4, 1.2, 8.6, 5.7 }, { 7.2, 8.1, 4.3, 3.9 } };
Analyse et programmation 1 - Les tableaux 24
{ . , . , . , . } };
Absolument équivalent à : double matrice[3][4] =
{ 1.4, 2.3, 3.3, 5.4, 3.4, 1.2, 8.6, 5.7, 7.2, 8.1, 4.3, 3.9 };
Les tableaux à 2 dimensions
Utilisation int i, j;
double matrice[3][4] = [ ][ ] { { 1.4, 2.3, 3.3, 5.4 },
{ 3.4, 1.2, 8.6, 5.7 }, { 7.2, 8.1, 4.3, 3.9 } };
for (i = 0; i < 3; i++) for (j = 0; j < 4; j++)
printf("M[%d, %d]=%lf\n", i, j ,matrice[i][j]);
printf( M[%d, %d] %lf\n , i, j ,matrice[i][j]);
Les tableaux à 2 dimensions
Représentation en mémoire
• Les éléments sont disposés consécutivement.
consécutivement.
• Exemple
int matrice_entiers[3][4] = { { 0, 1, 2, 3 },
{ 10, 11, 12, 13 }, { 20, 21, 22, 23 } };
• Contenu de la mémoire
Analyse et programmation 1 - Les tableaux 26
• Le compilateur calcule la position d’un élément
– M[1][3] -> élément n° 1 x 4 + 3
Les tableaux à 2 dimensions
Passage en paramètre à une fonction
• Préciser les dimensions nécessaires au calcul d’indice
Po r calc ler l’indice d’ n élément le compilate r a besoin de – Pour calculer l’indice d’un élément, le compilateur a besoin de
connaître la taille des sous indices du tableau.
– Correct :
void initialiser_matrice(double matrice[3][4]);
void initialiser_matrice(double matrice[][4]);
– Refusé par le compilateur:
void initialiser_matrice(double matrice[][]);
Généralisation
• Il est possible de créer des tableaux de N dimensions.
D i t diffi il à d
• Devient difficile à comprendre.
• Exemple : tableau de 10 matrices 3 x 4 :
double matrices[10][3][4];
– Quel est la taille de l’espace mémoire occupé ?
Analyse et programmation 1 - Les tableaux 28
4 x 3 x 10 x sizeof(double) = 4 x 3 x 10 x 8 = 960 octets
Qu’avons-nous appris ?
• Déclaration et utilisation de tableaux simples.
P blè lié déb d t d’i di
• Problèmes liés au débordement d’indice.
• Passage de tableau en paramètres.
• Algorithmes habituels avec les tableaux
– En particulier le tri
• Les tableaux à plusieurs dimensions.
Vos questions
Analyse et programmation 1 - Les tableaux 30