Vue d'ensemble
Jusqu'ici, chaque donnée avait son propre nom de variable. Mais comment stocker les 30 notes d'une classe, les pixels d'une image ou les lettres d'un mot ? On ne va pas créer note1, note2, … note30 ! Le tableau range plusieurs valeurs de même type dans une seule structure, accessibles par un indice. Et une chaîne de caractères — un mot, une phrase — n'est en C rien d'autre qu'un tableau de lettres avec une astuce : un marqueur de fin. Ce chapitre est la brique de base de presque tout le reste de l'année.
- Tableaux statiques : déclaration
int t[5];, initialisation, taille fixe connue à la compilation. - Accès et modification par indice
t[i]; parcours par une bouclefor. - Le piège majeur du C : aucun contrôle des débordements d'indice (comportement indéfini).
- Tableaux à deux dimensions
int m[2][3];, accèsm[i][j]. - Chaînes de caractères : tableau de
charterminé par le caractère nul ; écrire soi-même la fonction longueur.
Prérequis
- Les types de base du C (
int,char) et la déclaration de variables. - La boucle
foret la bouclewhile, la conditionif. - Écrire et appeler une fonction (paramètres, valeur de retour).
- L'affichage avec
printfet les formats%d,%c,%s.
Tout cela est couvert dans la fiche « C — Premiers pas ». Si l'un de ces points est flou, relis-la d'abord : sans la boucle for, les tableaux restent inaccessibles.
Les tableaux, c'est là que beaucoup décrochent en info. L'indice, le marqueur de fin, le débordement… autant de pièges silencieux qui font perdre des heures seul devant l'écran. Nos mentors alumni X · Centrale · Mines t'apprennent à raisonner comme un informaticien, pas à réciter.
Trouver un mentor →Les tableaux statiques
Un tableau est une suite de cases consécutives en mémoire, toutes de même type, désignées par un unique nom et repérées par un indice entier qui commence à 0. Un tableau de cases a donc des indices valides de à .
Déclarer et initialiser
Il y a deux façons de créer un tableau. Soit on réserve les cases sans les remplir :
int t[5]; // 5 cases entières, valeurs pour l'instant inconnues
t[0] = 3; // on remplit case par case
t[1] = 1;int t[5];réserve un bloc de 5 cases entières consécutives, nommé t. Les indices vont de t[0] à t[4]. Le 5 doit être une constante connue dès la compilation : la taille est fixe.t[0] = 3;écrit la valeur 3 dans la première case (indice 0, pas 1 !). C'est le point qui piège le plus au début.t[1] = 1;écrit dans la deuxième case. Les cases non encore remplies contiennent des valeurs indéterminées (des « déchets » mémoire), pas forcément 0.Soit — plus court — on donne directement les valeurs entre accolades :
int t[] = {3, 1, 4, 1, 5}; // taille déduite : 5 casesint t[] = {3, 1, 4, 1, 5};crée un tableau et le remplit d'un coup. Les crochets [] sont laissés vides : le compilateur compte les valeurs (ici 5) et fixe la taille à 5. On obtient t[0]=3, t[1]=1, t[2]=4, t[3]=1, t[4]=5.t déclaré avec 5 cases, il aura toujours 5 cases : on ne peut ni l'agrandir ni le rétrécir. C'est pourquoi on parle de tableau statique. Pour cette raison, on garde presque toujours la taille dans une variable à côté (souvent nommée n) : le tableau, lui, ne « connaît » pas sa propre longueur.Accéder et modifier une case
La notation t[i] désigne la case d'indice i. Elle sert à la fois à lire et à écrire :
int x = t[2]; // LIRE : x reçoit la valeur de la case 2, soit 4
t[2] = 9; // ÉCRIRE : la case 2 vaut désormais 9int x = t[2];à droite du =, t[2] vaut la valeur stockée (4) : on la lit et on la recopie dans x.t[2] = 9;à gauche du =, t[2] désigne la case elle-même : on y écrit 9. Le tableau devient {3, 1, 9, 1, 5}. Même notation, deux rôles selon le côté du =.Parcourir un tableau
L'opération reine : passer sur chaque case avec une boucle for. Calculons la somme des éléments.
#include <stdio.h>
int main(void) {
int t[] = {3, 1, 4, 1, 5};
int n = 5; // on retient la taille à part
int somme = 0;
for (int i = 0; i < n; i++) {
somme = somme + t[i]; // on ajoute la case courante
}
printf("Somme = %d\n", somme); // affiche : Somme = 14
return 0;
}int n = 5;on stocke la taille dans n. Le tableau ne la connaît pas ; c'est à nous de la garder pour savoir où s'arrêter.int somme = 0;l'accumulateur démarre à 0 (élément neutre de l'addition). On y empilera les valeurs.for (int i = 0; i < n; i++)i part de 0, la boucle continue tant que i < n (donc pour i = 0,1,2,3,4), et i++ passe à la case suivante. La condition < n (et non <= n) garantit qu'on s'arrête à l'indice 4, le dernier valide.somme = somme + t[i];cœur du parcours : on ajoute à l'accumulateur la valeur de la case d'indice i. Après la boucle, somme contient le total.printf("Somme = %d\n", somme);%d affiche l'entier somme ; ici la sortie est Somme = 14.Suivons l'exécution case par case pour voir l'accumulateur grossir :
| Tour | i | i < 5 ? | t[i] | somme après ajout |
|---|---|---|---|---|
| départ | — | — | — | 0 |
| 1 | 0 | vrai | 3 | 0 + 3 = 3 |
| 2 | 1 | vrai | 1 | 3 + 1 = 4 |
| 3 | 2 | vrai | 4 | 4 + 4 = 8 |
| 4 | 3 | vrai | 1 | 8 + 1 = 9 |
| 5 | 4 | vrai | 5 | 9 + 5 = 14 |
| fin | 5 | faux → sortie | — | 14 ✓ |
Parcourir un tableau de cases coûte tours de boucle : le calcul de la somme est en .
- Garde la taille dans une variable
ndéclarée à côté du tableau. - Boucle
for (int i = 0; i < n; i++): indice initial 0, condition strictement< n. - À l'intérieur, ne manipule les cases que via
t[i]— jamaist[n], qui n'existe pas.
Le piège majeur : le débordement d'indice
Voici LE point qui distingue le C d'un langage comme Python. Que se passe-t-il si on accède à une case qui n'existe pas ?
int t[5]; // cases valides : t[0] à t[4]
t[5] = 42; // l'indice 5 n'existe pas : DÉBORDEMENTint t[5];5 cases, donc les seuls indices légaux sont 0, 1, 2, 3, 4. Il n'y a pas de case d'indice 5.t[5] = 42;on écrit hors des limites du tableau. En Python ce serait une erreur nette (IndexError). En C, rien ne vérifie l'indice : le programme écrit dans une zone mémoire qui ne lui appartient pas. C'est un comportement indéfini.0 et n-1. Les deux erreurs les plus fréquentes : écrire i <= n au lieu de i < n dans un for, et oublier que le premier indice est 0 (donc croire que le dernier est n).Les tableaux à deux dimensions
Pour représenter une grille, une matrice ou une image, on utilise un tableau à deux indices : une ligne i et une colonne j.
#include <stdio.h>
int main(void) {
int m[2][3] = {{1, 2, 3},
{4, 5, 6}}; // 2 lignes, 3 colonnes
printf("%d\n", m[1][2]); // ligne 1, colonne 2 -> affiche 6
return 0;
}int m[2][3] = ...déclare une grille de 2 lignes et 3 colonnes, soit 6 cases. Le premier crochet est le nombre de lignes, le second le nombre de colonnes.{{1, 2, 3}, {4, 5, 6}}chaque accolade interne est une ligne. Ligne 0 = {1,2,3}, ligne 1 = {4,5,6}.m[1][2]on lit la case ligne 1 (la deuxième), colonne 2 (la troisième) : c'est 6. Les deux indices commencent à 0, comme toujours.Pour parcourir une grille, on imbrique deux boucles : une pour les lignes, une pour les colonnes.
for (int i = 0; i < 2; i++) { // pour chaque ligne
for (int j = 0; j < 3; j++) { // pour chaque colonne
printf("%d ", m[i][j]); // affiche la case (i, j)
}
}for (int i = 0; i < 2; i++)boucle externe : elle choisit la ligne, de 0 à 1.for (int j = 0; j < 3; j++)boucle interne : pour la ligne courante, elle parcourt les 3 colonnes. Elle tourne entièrement à chaque valeur de i.printf("%d ", m[i][j]);affiche la case courante. L'ordre de visite est m[0][0], m[0][1], m[0][2], m[1][0], … — ligne par ligne, de gauche à droite. Sortie : 1 2 3 4 5 6.Les chaînes de caractères
En C, il n'existe pas de type « chaîne » à part entière. Un mot est simplement un tableau de char. Mais comment savoir où le mot s'arrête, puisque le tableau ne connaît pas sa taille ? Grâce à un caractère spécial marquant la fin.
Une chaîne de caractères en C est un tableau de char dont la fin est signalée par le caractère nul (noté '\0', de valeur 0). Ce marqueur n'est pas affiché : il sert uniquement de sentinelle indiquant « le mot s'arrête ici ». Ainsi char s[] = "abc" occupe 4 cases : 'a', 'b', 'c', puis le caractère nul.
#include <stdio.h>
int main(void) {
char s[] = "abc"; // 4 cases : 'a' 'b' 'c' puis le nul
printf("%s\n", s); // affiche : abc
return 0;
}char s[] = "abc";crée un tableau de char. Les guillemets "…" ajoutent automatiquement le caractère nul à la fin : on obtient s[0]='a', s[1]='b', s[2]='c', s[3]='\0'. Taille réelle : 4, pas 3.printf("%s\n", s);%s affiche les caractères un par un jusqu'à rencontrer le caractère nul, qu'il n'affiche pas. Résultat : abc. C'est ce marqueur qui dit à printf où s'arrêter."info" (4 lettres) occupe 5 cases : i, n, f, o, puis le caractère nul. Règle d'or : un mot de lettres occupe cases. Oublier ce « +1 » est la source d'innombrables bugs.Écrire soi-même la fonction longueur
Puisqu'une chaîne ne connaît pas sa taille, on la calcule : on avance case par case et on compte jusqu'au caractère nul.
int longueur(char s[]) {
int i = 0;
while (s[i] != '\0') { // tant qu'on n'a pas atteint la fin
i = i + 1; // on avance d'un caractère
}
return i; // i = nombre de caractères avant le nul
}int longueur(char s[])fonction qui reçoit une chaîne s et renvoie un entier. Les crochets [] vides disent « s est un tableau de char », sans en fixer la taille.int i = 0;compteur/indice de parcours, démarré sur la première case.while (s[i] != '\0')on continue tant que la case courante n'est pas le marqueur de fin. Dès qu'on tombe sur le caractère nul, la condition devient fausse et on sort.i = i + 1;on passe au caractère suivant. Chaque tour compte donc exactement un caractère « réel ».return i;à la sortie, i vaut le nombre de caractères rencontrés avant le caractère nul — précisément la longueur du mot. Pour "abc", on renvoie 3 (et non 4).Déroulons ce parcours sur "abc", case par case :
| Tour | i | s[i] | s[i] != '\0' ? | action |
|---|---|---|---|---|
| 1 | 0 | 'a' | vrai | i devient 1 |
| 2 | 1 | 'b' | vrai | i devient 2 |
| 3 | 2 | 'c' | vrai | i devient 3 |
| fin | 3 | '\0' | faux → sortie | return 3 ✓ |
'\0' final, printf("%s", …) et longueur continueront à lire au-delà du mot, dans la mémoire voisine, jusqu'à tomber par hasard sur un octet nul : caractères parasites, longueur fantaisiste, voire plantage. Le caractère nul n'est pas décoratif : c'est lui qui définit la fin de la chaîne.« Ça compile mais le résultat est bizarre. » Débordement, caractère nul oublié, indice décalé de 1 : en C, un bug ne crie pas, il chuchote. Nos mentors alumni X · Centrale · Mines te montrent la méthode de trace qui fait apparaître l'erreur en trois lignes de papier.
Trouver un mentor →Exercices corrigés
Écris une fonction int maximum(int t[], int n) qui renvoie la plus grande valeur d'un tableau t de n entiers (on suppose n ≥ 1). Déroule-la mentalement sur {4, 9, 2, 7}.
Voir la correction détaillée
Idée : on retient un « champion » provisoire, initialisé à la première case, puis on le remplace dès qu'on voit plus grand.
int maximum(int t[], int n) {
int m = t[0]; // champion = 1re case
for (int i = 1; i < n; i++) { // on commence à 1 : t[0] est déjà pris
if (t[i] > m) {
m = t[i]; // nouveau champion
}
}
return m;
}Pourquoi partir de t[0] et de i = 1 ? Initialiser à 0 serait faux si toutes les valeurs étaient négatives. On prend donc un élément qui existe vraiment. Comme t[0] est déjà le champion de départ, la boucle commence à l'indice 1.
Déroulé sur {4, 9, 2, 7} : m = 4. i=1 : 9 > 4 → m = 9. i=2 : 2 > 9 ? non. i=3 : 7 > 9 ? non. Résultat : 9. Coût : un seul parcours, .
Écris int compte(char s[], char c) qui renvoie le nombre d'occurrences du caractère c dans la chaîne s. Que renvoie compte("banane", 'a') ? Combien de cases occupe "banane" en mémoire ?
Voir la correction détaillée
On parcourt la chaîne jusqu'au caractère nul en incrémentant un compteur à chaque case égale à c.
int compte(char s[], char c) {
int n = 0;
for (int i = 0; s[i] != '\0'; i++) { // arrêt sur le caractère nul
if (s[i] == c) {
n = n + 1;
}
}
return n;
}La condition d'arrêt est s[i] != '\0', pas un i < n : pour une chaîne, on ne connaît pas la taille d'avance, c'est la sentinelle qui borne le parcours. Comparer des char avec == est correct (un char est un petit entier).
Résultats. "banane" = b a n a n e : le 'a' apparaît aux indices 1 et 3, donc compte("banane", 'a') vaut 2. Le mot a 6 lettres ; avec le caractère nul il occupe 7 cases.
Écris void inverse(int t[], int n) qui inverse l'ordre des éléments dans le tableau lui-même (sans en créer un second). Illustre sur {10, 20, 30, 40, 50}. Combien d'échanges effectue-t-on ?
Voir la correction détaillée
Idée : échanger la première case avec la dernière, la deuxième avec l'avant-dernière, etc. On avance avec un indice i et sa case symétrique n - 1 - i.
void inverse(int t[], int n) {
for (int i = 0; i < n / 2; i++) { // jusqu'au milieu seulement
int tmp = t[i]; // sauvegarde temporaire
t[i] = t[n - 1 - i]; // la case symétrique arrive à gauche
t[n - 1 - i] = tmp; // et la sauvegarde part à droite
}
}Pourquoi i < n / 2 et pas i < n ? Si on allait jusqu'au bout, on ré-échangerait chaque paire une seconde fois et on retomberait sur le tableau de départ ! On ne traite donc que la première moitié. La case symétrique de l'indice i est n - 1 - i.
Pourquoi la variable tmp ? Sans elle, t[i] = t[n-1-i] écraserait la valeur de t[i] avant qu'on ait pu la déplacer : on la sauvegarde d'abord.
Déroulé sur {10, 20, 30, 40, 50} : n = 5, donc n / 2 = 2 (division entière), i prend les valeurs 0 et 1. i=0 : échange t[0] et t[4] → {50, 20, 30, 40, 10}. i=1 : échange t[1] et t[3] → {50, 40, 30, 20, 10}. La case centrale t[2] = 30 ne bouge pas. On a fait 2 échanges.
Récap final — Ce qu'il faut absolument retenir
Les tableaux et les chaînes sont la fondation de tout le reste du cours d'info. Vérifie que chaque case de ta mémoire est bien remplie — et surtout, qu'aucune ne déborde.
- Sais-tu déclarer un tableau de taille fixe (
int t[5];) et l'initialiser d'un coup (int t[] = {…};) ? - Sais-tu que les indices valides d'un tableau de cases vont de 0 à , et que le premier indice est 0 ?
- Sais-tu parcourir un tableau avec
for (int i = 0; i < n; i++)et pourquoi la condition est strictement< n? - Sais-tu qu'accéder hors des bornes est un comportement indéfini — pas une erreur propre — et que le C ne vérifie rien ?
- Sais-tu lire une case d'un tableau 2D avec
m[i][j](ligne puis colonne) ? - Sais-tu qu'une chaîne C est un tableau de
charterminé par le caractère nul, et qu'un mot de lettres occupe cases ? - Sais-tu écrire la fonction longueur en comptant jusqu'au caractère nul, et pourquoi elle renvoie et non ?
- Sais-tu quel désastre provoque un caractère nul oublié lors d'un affichage
%s?