Strings Aren't Real C String Tutorial (2027 Edition)

Cette vidéo démontre comment créer un type string_slice en C pour remplacer les chaînes C traditionnelles terminées par \\\\0, en utilisant une structure avec un pointeur et une longueur explicite, ce qui élimine les bugs liés au null terminator et permet des opérations de sous-c...

Voir la source

SYNTHÈSE STRUCTURÉE

Le problème fondamental des chaînes C

L’intervenant explique que les chaînes en C ne sont pas un vrai type : « Strings in C literally aren’t real. They are a social construct. » Un char * n’est qu’un pointeur vers un caractère, soit un entier représentant une adresse mémoire. Le null terminator (\0) invisible à la fin de chaque chaîne est la source de la plupart des bugs. La preuve : sizeof(s) sur un char * retourne 8 octets (taille du pointeur sur une machine 64 bits), pas la longueur du texte. De plus, tenter de modifier une chaîne littérale en place (ex. s[4] = '\0') provoque un segfault car elle est en lecture seule.

Création du type string_slice

Pour résoudre ces problèmes, l’intervenant définit une structure avec deux champs :

  • data : un char * pointant vers les caractères
  • len : un size_t contenant la longueur explicite
#include <stddef.h>

typedef struct {
    char *data;
    size_t len;
} string_slice;

Cette approche permet de connaître la longueur sans parcourir la chaîne à chaque fois, contrairement à strlen() qui est en O(n).

Fonctions utilitaires de base

Trois fonctions sont créées pour manipuler les slices :

Affichage : print_slice() utilise putchar() en boucle sur s.len caractères, évitant le null terminator.

Conversion depuis une chaîne C : slice_from_cstr() initialise data avec le pointeur et len avec strlen().

Comparaison : slice_eq() compare d’abord les longueurs (retour immédiat si différentes), puis les caractères un par un.

Opérations de sous-chaîne sans allocation

Les fonctions slice_take() et slice_drop() sont révolutionnaires car elles ne copient rien :

string_slice slice_take(string_slice s, size_t n) {
    if (n > s.len) n = s.len;
    return (string_slice){s.data, n};
}

string_slice slice_drop(string_slice s, size_t n) {
    if (n > s.len) n = s.len;
    return (string_slice){s.data + n, s.len - n};
}

L’intervenant souligne : « This is impossible to do with C strings by the way. No malloc, no memcopy, no copying of anything here. Just doing a little bit of pointer math. » Les sous-chaînes partagent la même mémoire que l’originale.

Découpage et nettoyage avancés

Trim : slice_trim() supprime les espaces en début et fin en combinant slice_drop() et slice_take(). Attention : isspace() nécessite un cast en unsigned char pour éviter un comportement indéfini sur les caractères négatifs.

Split : slice_split() retourne le segment avant un délimiteur et modifie la slice originale pour pointer après celui-ci. Cette fonction modifie le slice passé par pointeur, permettant une itération simple.

Application concrète : parser /etc/fstab

L’intervenant utilise les slices pour analyser le fichier de montage Linux. Le code :

  1. Ouvre le fichier avec fopen()
  2. Lit chaque ligne avec fgets() dans un buffer de 512 octets
  3. Convertit la ligne en slice et la trimme
  4. Ignore les lignes vides et les commentaires (commençant par #)
  5. Découpe chaque ligne sur les espaces avec slice_split()
  6. Affiche les champs alignés avec leurs en-têtes

Le résultat est un affichage propre et structuré du fichier fstab, démontrant la puissance de l’approche.

CONCEPTS CLÉS

  • Null terminator : Caractère \0 marquant la fin d’une chaîne C, source de bugs de dépassement et d’inefficacité.
  • String slice : Structure contenant un pointeur et une longueur, permettant des opérations sans copie mémoire.
  • Segfault : Erreur de segmentation due à un accès mémoire invalide, fréquent avec les chaînes C modifiées en place.
  • Pointer arithmetic : Technique consistant à décaler un pointeur d’un certain nombre d’éléments (ex. s.data + n pour avancer de n caractères).
  • isspace() : Fonction de ctype.h qui détecte les espaces, nécessitant un cast en unsigned char pour éviter les valeurs négatives.

CONCLUSION

L’approche string_slice transforme la gestion des chaînes en C en éliminant le null terminator et en rendant les opérations de sous-chaîne gratuites (sans allocation). Comme le dit l’intervenant : « We can literally make that problem evaporate simply because our strings know about their length. » Cette technique est particulièrement utile pour le parsing de fichiers, où les découpages et les comparaisons sont fréquents. Le message principal : en C, la connaissance explicite de la longueur d’une chaîne est plus fiable et plus performante que la convention du \0.

Du même canal

Tout voir