Aller au menu - Aller au contenu

Icône Les tableaux

Mise à jour : 22/01/2012
Difficulté : Intermédiaire Intermédiaire Creative Commons BY-NC-SA
172 420 visites depuis 7 jours , dont 4 129 sur ce chapitre , classé 2/777
Ce chapitre est vraiment la suite directe des pointeurs, et c'est un autre exemple de l'utilité des pointeurs. Vous comptiez y échapper ? C'est raté :D
Les pointeurs sont partout, je vous avais prévenus ;)

Dans ce chapitre, nous apprendrons à créer des variables de type "tableaux". Les tableaux sont très utilisés en C car ils sont vraiment pratiques :)

Nous commencerons dans un premier temps par quelques explications sur le fonctionnement des tableaux en mémoire (schémas à l'appui). Croyez-moi, ces petites introductions sur la mémoire sont extrêmement importantes : elles vous permettent de comprendre comment cela fonctionne. Un programmeur qui comprend ce qu'il fait, c'est quand même un peu plus rassurant pour la stabilité des programmes non ? :D
Sommaire du chapitre :
Icône du chapitre
Chapitre précédent Sommaire Chapitre suivant

Les tableaux dans la mémoire

"Les tableaux sont une suite de variables de même type, situées dans un espace contigu en mémoire"

Bon, je reconnais que ça fait un peu définition de dictionnaire tout ça ^^
Concrètement, il s'agit de "grosses variables" pouvant contenir plusieurs nombres du même type (long, int, char, double...)

Un tableau a une dimension bien précise. Il peut occuper 2 cases, 3 cases, 10 cases, 150 cases, 2500 cases, c'est vous qui décidez.
Ci-dessous, voici un schéma d'un tableau de 4 cases en mémoire qui commence à l'adresse 1600 :


Image utilisateur


Lorsque vous demandez à créer un tableau de 4 cases en mémoire, votre programme demande à l'OS la permission d'utiliser 4 cases en mémoire. Ces 4 cases doivent être contiguës, c'est-à-dire les unes à la suite des autres.
Comme vous le voyez, les adresses se suivent : 1600, 1601, 1602, 1603. Il n'y a pas de "trou" au milieu.
Enfin, chaque case du tableau contient un nombre du même type. Si le tableau est de type int, alors chaque case du tableau contiendra un int. On ne peut pas faire de tableau contenant à la fois des int et des double par exemple.


En résumé, voici ce qu'il faut retenir sur les tableaux :

  • Lorsqu'un tableau est créé, il prend un espace contigu en mémoire : les cases sont les unes à la suite des autres.
  • Toutes les cases d'un tableau sont du même type. Ainsi, un tableau de int contiendra uniquement des int, et pas autre chose.

Définir un tableau

Pour commencer, nous allons voir comment définir un tableau de 4 int :

Code : C
1
int tableau[4];


Voilà c'est tout :)
Il suffit donc de rajouter entre crochets le nombre de cases que vous voulez mettre dans votre tableau. Il n'y a pas de limite (à part peut-être la taille de votre mémoire :D ).

Maintenant, comment accéder à chaque case du tableau ?
Il faut écrire tableau[numeroDeLaCase].

Très important : un tableau commence à l'indice n°0 ! Notre tableau de 4 int a donc les indices 0, 1, 2 et 3. Il n'y a pas d'indice 4 ! C'est une source d'erreurs très courante, souvenez-vous en !


Si je veux mettre dans mon tableau les mêmes valeurs que celles indiquées dans mon schéma, je devrai donc faire :

Code : C
1
2
3
4
5
6
int tableau[4];

tableau[0] = 10;
tableau[1] = 23;
tableau[2] = 505;
tableau[3] = 8;


Tu as dit qu'il y avait des pointeurs avec les tableaux. Où ça, je n'en vois pas ?


En fait, si vous écrivez juste "tableau", vous avez un pointeur. C'est un pointeur sur la première case du tableau.
Faites le test :

Code : C
1
2
3
int tableau[4];

printf("%d", tableau);


Résultat, on voit l'adresse où se trouve tableau :

Code : Console
1600


En revanche, si vous indiquez l'indice de la case du tableau entre crochets, vous obtenez la valeur :

Code : C
1
2
3
int tableau[4];

printf("%d", tableau[0]);


Code : Console
10



De même pour les autres indices.


Notez que, comme tableau est un pointeur, on peut utiliser le symbole * pour connaître la première valeur :

Code : C
1
2
3
int tableau[4];

printf("%d", *tableau);


Code : Console
10


Il est aussi possible d'avoir la valeur de la seconde case en tapant *(tableau + 1) (adresse de tableau + 1).
Les 2 lignes suivantes sont donc identiques :

Code : C
1
2
tableau[1] // Renvoie la valeur contenue dans la seconde case (la première case étant 0)
*(tableau + 1) // Identique : renvoie la valeur contenue dans la seconde case


Donc, quand vous écrivez tableau[0], vous demandez la valeur qui se trouve à l'adresse tableau + 0 cases (c'est-à-dire 1600).
Si vous écrivez tableau[1], vous demandez la valeur se trouvant à l'adresse tableau + 1 case (c'est-à-dire 1601).
Et ainsi de suite pour les autres valeurs :)


Les tableaux à taille dynamique



Le langage C existe en plusieurs versions.
Une version récente, appelée le C99, autorise la création de tableaux à taille dynamique, c'est-à-dire de tableaux dont la taille est définie par une variable :

Code : C
1
2
int taille = 5;
int tableau[taille];


Or, cela n'est pas forcément reconnu par tous les compilateurs, certains planteront sur la ligne n°2.
Le langage C que je vous enseigne depuis le début (appelé le C89) n'autorise pas ce genre de choses. Nous considèrerons donc que faire cela est interdit.

Nous allons nous mettre d'accord sur la chose suivante : vous n'avez pas le droit de mettre une variable entre crochets pour la définition de la taille du tableau, même si cette variable est une constante ! const int taille = 5; ne marchera donc pas mieux.
Le tableau doit avoir une dimension fixe, c'est-à-dire que vous devez écrire noir sur blanc le nombre correspondant à la taille :

Code : C
1
int tableau[5];



Mais... Alors il est interdit de créer un tableau en fonction de la taille d'une variable ?


Non rassurez-vous, c'est possible ! (même en C89 :p )
Mais pour faire cela nous utiliserons une autre technique (plus sûre et qui marche partout) appelée l'allocation dynamique. Nous verrons cela bien plus tard dans la partie II de ce cours.

Parcourir un tableau

Supposons que je veuille maintenant afficher les valeurs de chaque case du tableau.
Je pourrais faire autant de printf qu'il n'y a de cases. Mais bon, c'est répétitif, un peu lourd, et imaginez le bazar si le tableau contenait 8000 nombres :p

Le mieux c'est de se servir d'une boucle. Pourquoi pas d'une boucle for ? Les boucles for sont très pratiques pour parcourir un tableau :

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
int main(int argc, char *argv[])
{
    int tableau[4], i = 0;

    tableau[0] = 10;
    tableau[1] = 23;
    tableau[2] = 505;
    tableau[3] = 8;

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

    return 0;
}


Code : Console
10

23

505

8


Notre boucle parcourt le tableau à l'aide d'une variable appelée i (c'est le nom super original que les programmeurs donnent en général à la variable qui leur permet de parcourir le tableau :p )

Ce qui est particulièrement pratique, c'est qu'on peut mettre une variable entre crochets. En effet, la variable était interdite pour la création du tableau (pour définir sa taille), mais elle est heureusement autorisée pour "parcourir" le tableau, c'est-à-dire afficher ses valeurs !
Ici, on a mis la variable i, qui vaut successivement 0, 1, 2, 3. Ainsi, on va donc afficher la valeur de tableau[0], tableau[1], tableau[2] et tableau[3] ! :)

Attention à ne pas tenter d'afficher la valeur de tableau[4] ! Un tableau de 4 cases possède les indices 0, 1, 2 et 3, point barre. Si vous tentez d'afficher tableau[4], vous aurez soit n'importe quoi, soit une belle erreur, l'OS coupant votre programme car il aura tenté d'accéder à une adresse ne lui appartenant pas.


Voilà la technique ^^
Ce n'est pas bien bien compliqué vous voyez.


Initialiser un tableau



Maintenant que l'on sait parcourir un tableau, on est capables d'initialiser toutes ses valeurs à 0 en faisant une boucle !

Bon, parcourir le tableau pour mettre 0 à chaque case, c'est pas trop dur vous devriez arriver à le faire :)
Voici le code :

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
int main(int argc, char *argv[])
{
    int tableau[4], i = 0;

    // Initialisation du tableau
    for (i = 0 ; i < 4 ; i++)
    {
        tableau[i] = 0;
    }

    // Affichage de ses valeurs pour vérifier
    for (i = 0 ; i < 4 ; i++)
    {
        printf("%d\n", tableau[i]);
    }

    return 0;
}


Code : Console
0

0

0

0



Une autre façon d'initialiser



Il faut savoir qu'il existe une autre façon d'initialiser un tableau un peu plus automatisée en C.
Elle consiste à écrire tableau[4] = {valeur1, valeur2, valeur3, valeur4}
En clair, vous mettez les valeurs une à une entre accolades, séparées par des virgules :

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
int main(int argc, char *argv[])
{
    int tableau[4] = {0, 0, 0, 0}, i = 0;

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

    return 0;
}


Code : Console
0

0

0

0


Mais en fait, c'est même mieux que ça : vous pouvez définir les valeurs des premières cases du tableau, toutes celles que vous n'aurez pas renseignées seront automatiquement mises à 0.

Ainsi, si je fais :

Code : C
1
int tableau[4] = {10, 23}; // Valeurs insérées : 10, 23, 0, 0


La case n°0 prendra la valeur 10, la n°1 prendra 23, et toutes les autres prendront la valeur 0 (par défaut).

Comment initialiser tout le tableau à 0 en sachant ça ?
Eh bien, il vous suffit d'initialiser au moins la première valeur à 0, et toutes les autres valeurs non indiquées prendront la valeur 0 :)

Code : C
1
int tableau[4] = {0}; // Toutes les cases du tableau seront initialisées à 0


Cette technique a l'avantage de fonctionner avec un tableau de n'importe quelle taille (là ça marche pour 4 cases, mais s'il en avait eu 100 ça aurait été bon aussi ;) )

Attention, contrairement à ce que beaucoup d'entre vous semblent croire :
Code : C
1
int tableau[4] = {1}; // Valeurs insérées : 1, 0, 0, 0

On n'initialise pas toutes les cases à 1 en faisant cela : seule la première case sera à 1, les autres seront à 0. On ne peut donc pas initialiser toutes les cases à 1 automatiquement, à moins de faire une boucle.

Passage de tableaux à une fonction

Vous aurez sûrement souvent besoin d'afficher tout le contenu de votre tableau.
Pourquoi ne pas écrire une fonction qui fait ça ? Ca va nous permettre de voir comment on envoie un tableau à une fonction en plus, donc ça m'arrange :-°

Il va falloir envoyer 2 informations à la fonction : le tableau (enfin, l'adresse du tableau) et aussi et surtout sa taille !
En effet, notre fonction doit être capable d'initialiser un tableau de n'importe quelle taille. Or, dans votre fonction vous ne connaissez pas la taille de votre tableau. C'est pour cela qu'il faut envoyer en plus une variable que vous appellerez par exemple tailleTableau.

Comme je vous l'ai dit, tableau peut être considéré comme un pointeur. On peut donc l'envoyer à la fonction comme on l'aurait fait avec un vulgaire pointeur :

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Prototype de la fonction d'affichage
void affiche(int *tableau, int tailleTableau);
 
int main(int argc, char *argv[])
{
    int tableau[4] = {10, 15, 3};
 
    // On affiche le contenu du tableau
    affiche(tableau, 4);
 
    return 0;
}
 
void affiche(int *tableau, int tailleTableau)
{
    int i;
 
    for (i = 0 ; i < tailleTableau ; i++)
    {
        printf("%d\n", tableau[i]);
    }
}


Code : Console
10
15
3
0


La fonction n'est pas différente de celles que l'on a étudiées dans le chapitre sur les pointeurs. Elle prend en paramètre un pointeur sur int (notre tableau), ainsi que la taille du tableau (très important pour savoir quand s'arrêter dans la boucle !).
Tout le contenu du tableau est affiché par la fonction via une boucle.

Important : il existe une autre façon d'indiquer que la fonction reçoit un tableau. Plutôt que d'indiquer que la fonction attend un int *tableau, mettez ceci :

Code : C
1
void affiche(int tableau[], int tailleTableau)


Cela revient exactement au même, mais la présence des crochets permet au programmeur de bien voir que c'est un tableau que la fonction prend, et non un simple pointeur. Ca permet d'éviter des confusions ;)
J'utilise personnellement tout le temps les crochets dans mes fonctions pour bien montrer que la fonction attend un tableau. Je vous conseille de faire de même. Il n'est pas nécessaire de mettre la taille du tableau entre les crochets cette fois.



Quelques exercices !



J'ai plein d'idées d'exercices pour vous entraîner ! :D
Je vous propose de réaliser des fonctions travaillant sur des tableaux.

Je donne juste les énoncés des exercices ici pour vous forcer à réfléchir à vos fonctions. Si vous avez du mal à réaliser ces fonctions, rendez-vous sur les forums pour poser vos questions ;)

  • Exercice 1 : créer une fonction sommeTableau qui renvoie la somme des valeurs contenues dans le tableau (utilisez un return pour renvoyer la valeur).
    Pour vous aider, voici le prototype de la fonction à créer :

    Code : C
    1
    int sommeTableau(int tableau[], int tailleTableau);
    


  • Exercice 2 : créer une fonction moyenneTableau qui calcule et renvoie la moyenne des valeurs.
    Prototype :

    Code : C
    1
    double moyenneTableau(int tableau[], int tailleTableau);
    


    La fonction renvoie un double car une moyenne est parfois un nombre décimal (souvent même :p )

  • Exercice 3 : créer une fonction copierTableau qui prend en paramètre 2 tableaux. Le contenu du premier tableau devra être copié dans le second tableau.
    Prototype :

    Code : C
    1
    void copie(int tableauOriginal[], int tableauCopie[], int tailleTableau);
    


  • Exercice 4 : créer une fonction maximumTableau qui aura pour rôle de remettre à 0 toutes les cases du tableau ayant une valeur supérieure à un maximum. Cette fonction prendra en paramètre le tableau ainsi que le nombre maximum autorisé (valeurMax). Toutes les cases qui contiennent un nombre supérieur à valeurMax doivent être mises à 0.
    Prototype :

    Code : C
    1
    void maximumTableau(int tableau[], int tailleTableau, int valeurMax);
    


  • Exercice 5 (plus difficile) : créer une fonction ordonnerTableau qui classe les valeurs d'un tableau dans l'ordre croissant. Ainsi, un tableau qui vaut {15, 81, 22, 13} doit à la fin de la fonction valoir {13, 15, 22, 81} !
    Cet exercice est un peu plus difficile que les autres, mais est tout à fait réalisable. Ca va vous occuper un petit moment :p

    Prototype :

    Code : C
    1
    void ordonnerTableau(int tableau[], int tailleTableau);
    




Faites-vous un petit fichier de fonctions appelé tableaux.c (avec son homologue tableaux.h qui contiendra les prototypes bien sûr !) contenant toutes les fonctions de votre cru réalisant des opérations sur des tableaux :)
Vous entraîner comme ça, c'est le meilleur moyen de vous former :)



Au boulot ! ;)

Q.C.M.

Laquelle de ces lignes crée un tableau de 10 double ?
A quel indice commence un tableau ?
Qu'est-ce qu'un tableau à dimension dynamique ?
Lequel de ces prototypes de fonction ne permet pas de faire passer mon tableau ?
Si je crée un tableau de 20 char appelé tableau situé à l'adresse 45782015... quelle est l'adresse de tableau[3] ?
Quelle est l'autre façon d'initialiser mon tableau avec ces valeurs ?


Code : C
1
2
3
4
5
6
int tableau[4];

tableau[0] = 10;
tableau[1] = 23;
tableau[2] = 505;
tableau[3] = 8;

Statistiques de réponses au QCM

Lorsqu'on a appris à se servir des pointeurs, généralement le reste coule de source. Je ne pense pas que ce chapitre vous aura posé trop de problèmes (enfin je peux me tromper hein ^^ )
Attention toutefois, cela ne veut pas dire qu'il n'y a pas de pièges. Si je devais vous faire retenir 2 choses auxquelles il faut faire très attention ce serait :

  • N'oubliez JAMAIS qu'un tableau commence à l'indice 0, et non pas l'indice 1
  • Quand vous envoyez un tableau à une fonction, envoyez toujours à côté la taille du tableau. Sinon, il n'est pas possible de connaître la taille du tableau lorsqu'on doit le parcourir !


Ah au fait, j'ai une bonne nouvelle. Vous avez maintenant le niveau pour manipuler des chaînes de caractères, c'est-à-dire du texte. Vous allez pouvoir être capables de retenir du texte dans la mémoire, et donc de demander à l'utilisateur son nom par exemple :)
Ah il en aura fallu du temps pour faire une chose aussi simple, comme quoi vous voyez même ça ce n'était pas simple ^^

Nous allons justement étudier les chaînes de caractères dans le prochain chapitre.
(hop hop hop, vous avez vu la transition de dingue que je viens de faire là ? :D )
Chapitre précédent Sommaire Chapitre suivant

Partager

854 commentaires pour "Les tableaux"
Note moyenne : 3.89 / 4 (2856 votes)
Pseudo Commentaire
Hors ligne Mydym # Posté le 01/02/2012 à 23:35:59

J'ai trouvé ce code en réponse à l'exercice 5 car je ne trouvais pas la réponse, j'ai testé, ça fonctionne mais je ne comprends pas pourquoi...

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <stdio.h>
#include <stdlib.h>


void ordonnerTableau(int tableau[], int tailleTableau);

int main(int argc, char *argv[])
{
    int tableau[4] = {10, 15, 4, 16};

    ordonnerTableau(tableau, 4);

    return 0;
}

void ordonnerTableau(int tableau[], int tailleTableau)
{
    int i , j , difference;

    for (i = 0 ; i < tailleTableau ; i++)
    {
        for (j = 0 ; j < tailleTableau ; j++)
        {
            if (tableau[i] < tableau[j])
            {
                difference = tableau[i] - tableau[j];
                tableau[i] -= difference;
                tableau[j] += difference;
            }
        }
    }
    for(i = 0; i < tailleTableau ; i++)
    {
        printf("%d\n", tableau[i]);
    }
}
Hors ligne CreiZyz # Posté le 03/02/2012 à 23:25:33

Salut salut! D'abord, je tient a remercier le site du zero, et surtout mateo pour tout ce qu'il nous apporte!

Sinon, j'ai un petit problème avec mon code a l'exercice 5... il se base sur une boucle, mais ca déconne dans ma prise en compte des valeurs. En fait, il prend en compte une valeur de trop a cause du fonctionnement de ma boucle (le i+1 ligne 9). J'ai cherché a résoudre ce problème en remettant a zero cette valeur, mais ca ne marche pas. Quelqu'un aurait une solution?
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
void ordonf(int tableau[], int taille)
{
    int i = 0, c = 0, d = 0, m = 0;
    for (c = 0; c < taille - 1; c++)
    {
        for (i = 0; i < taille - 1; i++) //for (i = 0; i < taille; i++) changé en for (i = 0; i < taille - 1; i++)
        {
            if (tableau[i] < tableau[i+1])
            {
                d = tableau[i];
                m = tableau[i+1];
                tableau[i] = m;
                tableau[i+1] = d;
            }
        }
    }
    for (i = 0; i < taille; i++)
    {
        printf("\nvaleur %d apres tri: %d", i, tableau[i]);
    }
}


EDIT:
Problème résolu... c'est plutôt idiot d'ailleurs, il suffisait que je fasse 1 test de moins :)
Hors ligne Ismuur # Posté le 05/02/2012 à 14:36:38
Avatar

Salut à tous!
Tout d'abord un GRAND merci à M@théo21, parce que ce tuto est vraiment génial!
Ensuite pour ceux qui le veulent, voilà ma solution pour l'exercice 5, ce n'est peut être pas la meilleure mais elle à l'air de fonctionner et c'est le principal!Secret (cliquez pour afficher)
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
//Organise un tableau en mettant ses valeurs dans l'ordre croissant
void ordonnerTableau(int tableau[], int tailleTableau)
{
    int i = 0, k = 0, l = 0;

    for(l = 0; l < tailleTableau; l++) //Cette boucle est là pour ranger toutes les cases du tableau dans l'ordre croissant
    {
        for(i = 0; i < tailleTableau; i++) // Cette boucle permet de ranger une case par rapport à celle qui la suit seulement (d'où la nécessité de la boucle précédante)
        {
            if(tableau[i] > tableau[i+1])
            {
                k = tableau[i]; //On a besoin de k sinon on perd une valeur
                tableau[i] = tableau[i + 1];
                tableau[i + 1] = k;
            }
        }
    }

}

Voilà! Bon courage à tous et encore merci pour ce tuto! :)
Hors ligne X.Yassir.Matar.X # Posté le 06/02/2012 à 21:11:22

bonjour un GRAND merci a mateos pour ce très bon cours .
bon je bloque sur l'exercice n°5 bien que je crois que le probleme n'a rien a voir avec les tableau en sois , en effet bien que je n'ai aucune erreure lors de la compilation mon programme plante des son lancemment , voici mon code :
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <stdio.h>
#include <stdlib.h>
void ordonnerTableau(int tableau[], int taille);

int permuter(int* A,int* B);

int main(int argc,int *argv)
{
    int taille=5 ,i=0;
	int tableau[5]={0};

    for(i=0;i>taille;i++)
    {
        printf("entrez la valeur n°%d de votre tableau:",i);
        scanf("%d",&tableau[i]);
    }
    ordonnerTableau(tableau,taille);
    for(i=0;i>taille;i++)
    printf("%d",i);
}
void ordonnerTableau(int tableau[],int taille)
{
    int i=0, anomallie=1;/* variable qui sert a detecter si il y a une anomalie dans l'arrangement du tableau, si la boucle parcours le tableau sans 
						 changer la variable anomalie ca veut dire que que le tableau est trié */
    do
    {
    for(i=0;i>taille;i++)
    {
        if (tableau[i]>tableau[i+1])
		{
            permuter(&tableau[i],&tableau[i+1]);
			anomallie=1;
		}
        else anomallie=0;
    }
    }while (anomallie==1);
}
int permuter(int *A,int *B)
{
    int temp=0;
    temp=*A;
    *B=*A;
    *A=temp;
    return 0;
}
Hors ligne X.Yassir.Matar.X # Posté le 06/02/2012 à 21:16:43

je m'excuse oubliez mon misérable post :D

Voir tous les commentaires