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) == 0pour l'égalité. Écrireif (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 à
1ou-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 - lestrcasecmpsouvent 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
strcpya besoin destrlen(src) + 1octets libres dans la destination.strcata besoin destrlen(dst) + strlen(src) + 1.- Après
strncpy, écrivezdst[n - 1] = '\0'vous-même. - Pour
strncat, le compte est l'espace restant :sizeof dst - strlen(dst) - 1. - Vérifiez
strchretstrstrcontreNULLavant d'utiliser le résultat. - N'utilisez
sizeof dstque quanddstest un vrai tableau. Dans une fonction prenantchar *dst,sizeofdonne 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é.