Les chaînes de caractères en langage C
En C, il n'existe pas de type string natif. Une chaîne de caractères est représentée comme un tableau de char terminé par le caractère spécial '\0' (caractère nul), qui marque la fin de la chaîne.
char dont le dernier élément est obligatoirement le caractère nul '\0' (code ASCII 0). C'est ce terminateur qui distingue une chaîne d'un simple tableau de caractères et qui permet aux fonctions standard de connaître la fin de la chaîne.Ainsi, la chaîne "Meknes" occupe 7 octets en mémoire : 6 caractères + 1 terminateur '\0'.
| Case | [0] | [1] | [2] | [3] | [4] | [5] | [6] |
|---|---|---|---|---|---|---|---|
| Caractère | 'M' | 'e' | 'k' | 'n' | 'e' | 's' | '\0' |
1. Déclarer une chaîne
char nom_chaine[taille];'\0' Pour stocker une chaîne de n caractères, il faut déclarer un tableau de taille n + 1afin de laisser de la place au terminateur :char ville[7]; /* peut stocker "Meknes" (6 car.) + '\0' */2. Initialiser une chaîne
Il existe quatre façons équivalentes d'initialiser une chaîne en C.
| Forme | Code | Remarque |
|---|---|---|
| Littéral, taille déduite | char ville[] = "Meknes"; | Taille = 7 (6 + '\0') — recommandée |
| Littéral, taille fixe | char ville[20] = "Meknes"; | Cases [7]…[19] remplies de '\0' |
| Caractère par caractère | char ville[] = {'M','e','k','n','e','s','\0'}; | '\0' explicite obligatoire |
| Caractère par caractère, taille fixe | char ville[20] = {'M','e','k','n','e','s','\0'}; | Reste des cases initialisées à '\0' |
Exemple n°1 — Déclaration, initialisation et affichage
#include <stdio.h>
int main(void)
{
char ville[] = "Meknes";
printf("Chaîne : %s\n", ville);
printf("Longueur : %lu\n", sizeof(ville) - 1); /* -1 pour exclure '\0' */
printf("Taille : %lu\n", sizeof(ville)); /* inclut '\0' */
return 0;
}Chaîne : Meknes Longueur : 6 Taille : 7
3. Afficher et lire une chaîne
a. printf / scanf
C dispose du spécificateur %s qui permet d'afficher et de lire une chaîne entière en une seule instruction.
Exemple n°2 — Affichage avec printf
#include <stdio.h>
int main(void)
{
char ville[] = "Meknes";
printf("%s\n", ville);
return 0;
}Meknes
Exemple n°3 — Lecture avec scanf
#include <stdio.h>
int main(void)
{
char ville[20];
scanf("%s", ville); /* pas de & car "ville" est déjà une adresse */
printf("%s\n", ville);
return 0;
}& devant ville dans scanf ? Le nom d'un tableau est déjà une adresse (celle du premier élément). Écrire ville dans scanf fournit directement &ville[0] — ajouter & serait redondant.scanf("%s", …) scanf avec %s s'arrête au premier espace. Pour lire une phrase complète (avec espaces), utiliser fgets() à la place.4. Chaînes et pointeurs de caractères
Une chaîne peut aussi être manipulée via un pointeur char *. Le comportement diffère selon la zone mémoire utilisée.
| Déclaration | Zone mémoire | Modifiable ? | Utilisable hors portée ? |
|---|---|---|---|
char *p = "Meknes"; | Segment de données (lecture seule) | Non — erreur de segmentation | Oui — reste après fin de fonction |
char t[] = "Meknes"; | Pile (stack) | Oui | Non — libérée après fin de fonction |
malloc(sizeof(char)*n) | Tas (heap) | Oui | Oui — jusqu'à free() |
a. Chaîne en lecture seule (segment partagé)
Exemple n°4 — Modification interdite d'un littéral
#include <stdio.h>
int main(void)
{
char *ville = "Meknes"; /* stockée en lecture seule */
*(ville + 1) = 'n'; /* tentative d'écriture — erreur */
return 0;
}Bus error: 10
char * char *ville = "Meknes" pointe vers un littéral stocké en mémoire lecture seule. Toute tentative de modification provoque une erreur fatale (bus error ou segmentation fault). Utiliser char ville[] pour une chaîne modifiable, ou déclarer le pointeur constpour indiquer l'intention :const char *ville = "Meknes"; /* intention claire : lecture seule */b. Chaîne modifiable (tableau)
Exemple n°5 — Modification autorisée sur char[]
#include <stdio.h>
int main(void)
{
char ville[] = "Meknes"; /* copie sur la pile — modifiable */
*(ville + 1) = 'n'; /* autorisé */
puts(ville);
return 0;
}Mnknes
c. Chaîne allouée dynamiquement (malloc)
Exemple n°6 — Allocation sur le tas avec malloc
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int taille = 7;
char *ville = (char *)malloc(sizeof(char) * taille);
if (ville == NULL) { fprintf(stderr, "Allocation échouée\n"); return 1; }
*(ville + 0) = 'M';
*(ville + 1) = 'e';
*(ville + 2) = 'k';
*(ville + 3) = 'n';
*(ville + 4) = 'e';
*(ville + 5) = 's';
*(ville + 6) = '\0';
puts(ville);
free(ville); /* libération obligatoire */
return 0;
}Meknes
strdup pour dupliquer une chaîne sur le tas Au lieu d'allouer manuellement octet par octet, la fonction strdup(POSIX) crée automatiquement une copie allouée dynamiquement :#include <string.h>
char *copie = strdup("Meknes"); /* alloue + copie en une ligne */
free(copie);5. Retourner une chaîne depuis une fonction
Le segment mémoire utilisé détermine si une chaîne retournée par une fonction est valide ou non.
Exemple n°7 — Retour valide : pointeur vers littéral (segment partagé)
#include <stdio.h>
char *getVille()
{
char *ville = "Meknes"; /* segment partagé — persiste après retour */
return ville;
}
int main(void)
{
printf("%s\n", getVille());
return 0;
}Meknes
Exemple n°8 — Retour invalide : adresse d'un tableau local (pile)
#include <stdio.h>
char *getVille()
{
char ville[] = "Meknes"; /* sur la pile — libérée après retour ! */
return ville; /* retourne une adresse invalide */
}
int main(void)
{
printf("%s\n", getVille());
return 0;
}warning: address of stack memory associated with local variable 'ville' returned return ville; ^~~~~
const char *), ou d'allouer avec malloc et de laisser l'appelant libérer la mémoire.6. Passer une chaîne en paramètre
Comme une chaîne est un tableau, elle est automatiquement convertie en pointeur lors du passage à une fonction.
Exemple n°9 — Passage de chaîne à une fonction
#include <stdio.h>
#include <string.h>
/* Les deux signatures sont équivalentes */
void afficher(char str[]) /* ou : void afficher(char *str) */
{
printf("Ville : %s (longueur : %lu)\n", str, strlen(str));
}
int main(void)
{
char ville[20];
printf("Entrer une ville : ");
scanf("%s", ville);
afficher(ville);
return 0;
}strlen vs sizeof Dans une fonction, sizeof(str) donne la taille du pointeur (8 octets), non la longueur de la chaîne. Utiliser strlen(str) (de string.h) pour obtenir le nombre de caractères hors '\0'.7. puts() vs printf() pour l'affichage
| Fonction | Syntaxe | Saut de ligne | Interprète % ? | Cas d'usage |
|---|---|---|---|---|
printf("%s", s) | printf(format, …) | Non | Oui | Affichage formaté |
puts(s) | puts(chaine) | Oui (automatique) | Non | Affichage simple, plus sûr |
fputs(s, stdout) | fputs(chaine, flux) | Non | Non | Affichage sans saut de ligne |
Exemple n°10 — puts : chaque appel ajoute un saut de ligne
#include <stdio.h>
int main(void)
{
puts("Sedoki "); /* affiche "Sedoki " puis '\n' */
puts("Mostafa"); /* affiche "Mostafa" puis '\n' */
return 0;
}Sedoki Mostafa
Exemple n°11 — fputs : sans saut de ligne automatique
#include <stdio.h>
int main(void)
{
fputs("Sedoki ", stdout);
fputs("Mostafa", stdout);
printf("\n");
return 0;
}Sedoki Mostafa
printf(str) avec une chaîne utilisateur Passer directement une chaîne en premier argument de printf est une faille de sécurité connue (format string attack). Si la chaîne contient %s, %d… le comportement est indéfini :/* Incorrect — faille de sécurité */
printf(str);
/* Correct — toujours spécifier le format */
printf("%s", str);Exemple n°12 — printf interprète le % dans la chaîne
#include <stdio.h>
int main(void)
{
printf("Sedokimo%stafa"); /* % interprété comme format — warning */
return 0;
}warning: more '%' conversions than data arguments [-Wformat]
Exemple n°13 — puts affiche le % tel quel
#include <stdio.h>
int main(void)
{
puts("Sedokimo%stafa"); /* % n'est pas interprété */
return 0;
}Sedokimo%stafa
8. Lire une chaîne avec espaces : fgets et gets
scanf("%s", …) s'arrête au premier espace. Pour lire une ligne complète contenant des espaces, deux fonctions sont disponibles — avec des niveaux de sécurité très différents.
| Fonction | Syntaxe | Limite de taille | Sécurité | Recommandation |
|---|---|---|---|---|
fgets | fgets(buf, n, stdin) | Oui — lit au plus n−1 caractères | Sûre | À utiliser |
gets | gets(buf) | Non — aucune limite | Dangereuse | À éviter — supprimée en C11 |
a. fgets() — lecture sécurisée
fgets Cchar *fgets(char *buf, int n, FILE *flux);
/* Lit au plus n-1 caractères depuis flux (stdin, fichier…)
S'arrête à '\n', à EOF, ou après n-1 caractères
Ajoute automatiquement '\0' en fin de chaîne */Exemple n°14 — fgets avec limite de taille
#include <stdio.h>
#define MAX 15
int main(void)
{
char buf[MAX];
printf("Entrer une phrase : ");
fgets(buf, MAX, stdin);
printf("Chaîne lue : %s\n", buf);
return 0;
}Entrer une phrase : mostafa est un professeur d'informatique Chaîne lue : mostafa est un
fgets conserve le '\n' Contrairement à gets, fgets inclut le caractère '\n'final dans la chaîne lue. Pour le supprimer :#include <string.h>
buf[strcspn(buf, "\n")] = '\0'; /* supprime le '\n' s'il est présent */b. gets() — à éviter absolument
Exemple n°15 — gets : débordement de tampon
#include <stdio.h>
#define MAX 6
int main(void)
{
char buf[MAX];
printf("Saisir une chaîne : ");
gets(buf); /* dangereux — aucune limite de taille ! */
printf("Chaîne : %s\n", buf);
return 0;
}warning: this program uses gets(), which is unsafe. Saisir une chaîne : mostafa est un professeur Chaîne : mostafa est un professeur Segmentation fault: 11
gets() supprimée en C11 gets() n'effectue aucune vérification de taille. Une saisie plus longue que le buffer écrase d'autres zones mémoire — c'est une faille de type buffer overflow, responsable de nombreuses failles de sécurité historiques. La fonction a été retirée du standard C11. Toujours utiliser fgets(buf, taille, stdin) à la place.Récapitulatif
| Opération | Fonction / Syntaxe | Point clé |
|---|---|---|
| Déclaration | char s[n]; | Prévoir n = longueur + 1 pour '\0' |
| Initialisation | char s[] = "texte"; | Forme la plus concise — recommandée |
| Affichage | printf("%s", s) / puts(s) | puts ajoute '\n' ; préférer printf("%s", s) |
| Lecture sans espace | scanf("%s", s) | S'arrête au premier espace — pas de & |
| Lecture avec espaces | fgets(s, n, stdin) | Sûre — limite la saisie à n−1 caractères |
| Longueur | strlen(s) | Hors '\0' — nécessite string.h |
Pointeur const | const char *s = "texte"; | Lecture seule — modification interdite |
| Retour de fonction | malloc ou littéral const char * | Ne jamais retourner l'adresse d'un tableau local |
Discussion (0)
Soyez le premier à laisser un commentaire !
Laisser un commentaire
Votre commentaire sera visible après modération.