Les tableaux en langage C
Un tableau est une collection d'éléments du même type stockés dans des emplacements mémoire contigus. Il est identifié par un nom et chaque élément est accessible via un indice entier.

v1, v2, v3…), gérer un grand nombre d'éléments devient rapidement ingérable. Un tableau permet de représenter n éléments sous un seul nom et de les traiter efficacement avec des boucles.1. Déclaration d'un tableau
type nom[taille]; /* taille fixe */
type nom[] = { val1, val2, ... }; /* taille déduite */
type nom[taille] = { val1, val2, ... }; /* taille + initialisation */| Forme | Exemple | Résultat |
|---|---|---|
| Taille seule | int tab[10]; | Tableau de 10 entiers, non initialisé |
| Taille variable | int n=10; int T[n]; | Tableau à taille définie à l'exécution (VLA) |
| Initialisation seule | int tab[] = {10,20,30,40}; | Taille déduite automatiquement : 4 |
| Taille + initialisation | int tab[6] = {10,20,30,40}; | 4 valeurs fournies, les 2 restantes valent 0 |
Exemple n°1 — Les trois formes de déclaration
int main(void)
{
/* Forme 1 — taille seule */
int tab[10];
/* Forme 2 — taille variable (VLA, C99) */
int n = 10;
int T[n];
/* Forme 3 — initialisation, taille déduite */
int tab2[] = {10, 20, 30, 40};
/* équivalent à : int tab2[4] = {10, 20, 30, 40} */
/* Forme 4 — taille + initialisation partielle */
int tab3[6] = {10, 20, 30, 40};
/* équivalent à : int tab3[6] = {10, 20, 30, 40, 0, 0} */
return 0;
}int tab[100] = {0}; /* tous les éléments valent 0 */
int tab[100] = {}; /* idem — valable en C99/C11 */2. Propriétés d'un tableau
a. Accès aux éléments
Les éléments sont accessibles via un indice entier compris entre 0 et taille − 1.
Exemple n°2 — Lecture et modification d'éléments
#include <stdio.h>
int main(void)
{
int tab[] = {10, 20, 30, 40};
tab[2] = 5; /* tab = {10, 20, 5, 40} */
tab[0] = 2; /* tab = {2, 20, 5, 40} */
tab[2] = tab[1]; /* tab = {2, 20, 20, 40} */
printf("%d - %d - %d - %d\n", tab[0], tab[1], tab[2], tab[3]);
return 0;
}2 - 20 - 20 - 40
b. Absence de contrôle des indices
Le C ne vérifie pas si un indice est dans les bornes du tableau. Accéder hors limites compile sans erreur mais produit un comportement indéfini à l'exécution.
Exemple n°3 — Accès hors limites
#include <stdio.h>
int main(void)
{
int tab[2];
printf("%d\n", tab[3]); /* hors limites — valeur imprévisible */
printf("%d\n", tab[-2]); /* indice négatif — comportement indéfini */
return 0;
}-434996632 32766
#define TAILLE 10
int tab[TAILLE];
int i = 12;
/* Vérification correcte avant accès */
if (i >= 0 && i < TAILLE)
printf("%d\n", tab[i]);c. Initialisation avec trop d'éléments
Exemple n°4 — Plus d'initialiseurs que la taille
#include <stdio.h>
int main(void)
{
int tab[2] = {10, 20, 30, 40, 50}; /* 5 valeurs pour 2 cases */
return 0;
}warning: excess elements in array initializer
int tab[2] = {10, 20, 30, 40, 50};
^~
1 warning generated.d. Stockage contigu en mémoire
Les éléments d'un tableau sont stockés dans des adresses consécutives. L'écart entre deux adresses successives est égal à sizeof(type).
Exemple n°5 — Adresses consécutives
#include <stdio.h>
int main(void)
{
int tab[5], i;
printf("Taille d'un int : %lu octet(s)\n", sizeof(int));
for (i = 0; i < 5; i++)
printf("Adresse tab[%d] : %p\n", i, &tab[i]);
return 0;
}Taille d'un int : 4 octet(s) Adresse tab[0] : 0x7ffee793ba00 Adresse tab[1] : 0x7ffee793ba04 (+4) Adresse tab[2] : 0x7ffee793ba08 (+4) Adresse tab[3] : 0x7ffee793ba0c (+4) Adresse tab[4] : 0x7ffee793ba10 (+4)
3. Différences entre tableau et pointeur
Bien que le nom d'un tableau se comporte souvent comme un pointeur, il existe des différences fondamentales à connaître.
| Aspect | Tableau tab[] | Pointeur *ptr |
|---|---|---|
sizeof | Taille totale du tableau (octets) | Taille du pointeur (4 ou 8 octets) |
| Affectation d'adresse | Interdit — tab = &x → erreur | Autorisé — ptr = &x |
| Arithmétique | Interdit — tab++ → erreur | Autorisé — ptr++ |
| Accès éléments | tab[i] = *(tab+i) | ptr[i] = *(ptr+i) |
| Nature | Constante (adresse fixe) | Variable (peut changer) |
a. Opérateur sizeof
Exemple n°6 — sizeof sur tableau vs pointeur
#include <stdio.h>
int main(void)
{
int tab[5] = {10, 20, 30, 40, 50};
int *ptr = tab;
printf("sizeof(tab) = %lu\n", sizeof(tab)); /* 5 × 4 = 20 octets */
printf("sizeof(ptr) = %lu\n", sizeof(ptr)); /* taille d'un pointeur = 8 */
printf("Nb éléments = %lu\n", sizeof(tab) / sizeof(tab[0])); /* 5 */
return 0;
}sizeof(tab) = 20 sizeof(ptr) = 8 Nb éléments = 5
sizeof(tab) / sizeof(tab[0]). Cette formule est plus robuste qu'une constante codée en dur car elle s'adapte automatiquement si la taille change :#define NB_ELEM(t) (sizeof(t) / sizeof((t)[0]))
int tab[] = {1, 2, 3, 4, 5};
for (int i = 0; i < NB_ELEM(tab); i++)
printf("%d ", tab[i]);b. Affectation d'adresse
Exemple n°7 — Affectation interdite sur un tableau
#include <stdio.h>
int main(void)
{
int tab[5] = {10, 20, 30, 40, 50};
int x = 5;
int *ptr = &x; /* autorisé — ptr est une variable */
tab = &x; /* erreur de compilation */
return 0;
}error: array type 'int [5]' is not assignable tab = &x; ~~~ ^
c. Arithmétique sur tableau vs pointeur
Exemple n°8 — Incrément interdit sur le nom du tableau
int main(void)
{
int a[10];
int *p = a;
p++; /* autorisé — p est un pointeur variable */
a++; /* erreur de compilation — a est constant */
return 0;
}error: cannot increment value of type 'int [10]' a++; ~^
4. Similitudes entre tableau et pointeur
a. Le nom du tableau = adresse du premier élément
Exemple n°9 — Nom du tableau utilisé comme pointeur
#include <stdio.h>
int main(void)
{
int tab[] = {10, 20, 30, 40, 50, 60};
int *ptr = tab; /* équivaut à ptr = &tab[0] */
printf("Premier élément via tab : %d\n", *tab);
printf("Premier élément via ptr : %d\n", *ptr);
printf("Même adresse ? : %d\n", tab == ptr);
return 0;
}Premier élément via tab : 10 Premier élément via ptr : 10 Même adresse ? : 1
b. Accès aux éléments — quatre notations équivalentes
Le compilateur traduit tab[i] en *(tab + i) en interne. Les quatre notations suivantes sont donc strictement équivalentes.
Exemple n°10 — Quatre façons d'accéder au même élément
#include <stdio.h>
int main(void)
{
int tab[] = {10, 20, 30, 40, 50, 60};
int *ptr = tab;
printf("tab[2] = %d\n", tab[2]); /* notation tableau classique */
printf("*(tab + 2) = %d\n", *(tab + 2)); /* arithmétique via tableau */
printf("ptr[2] = %d\n", ptr[2]); /* notation tableau via ptr */
printf("*(ptr + 2) = %d\n", *(ptr + 2)); /* arithmétique via pointeur */
return 0;
}tab[2] = 30 *(tab + 2) = 30 ptr[2] = 30 *(ptr + 2) = 30
c. Passage de tableau à une fonction
Quand un tableau est passé à une fonction, il est automatiquement converti en pointeur vers son premier élément — même si la syntaxe utilise des crochets. La fonction reçoit donc un pointeur, pas une copie du tableau.
Exemple n°11 — Passage de tableau : le paramètre devient un pointeur
#include <stdio.h>
/* "int ptr[]" et "int *ptr" sont strictement équivalents ici */
void afficher(int ptr[], int taille)
{
int i;
/* sizeof(ptr) donne la taille du POINTEUR, pas du tableau ! */
printf("sizeof(ptr) dans la fonction = %lu\n", sizeof(ptr));
for (i = 0; i < taille; i++)
printf("%d ", ptr[i]);
printf("\n");
}
int main(void)
{
int tab[] = {10, 20, 30, 40, 50, 60};
int n = sizeof(tab) / sizeof(tab[0]); /* calculé dans main */
printf("sizeof(tab) dans main = %lu\n", sizeof(tab));
afficher(tab, n);
return 0;
}sizeof(tab) dans main = 24 sizeof(ptr) dans la fonction = 8 10 20 30 40 50 60
sizeof(tableau) dans main donne la taille réelle, mais dans une fonction appelée, le tableau devient un pointeur et sizeof ne retourne que la taille du pointeur (4 ou 8 octets). Toujours passer la taille explicitement en paramètre supplémentaire.Récapitulatif
| Concept | Syntaxe / Règle | Point clé |
|---|---|---|
| Déclaration | int tab[n]; | Indices de 0 à n−1 |
| Initialisation | int tab[] = {1,2,3}; | Taille déduite automatiquement |
| Accès | tab[i] = *(tab+i) | Quatre notations équivalentes |
| Taille | sizeof(tab)/sizeof(tab[0]) | Valable uniquement dans la portée de déclaration |
| Hors bornes | Aucune vérification automatique | Comportement indéfini — vérifier manuellement |
| Nom = adresse | tab = &tab[0] | Constante — ne peut pas être modifiée |
| Passage en fonction | Converti en pointeur automatiquement | Passer la taille séparément |
Discussion (0)
Soyez le premier à laisser un commentaire !
Laisser un commentaire
Votre commentaire sera visible après modération.