Menu

Les fonctions de chaînes en C : strlen, strcpy, strcat, strcmp et les autres

Un tour pratique de <string.h> : mesurer avec strlen, copier avec strcpy et strncpy, joindre avec strcat, comparer avec strcmp, chercher avec strchr et strstr - et comment dimensionner les tampons pour qu'aucune ne déborde.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

Chaque fonction de <string.h> est une petite boucle sur un tableau de char qui s'arrête au terminateur nul. Une fois cela clair, la bibliothèque cesse de ressembler à une liste de noms cryptiques et commence à ressembler à la poignée de boucles que vous auriez écrites vous-même. Cette page couvre celles qui portent presque tout le travail réel - et les règles de dimensionnement qui les empêchent d'écrire au-delà de vos tampons.

Tout ici demande une inclusion :

#include <string.h>

strlen : combien de caractères

strlen compte les octets jusqu'au terminateur, exclu. Elle renvoie un size_t, affichez-le donc avec %zu.

strlen vaut 6 ; sizeof vaut 32. Le premier est le texte, le second le stockage - voir les chaînes pour comprendre pourquoi cette distinction compte tant.

strlen parcourt toute la chaîne à chaque appel, ne la mettez donc pas dans une condition de boucle sur la même chaîne inchangée :

/* recompte toute la chaine a chaque iteration */
for (size_t i = 0; i < strlen(s); i++) { ... }

/* compter une fois */
size_t n = strlen(s);
for (size_t i = 0; i < n; i++) { ... }

strcpy et strncpy : copier

strcpy(dst, src) copie les caractères plus le terminateur. Elle n'a aucune idée de la taille de dst, donc l'appelant doit garantir que dst contient au moins strlen(src) + 1 octets.

strncpy prend un compte maximal, mais elle a un piège célèbre : quand la source fait au moins n octets, elle copie exactement n caractères et aucun terminateur. Terminez toujours vous-même :

Le sizeof dst - 1 plus le terminateur explicite est le motif à mémoriser. (strncpy complète aussi les sources courtes avec des zéros jusqu'à n octets, ce qui est du travail gaspillé pour de gros tampons - elle a été conçue pour des enregistrements à largeur fixe, pas pour la sûreté.)

strcat et strncat : joindre

strcat(dst, src) ajoute src à la fin de ce qui se trouve déjà dans dst. La destination doit contenir les deux chaînes plus un terminateur, et elle doit déjà contenir une chaîne valide - ajouter à de la mémoire non initialisée est un comportement indéfini.

Notez char path[64] = "/home/ada"; plutôt que char path[64]; - c'est l'initialiseur qui en fait une chaîne valide pour le premier strcat.

strncat(dst, src, n) ajoute au plus n caractères et ajoute toujours un terminateur, donc n est l'espace restant, pas la taille totale du tampon :

strncat(dst, src, sizeof dst - strlen(dst) - 1);

Des appels strcat répétés rebalaient la destination pour en trouver la fin à chaque fois. Construire une longue chaîne dans une boucle ainsi est quadratique ; pour quoi que ce soit de conséquent, suivez votre propre position d'écriture ou utilisez snprintf, couvert dans conversion de chaînes.

strcmp : comparer

== compare des adresses, il est donc faux pour deux tableaux distincts contenant le même texte. strcmp compare les caractères et renvoie le signe de la différence.

Trois règles :

  • Testez strcmp(a, b) == 0 pour l'égalité. Écrire if (strcmp(a, b)) signifie « si elles diffèrent », ce qui se lit à l'envers pour presque tout le monde.
  • Seul le signe est défini. Ne comparez pas le résultat à 1 ou -1.
  • L'ordre se fait par valeur d'octet, donc "Zebra" se classe avant "apple" en ASCII. Pour une comparaison insensible à la casse, passez d'abord les deux copies en minuscules - le strcasecmp souvent rencontré est une extension POSIX, pas du C standard.

strncmp(a, b, n) ne compare que les n premiers caractères, c'est la façon propre de tester un préfixe :

strchr et strstr : chercher

strchr(s, ch) trouve la première occurrence d'un caractère ; strrchr trouve la dernière. strstr(haystack, needle) trouve une sous-chaîne. Toutes trois renvoient un pointeur dans la chaîne d'origine, ou NULL s'il n'y a aucune correspondance.

Soustraire le pointeur renvoyé du début donne l'indice ; son type est ptrdiff_t, affiché avec %td. Comme le résultat pointe à l'intérieur du tableau d'origine, at + 1 est le reste de la chaîne sans aucune copie - un idiome C très courant.

Vérifiez toujours NULL avant de déréférencer. strchr(email, '@') + 1 sur une chaîne sans @ calcule une adresse depuis NULL et le programme n'est plus défini.

Découper une chaîne

Il n'y a pas de fonction de découpage, mais strchr plus un terminateur font le travail sur place. Cet exemple coupe une adresse e-mail en utilisateur et domaine :

memcpy copie un nombre exact d'octets sans se soucier des terminateurs, ce que vous voulez quand vous connaissez déjà la longueur. Le terminateur est ensuite écrit à la main.

Un exemple complet : normaliser un nom

En réunissant le tour - nettoyer, comparer, copier et joindre :

Chaque écriture est bornée par le sizeof propre à la destination, et chaque strncpy est suivi d'un terminateur explicite. Cette discipline, appliquée avec constance, est ce qui rend sûr le code C manipulant des chaînes.

Les règles de dimensionnement à garder

  • strcpy a besoin de strlen(src) + 1 octets libres dans la destination.
  • strcat a besoin de strlen(dst) + strlen(src) + 1.
  • Après strncpy, écrivez dst[n - 1] = '\0' vous-même.
  • Pour strncat, le compte est l'espace restant : sizeof dst - strlen(dst) - 1.
  • Vérifiez strchr et strstr contre NULL avant d'utiliser le résultat.
  • N'utilisez sizeof dst que quand dst est un vrai tableau. Dans une fonction prenant char *dst, sizeof donne la taille du pointeur - passez la longueur du tampon en paramètre séparé.

Questions fréquentes

Que renvoie strcmp en C ?

Zéro quand les deux chaînes sont identiques, une valeur négative quand la première se classe avant la seconde, et une valeur positive quand elle se classe après. Seul le signe a un sens - ne supposez jamais qu'elle renvoie -1 ou 1. Le test que vous voulez est presque toujours if (strcmp(a, b) == 0).

Pourquoi ne peut-on pas comparer des chaînes avec == en C ?

a == b compare les deux adresses, pas les caractères. Deux tableaux distincts contenant « chat » vivent à des adresses différentes, donc la comparaison est fausse même si le texte correspond. Utilisez strcmp(a, b) == 0 de <string.h>.

Quelle est la différence entre strcpy et strncpy ?

strcpy copie jusqu'au '\0' de la source sans aucune idée de la taille de la destination. strncpy s'arrête après au plus n octets - mais si la source est aussi longue, elle ne copie aucun terminateur, vous devez donc écrire dst[n - 1] = '\0'; vous-même. Aucune des deux n'est automatiquement sûre ; la discipline de taille vous revient.

Comment trouver une sous-chaîne en C ?

strstr(haystack, needle) renvoie un pointeur sur la première occurrence, ou NULL s'il n'y en a aucune. Comme elle renvoie un pointeur dans la chaîne d'origine, found - haystack vous donne l'indice. Utilisez strchr quand vous cherchez un caractère isolé.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER