Une rangée de valeurs de taille fixe
Un tableau est un bloc de mémoire contigu qui contient un nombre fixe de valeurs du même type. Là où un seul int stocke un nombre, un tableau d'int en stocke beaucoup les uns à la suite des autres, chacun accessible par un indice entier.
Vous en déclarez un en donnant le type des éléments, un nom et une taille entre crochets. Ajoutez une liste entre accolades pour le remplir :
L'indexation commence à zéro : le premier élément est scores[0], et un tableau de taille 4 a des indices valides de 0 à 3. La taille doit être une constante connue à la compilation : vous ne pouvez pas écrire int n = readInput(); int a[n]; en C++ standard (c'est une extension non portable). Lorsque vous avez besoin d'une taille déterminée à l'exécution, utilisez plutôt un vector.
Initialiser des tableaux
Vous avez plusieurs façons de remplir un tableau, et quelques raccourcis bons à connaître :
Le point à bien retenir : lorsque vous fournissez moins d'initialiseurs que la taille, les restants sont initialisés par valeur (zéro pour les types numériques), et non laissés à l'état de déchets. Mais un tableau sans aucun initialiseur — int e[4]; déclaré comme variable locale — contient des valeurs indéterminées, et les lire avant de les affecter est un comportement indéfini.
Parcourir un tableau
Comme les éléments sont stockés de façon contiguë, vous parcourez un tableau avec une simple boucle indexée. Pour rester dans les bornes, pilotez la boucle avec la longueur réelle du tableau plutôt qu'un nombre écrit en dur :
sizeof(scores) est le nombre total d'octets de tout le tableau ; le diviser par sizeof(scores[0]) (la taille d'un élément) donne le nombre d'éléments. Depuis C++17, il existe une écriture plus propre, std::size(scores), qui se lit mieux et refuse de compiler si vous lui passez par erreur un pointeur. Encore plus simple lorsque vous n'avez besoin que des valeurs : un for basé sur une plage évite entièrement le calcul d'indice.
Le piège du dépassement de bornes
C++ ne fait aucune vérification de bornes sur arr[i]. Indexer au-delà du dernier élément ne lève pas d'exception et n'avertit pas : il lit ou écrit dans la mémoire qui se trouve là. C'est le bug de tableau le plus courant, et c'est un cas classique de comportement indéfini :
int a[3] = {1, 2, 3};
a[3] = 99; // OOPS - valid indices are 0..2, not 3
cout << a[5]; // garbage, crash, or corruption - undefined behavior
L'erreur de décalage d'une unité se cache souvent dans la condition d'une boucle. Écrire i <= n au lieu de i < n fait un pas de trop et touche arr[n], qui n'existe pas :
for (int i = 0; i <= n; i++) // BUG: when i == n, arr[i] is out of bounds
cout << arr[i];
La solution est la discipline de la section précédente : bouclez avec i < size, jamais avec <=, et calculez la taille à partir du tableau plutôt que de réécrire un littéral qui se désynchronise dès que vous ajoutez un élément.
La décroissance des tableaux : le pointeur caché
Le comportement de tableau le plus délicat en C++ est la décroissance : lorsque vous passez un tableau à une fonction, il se convertit silencieusement en un pointeur vers son premier élément. L'information de taille est perdue, donc sizeof à l'intérieur de la fonction mesure le pointeur, pas le tableau.
Notez que int arr[] et int* arr sont identiques en tant que paramètres de fonction — les crochets sont purement cosmétiques. Comme le nombre est perdu, vous devez passer vous-même la longueur à côté du tableau :
int sum(const int* arr, int n) {
int total = 0;
for (int i = 0; i < n; i++) total += arr[i];
return total;
}
Ce schéma « passe un pointeur et une longueur, et prie pour qu'ils correspondent » est exactement la friction qui pousse la plupart du code C++ vers std::array et std::vector, qui transportent leur propre taille et ne dégénèrent jamais.
Un mot rapide sur les tableaux multidimensionnels
Vous pouvez imbriquer les crochets pour former une grille. Un tableau 2D est en réalité un tableau de tableaux, disposé rangée par rangée en mémoire :
Indexez-le avec grid[row][col]. Les mêmes mises en garde sur les bornes et la décroissance s'appliquent — et elles empirent, car passer un tableau 2D à une fonction exige de préciser toutes les dimensions sauf la première (void f(int g[][3])). Pour tout ce qui dépasse une petite grille fixe, un vector de vectors est bien moins propice aux erreurs.
Ensuite : Vector
Les tableaux natifs sont rapides et prévisibles, mais leur taille fixe, l'absence de sécurité sur les bornes et leur décroissance en pointeur les rendent peu pratiques pour le code de tous les jours. Ensuite, nous découvrirons std::vector — un tableau redimensionnable qui grandit à la demande, mémorise sa propre taille et se branche directement sur les algorithmes de la STL, vous offrant presque tout ce que proposent les tableaux avec beaucoup moins de façons de vous tirer une balle dans le pied.
Questions fréquentes
Comment déclarer et initialiser un tableau en C++ ?
Écrivez le type des éléments, un nom et la taille entre crochets, puis éventuellement une liste entre accolades : int scores[4] = {90, 75, 100, 60};. Vous pouvez omettre la taille lorsque vous fournissez des initialiseurs : int scores[] = {90, 75, 100, 60}; laisse le compilateur les compter pour vous.
Comment obtenir la longueur d'un tableau en C++ ?
Pour un vrai tableau encore dans sa portée, utilisez std::size(arr) (C++17) ou sizeof(arr) / sizeof(arr[0]). Cela ne fonctionne pas une fois que le tableau a dégénéré en pointeur (par exemple à l'intérieur d'une fonction qui a reçu int arr[]), où sizeof renvoie la taille du pointeur, pas celle du tableau.
Que se passe-t-il si vous accédez à un tableau hors limites en C++ ?
C'est un comportement indéfini. C++ ne vérifie pas les bornes sur arr[i], donc lire ou écrire au-delà de la fin peut provoquer un plantage, renvoyer des valeurs erronées ou corrompre silencieusement la mémoire voisine. Gardez toujours votre indice dans la plage de 0 à size - 1.