☀️ Stage Pré-rentrée · dès le 24 aoûtRéserver ma place →
Majorant
📘 Fiche de cours · 1re année💻 MP2I💻 Informatique MP2I / MPINiveau · MP2I

C — Tableaux et chaînes de caractères

La brique de base de presque tout le reste de l'année : les tableaux statiques (indice à partir de 0, taille fixe, débordement non contrôlé), les tableaux 2D, et les chaînes de caractères comme tableaux de char terminés par '\0' — chaque programme compilé, avec trois exercices corrigés.

Fiche rédigée par les mentors Majorant — alumni Polytechnique, CentraleSupélec et Mines Paris.

2 définitionsMis à jour le 2026-08-02

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.

Au programme (MP2I, réforme 2021)
  • Tableaux statiques : déclaration int t[5];, initialisation, taille fixe connue à la compilation.
  • Accès et modification par indice t[i] ; parcours par une boucle for.
  • 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ès m[i][j].
  • Chaînes de caractères : tableau de char terminé 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 for et la boucle while, la condition if.
  • Écrire et appeler une fonction (paramètres, valeur de retour).
  • L'affichage avec printf et 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.

🎯 Accompagnement Majorant

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

Définition 1.1 — Tableau

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;
🔍 Décryptage ligne par ligne
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 cases
🔍 Décryptage ligne par ligne
int 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.
📝 La taille est figée. Une fois 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 9
🔍 Décryptage ligne par ligne
int 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;
}
🔍 Décryptage ligne par ligne
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 :

Trace de la somme sur t = {3, 1, 4, 1, 5}
Tourii < 5 ?t[i]somme après ajout
départ0
10vrai30 + 3 = 3
21vrai13 + 1 = 4
32vrai44 + 4 = 8
43vrai18 + 1 = 9
54vrai59 + 5 = 14
fin5faux → sortie14 ✓

Parcourir un tableau de cases coûte tours de boucle : le calcul de la somme est en .

📐 Méthode — Parcourir un tableau sans se tromper
  1. Garde la taille dans une variable n déclarée à côté du tableau.
  2. Boucle for (int i = 0; i < n; i++) : indice initial 0, condition strictement < n.
  3. À l'intérieur, ne manipule les cases que via t[i] — jamais t[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ÉBORDEMENT
🔍 Décryptage ligne par ligne
int 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.
⚠ Comportement indéfini ≠ erreur propre. Un débordement peut sembler marcher (le programme continue sans broncher), écraser une autre variable en douce, produire un résultat aberrant, ou planter (segmentation fault) — et pas forcément à la ligne fautive ! Le C ne te prévient pas. C'est à toi de garantir que tout indice reste entre 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).
📝 Pourquoi le C fait-il ça ? Par choix de performance : vérifier chaque indice à l'exécution coûterait du temps. Le C fait confiance au programmeur. C'est puissant mais impitoyable — d'où l'importance des traces et des tests.

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;
}
🔍 Décryptage ligne par ligne
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)
    }
}
🔍 Décryptage ligne par ligne
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.

Définition 2.1 — Chaîne de caractères et caractère nul

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;
}
🔍 Décryptage ligne par ligne
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.
💡 Repère mémoire. Le mot "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
}
🔍 Décryptage ligne par ligne
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 :

Trace de longueur("abc") — les cases sont 'a' 'b' 'c' '\0'
Touris[i]s[i] != '\0' ?action
10'a'vraii devient 1
21'b'vraii devient 2
32'c'vraii devient 3
fin3'\0'faux → sortiereturn 3 ✓
⚠ Ne jamais « oublier » le caractère nul. Si tu construis une chaîne case par case et que tu omets d'écrire le '\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.
🎯 Accompagnement Majorant

« Ç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

Exo 1Maximum d'un tableauFacile

É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, .

Exo 2Compter une lettre dans un motIntermédiaire

É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.

Exo 3Inverser un tableau sur placeDifficile

É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 char terminé 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 ?

Débloque la fiche complète

Théorèmes, démonstrations à savoir refaire, méthodes-types et pièges de concours : crée ton compte gratuit pour tout lire. Une seule fois pour toutes les fiches et ressources Majorant.

Gratuit · vos données restent confidentielles.

Valide tes acquis

Quiz — C : tableaux & chaînes

10 questions · une à la fois · seuil de maîtrise 80 %.

MP2I / MPI · MP2IQuiz — C — Tableaux et chaînes de caractèresQuestion 1 / 10
FacileChoix unique1 pt

Combien de cases occupe en mémoire la chaîne déclarée par char s[] = "hello" ?

Sélectionne une réponse pour valider.

Fiches associées

💻 MP2I·Informatique

C — Premiers pas

Écrire son premier programme C : la structure main/return, les types de base, printf et ses formats, les boucles for/while, et le piège n°1 — la division entière (7/2 vaut 3, pas 3,5) — chaque programme compilé et tracé, avec trois exercices corrigés.

💻 MP2I·Informatique

C — Pointeurs et allocation dynamique

Le cœur du C : l'adresse et le pointeur, les opérateurs & et *, pourquoi il faut un pointeur pour modifier une variable (le passage par valeur), le lien tableaux/pointeurs, et malloc/free — chaque programme compilé et tracé, avec trois exercices corrigés.

💻 MP2I·Informatique

OCaml — Premiers pas

Découvrir OCaml, le langage fonctionnel de MP2I : le let et le typage inféré, les fonctions, le piège des opérateurs pointés (+. pour les float), le if/then/else qui renvoie une valeur, et la récursivité let rec (factorielle déroulée) — avec trois exercices corrigés.

💻 MP2I·Informatique

OCaml — Filtrage et listes

Les deux piliers d'OCaml : le filtrage (match ... with) et les listes récursives (:: et []), avec longueur et somme déroulées sur un exemple, les types somme et le type option (Some/None) — attention à l'ordre et à l'exhaustivité des cas, avec trois exercices corrigés.

💻 MP2I·Informatique

C — Structures et listes chaînées

La première structure de données dynamique du programme : les struct, le maillon et l'opérateur flèche p->suivant, l'insertion en tête et le parcours d'une liste chaînée — construction de [3, 5, 8] tracée, avec les pièges (NULL, ordre inversé, fuite mémoire) et trois exercices corrigés.

💻 MP2I·Informatique

C — Piles et files

Les deux structures linéaires fondamentales implémentées en C : la pile (LIFO, empiler/dépiler en tête) et la file (FIFO, avec un pointeur de queue pour enfiler en O(1)) — chaque opération compilée et tracée, avec trois exercices corrigés.

Tu veux aller plus loin sur ce chapitre ?

Nos mentors alumni de Polytechnique, CentraleSupélec et Mines Paris t'accompagnent en cours particuliers — démonstrations détaillées, exos type concours, oraux blancs.

Trouver un mentor →