Une chaîne C finit par un octet zéro
En langage C, une chaîne de caractères est un tableau d’octets qui se termine par un octet de valeur zéro. Comprendre ce zéro final explique la plupart des débordements de tampon, la première cause de failles de sécurité en C.
Un formulaire d’inscription réserve six cases pour un prénom. Un visiteur en tape sept. Le programme n’affiche aucune erreur : il écrit simplement sur la mémoire du voisin.
À la fin de cette leçon
Remarque
Je peux expliquer un tableau comme de la mémoire et une chaîne comme des octets qui finissent par zéro.
Mots-clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Tableau | des variables du même type rangées côte à côte | int t[4] |
| Indice | le numéro d’une case, qui commence à 0 | t[2] |
| Chaîne | des caractères suivis d’un octet de valeur 0 | |
| Tampon | une zone de mémoire de taille fixe qui reçoit des données | |
| Débordement | une écriture qui dépasse la fin du tampon |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Un tableau est de la mémoire contiguë
Un tableau int t[4] réserve quatre int côte à côte, donc seize octets. La case t[i] se trouve à l’adresse de départ plus i fois quatre.
C’est pourquoi les indices commencent à 0 : la case 0 est au départ même, à zéro octet de décalage. Le langage ne vérifie jamais l’indice. Écrire t[9] va à l’adresse correspondante, même si elle appartient à une autre variable.
Une chaîne se termine par l’octet zéro
Le mot « salut » compte cinq lettres, mais il occupe six octets : cinq codes de lettres puis un zéro. Ce zéro final marque la fin. La fonction strlen compte les octets jusqu’au premier zéro. L’opérateur sizeof donne la taille du tableau entier.
Mettre un zéro au milieu raccourcit la chaîne : tout ce qui suit est ignoré.
strlen, sizeof et un zéro posé au milieu
char s[] = "salut";
printf("%zu %zu\n", strlen(s), sizeof s);
s[2] = 0;
printf("%s %zu\n", s, strlen(s));Aller dans le dossier de travail
mkdir -p ~/c && cd ~/cAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire le programme dans un fichier
printf '#include <stdio.h>\n#include <string.h>\nint main(void) {\n char s[] = "salut";\n printf("%%zu %%zu\\n", strlen(s), sizeof s);\n for (int i = 0; i < (int)sizeof s; i++) printf("%%d ", s[i]);\n printf("\\n");\n s[2] = 0;\n printf("%%s %%zu\\n", s, strlen(s));\n return 0;\n}\n' > chaine.cAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Compiler et lancer le programme
gcc -Wall -o chaine chaine.c && ./chaineAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Exemple travaillé : les six octets de « salut »
| Indice | Caractère | Code affiché |
|---|---|---|
| 0 | s | 115 |
| 1 | a | 97 |
| 2 | l | 108 |
| 3 | u | 117 |
| 4 | t | 116 |
| 5 | fin de chaîne | 0 |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Pourquoi une chaîne trop longue déborde
Le tampon nom a six cases. La chaîne « bonjour » a sept lettres et son zéro : huit octets. La copie ne vérifie rien et écrit les deux derniers octets après le tampon.
Ces octets tombent sur la variable voisine, ou sur l’adresse de retour de la fonction. Ce comportement s’appelle un débordement de tampon. On ne le lance pas dans le labo : on le lit sur une table.
Huit octets dans un tampon de six
char nom[6];
strcpy(nom, "bonjour"); /* 8 octets dans 6 cases */Exemple travaillé : les octets en trop
| Case | Appartient à | Reçoit |
|---|---|---|
| nom[0] à nom[5] | Le tampon nom | b, o, n, j, o, u |
| Case suivante | Une autre variable | r, écrasé sans erreur |
| Case encore après | Une autre variable | le zéro final, écrasé sans erreur |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Erreur fréquente
Attention
Beaucoup de gens pensent qu’un tampon de six cases reçoit six lettres. Il reçoit cinq lettres et le zéro final. Comptez toujours la longueur plus un avant de copier, ou utilisez une copie qui connaît la taille du tampon.