Afin de montrer l'intérêt des tableaux, prenons un exemple dans lequel on doit calculer la moyenne de 4 notes saisies par l'utilisateurs. Pour cela 2 solutions :
L'utilisation de 4 variables et le calcul de la moyenne utilisant ces 4 variables
l'utilisation d'un tableau de 4 cases et le calcul de la moyenne utilisant les 4 cases de ce tableau.
Calcul de la moyenne de 4 notes (sans les tableaux)
Calcul de la moyenne de 4 notes (avec les tableaux)
Les tableaux permettent de définir simultanément plusieurs variables de même type.
La définition suivante permet de créer 4 variables de type double.
double notes[4];
Ces variables sont numérotées de 0 à 3. On dit que notes est un tableau de 4 réels (double). Ce sont les crochets qui permettent de distinguer une simple variable d'un tableau. On accède à chaque élément du tableau par son numéro entre crochets, c'est l'indice de l'élément, de 0 à 3 : notes[0], notes[1], notes[2], notes[3]
Attention : un tableau commence toujours à l’indice 0 !
En plus de permettre de ranger plusieurs variables dans une seule variable tableau, les tableaux ont l'avantage de pouvoir être lue dans une boucle for. On obtient alors un programme plus compact et permettant de traiter autant de notes que l'on veut (il suffit de remplacer 4 par 24 et nous aurons la saisie de 24 notes et le calcul de la somme de ces 24 notes).
😀Calcul de la moyenne de 4 notes (avec les tableaux et la boucle for)😀
double notes[4], moyenne = 0;
for (int i = 0; i < 4; i++) {
printf("Note numero %d : ", i);
scanf_s("%lf", ¬es[i]);
moyenne += notes[i];
}
printf("moyenne des notes:%.2lf", moyenne / 4.0);
3. Initialiser un tableau
Un tableau peut être initialisé lors de sa définition de la manière suivante :
int premiers[8] = {2, 3, 5, 7, 11, 13, 17, 19};
int zero[8] = {0};
Les 8 éléments du tableau (numérotés de 0 à 7) vaudront les valeurs précisées entre accolades dans l'ordre. Si l'on place une seule valeur dans les accolades, on initialise toutes les cases avec cette valeur.
initialiser un tableau à la déclaration
initialiser un tableau avec des variables aléatoires comprises entre 0 et 19
double notes[TAILLE] = { 12.9,10.5,16,9.5 };
double notes[TAILLE] ;
srand(time(NULL));
for (int i = 0; i < TAILLE; i++)
notes[i] = rand() % 20;
Cette initialisation ne peut être utilisé que lors de la définition du tableau. On ne peut pas utiliser cette syntaxe pour affecter des valeurs à un tableau. En C, quand le tableau a été défini, on est obligé de manipuler les éléments un par un.
Quizz
4. Exemple de programme
En général, lorsqu'on utilise les tableaux on travaille avec une constante TAILLE qui définit la taille du tableau et que l'on retrouve dans toutes les boucles for travaillant sur les tableaux. Ainsi, en modifiant sa valeur dans le #define, on modifie toutes les boucles for.
Programme de test
Résultat
#include<stdio.h>
#defineTAILLE 5
int main(){
int tab[TAILLE] = { 1,2,3,4,5 };
for (int i = 0; i < TAILLE; i++)
tab[i] = tab[i] * 2 + 1;
for (int i = 0; i < TAILLE; i++)
printf("tab[%d]=%d\n", i, tab[i]);
return 0;
}
tab[0]=3
tab[1]=5
tab[2]=7
tab[3]=9
tab[4]=11
Quizz
5. Exemple avec un fichier audio wav
L'utilisation d'un fichier son de type wav (fichier qui n'est pas compressé comme le format mp3) est une bonne illustration de l'utilisation des tableaux. Nous allons utiliser le fichier sinus.wav qui se trouve dans le répertoire ressources du projet son: https://github.com/jlsalvat/wave_bmp_visualStudio/
Le fichier sinus.wav est constitué d'un header de 44 octets permettant de définir les informations associées au fichier (type du fichier, taille du fichier, en mono ou stereo, codage des échantillons sur 8, 16 ou 32 bits, fréquence d'échantillonnage, nombre d'échantillons,...) suivi des données de son. Dans l'exemple proposé le fichier sinus.wav est de type mono, 8KHz, données sur un octet et de durée 3s (1,5s d'une sinusoide de fréquence 250Hz suivi par aucun son). Dans le fichier, afin de pouvoir visualiser le début des données (aprés le header), les 20 premiers échantillons sont à 127 (0x7F), ce qui correspond à aucun son. Puis la sinusoide démarre.
Dans l'exemple ci-dessous, remarquez l'utilisation des fonctions fopen, fseek, fread et fclose qui permettent d'ouvrir un fichier, se déplacer dans le fichier (aprés le header), lire un nombre d'échantillons (et les placer dans un tableau) puis fermer le fichier. Le chemin d'accés au fichier est relatif et donné à partir du chemin du fichier son.c ou se trouve le main et qui se trouve dans le répertoire son. Il faut donc monter d'un cran (..) puis aller dans le répertoire ressources (..\\ressources) ou se trouve le fichier sinus.wav.
Lecture du fichier et affichage des 1024 échantillons de son en hexadecimal
Résultat
// pour pouvoir utiliser fopen
#define_CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main() {
FILE* file;
unsignedchar tab[1024];
// Ouvrir le fichier en mode lecture & modification binaire
file = fopen("..\\ressources\\sinus.wav", "rb+");
if (file == NULL) {
printf("Impossible d'ouvrir le fichier.\n");
return 1;
}
// Aller à la position de début des données audio (44 octets)
fseek(file, 44, SEEK_SET);
// Lire 1024 octets dans le fichier et les placer dans le tableau
fread(tab, 1, 1024, file);
// Afficher les données audio (fichier en mono et sur 8 bits)
for (int i = 0; i < 1024; i++) {
printf("tab[%2d]=%hhX\n", i,tab[i]);
}
// fermeture fichier
fclose(file);
return 0;
}
data[ 0]=7F
data[ 1]=7F
data[ 2]=7F
data[ 3]=7F
data[ 4]=7F
data[ 5]=7F
data[ 6]=7F
data[ 7]=7F
data[ 8]=7F
data[ 9]=7F
data[10]=7F
data[11]=7F
data[12]=7F
data[13]=7F
data[14]=7F
data[15]=7F
data[16]=7F
data[17]=7F
data[18]=7F
data[19]=7F
data[20]=7F
data[21]=97
data[22]=AF
data[23]=C5
data[24]=D8
data[25]=E8
Il est possible aussi avec la fonction fwrite de modifier le fichier aprés avoir modifier les éléments du tableau :
Ecrire un bloc de 1024 octets se trouvant dans le tableau tab (une seule écriture)
Ecrire 1024 octets se trouvant dans le tableau tab (1024 écriture -> plus long)
fwrite(tab, 1, 1024, file);
fwrite(tab, 1024, 1, file);
6. Les matrices
Comme pour les tableaux, les matrices peuvent être définis sans être initialisée. Dans ce cas les cases mémoires sont inconnues.
Il est aussi possible d'initialiser les valeurs de la matrice au moment de sa déclaration.
Initialisation d'un matrice d'entiers de 5x4
Initialisation d'un matrice de double de 2x3
On privilégiera l'utilisation des constantes LIGNE et COLONNE dans la définition de la taille de la matrice.
Initialisation et affichage d'une matrice de 5x4
Résultat
#include<stdio.h>
#defineLIGNE 5
#defineCOLONNE 4
int main(){
intiM[LIGNE][COLONNE] = {
{ 1, 2, 3, 4},
{ 5, 6, 7, 8},
{ 9,10,11,12},
{13,14,15,16},
{17,18,19,20}
};
for (int i = 0; i < LIGNE; i++) {
for (int j = 0; j < COLONNE; j++) {
printf("%3d ", iM[i][j]);
}
printf("\n");
}
return 0;
}
1234
5678
9101112
13141516
17181920
Quizz
7. Exemple avec fichier BMP 24 couleurs
Nous avons vu un fichier son (wav) pour comprendre l'intérêt des tableaux, voyons un exemple de fichier image bmp pour comprendre l'intérêt des matrices. Nous ne nous intéressons pas ici aux fichier png ou jpeg pour les plus connus qui sont des fichiers images compressés mais seulement aux fichiers bmp qui sont des fichiers dans lequel on retrouve chaque pixel (aucune compression de l'image). Il existe principalement 2 types de fichiers BMP :
le fichier bitmap 24 bits intégrant 3 matrices R,G,B correspondant chacune à l'intensité des couleurs Rouge (R), vert (G comme Green) et Bleu (B).
le fichier bitmap 8 bits en niveau de gris (que nous allons voir juste aprés)
Le fichier bitmap 24 bits est constitué d'un header (taille 0x36) permettant de définir le type d'image, sa taille, son codage,... suivi des valeurs en BGR de chaque pixel. Prenons l'exemple d'une image de taille 7x10 pixels noté Shape_24.bmp (dossier ressources). Cette image peut être visualisé avec paint par exemple, mais aussi avec Visual Studio. On pourra aller chercher le projet image_24bits dans https://github.com/jlsalvat/wave_bmp_visualStudio
Ouverture du fichier avec paint
ouverture du fichier dans le projet image_24bits sous Visual Studio
Si l'on analyse le fichier bmp, on retrouve aprés le header les valeurs BGR de chaque pixel. Attention le premier pixel qui correspond à la ligne 0 et colonne 0 est situé en bas à gauche de l'image, puis est suivi du pixel suivant (ligne 0 , colonne 1) et ainsi de suite.
Petite subtilité des fichiers bitmaps : une ligne est forcément constituée d'un multiple de 4. Dans notre cas, une ligne est constitué de 10 pixels chacun codé sur 3 octets (B,G,R), il faudra donc ajouter 2 octets de bourrage pour obtenir une ligne de 32 octets = 3x10 +2 (32%4=0) puisque 32 est un multiple de 4. C'est pour cette raison que l'on trouve à la fin de chaque ligne 2 octets à 00 (dit de bourrage).
Pour terminer, les valeurs des pixels sont codées à l'envers (bizarre mais c'est comme ça) : la valeur 0x00 correspond à l'intensité maximale et la valeur 0xFF à l'intensité minimale. Ce qui veut dire que les cases en blanc sont codées B=G=R=0xFF, que les cases en noir sont codées B=G=R=0 et que les cases en vert clairs sont codées : R=0,G=255 et B=128.
8. Exemple de fichier bmp en niveau de gris
Une image en niveau de gris est plus simple à analyser puisque chaque pixel est codé sur un octet (et non sur 3 octets). l'image peut donc être lue dans une seule matrice. Ca c'est pour le bon coté. Le mauvais coté c'est qu'un fichier bmp en niveau de gris est en fait un fichier bmp couleur codé sur 8 bits avec le codage des couleurs (palette de couleur) intégré dans le fichier. Ce qui veut dire que pour un fichier bmp en niveau de gris 20x15 n'aura pas une taille en octet de 0x36 (taille du header) + 20x15 c'est à dire 54+300=354 octets mais une taille bien plus grand intégrant le header (54 octets), la palette de couleurs (256x4 octets puisque chaque couleur est codée sur 4 octets) et l'image en niveau de gris (20x15 octets), soit une taille de fichier de 1378 octets (dans ce fichier il n'y a pas d'octets de bourrage puisque une ligne est constitué de 20 octets qui est divisible par 4).
Pour lire un fichier bmp en niveau de gris, il faudra donc lire l'offset de l'image qui se trouve au dixième octet du header puis se déplacer dans le fichier au début de l'image et placer les pixels dans la matrice.
Dans le programme qui se trouve image_8bits qui se trouve dans https://github.com/jlsalvat/wave_bmp_visualStudio on pourra lancer le programme d'affichage des valeurs du fichier. On rappelle que la première ligne affichée constituée de 0 correspond à la ligne noire en bas de l'image (on commence en bas et on remonte) et que la quatrième ligne à partir du bas se trouve la ligne blanche (valeur 255).
Lecture du fichier grayscale_shapes.bmp de taille 20x15
résultat
#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
//on suppose qu'on connait la taille de l'image...