Je vais coacher une équipe ACM le mois prochain (aller à la figure), et le temps est venu de parler de chaînes de C. Outre une discussion sur la norme Lib, Connaissez-vous de toutes les listes (comme des feuilles de triche) ou votre propre expérience dans la matière? P>
Je suis déjà au courant des livres pour la compétition ACM (qui sont bons, voir en particulier Ce ), mais je suis après des tours du commerce. p>
merci. p>
Strcpy code>, STRCMP code>, etc., je voudrais leur donner des indices (quelque chose comme STR [0] est équivalent à * STR code> et des choses comme ça). P>
16 Réponses :
Les fonctions suivantes peuvent être utilisées pour implémenter une non-mutation Le premier trouve le premier caractère dans l'ensemble des délimiteurs que vous passez . Le second découvre le premier caractère i préférez-les à strutok code>: STRPBRK code> car ils renvoient la longueur de la chaîne s'ils ne peuvent pas correspondre. p> p>
Il est évident mais je pense qu'il est important de savoir que les chaînes sont rien b> plus qu'un tableau d'octets, délimité par un octet zéro.
C Strings ne sont pas tous les conviviaux que vous le savez probablement.
if( strncmp( s1, s2, BUFFER_SIZE ) == 0 )
doStuff(s1);
Si vous utilisez vraiment Printf et non une macro enrçonneuse qui fait des choses supplémentaires, les puts / fput sont les fonctions que vous recherchez.
Est strlcpy () standard c? Il est probablement important de savoir que pour une compétition. Sinon, soyez prêt à l'écrire. De plus, Strcpy, etc. est en sécurité si vous pouvez prouver que la destination est suffisamment longue.
Je suis personnellement friand d'utiliser Strncpy, suivi d'écrire une nul à la fin de la matrice de destination. De cette façon, je sais que cela n'a pas été écrasé, et je sais que cela s'est arrêté. Puisque Strlcpy n'est pas (à ma connaissance) encore une norme, je n'aime pas compter sur elle quand je rebondis entre des environnements.
@David Thorley: Strlcpy n'est en effet pas standard et ce drapper idiot refuse de le mettre dans GLIBC. Mais il s'avère vraiment génial, car le Strlcpy que j'ai écrit est plus rapide que Strcpy. Je n'aime pas Strncpy car il écrase toute la matrice, au lieu de quelle taille je donne.
Notez que vous ne pouvez pas utiliser en toute sécurité strncat () code> sauf si vous pouvez utiliser en toute sécurité memmove () code> ou memcpy () code>. En particulier, STRNCAT (cible, source, taille de taille (cible) code> est incorrect à moins que vous sachiez que * cible == '\ 0' code>. En utilisant strncat () code> est généralement une erreur.
nb p>
Ceci n'est pas spécifique aux chaînes, mais cela fonctionne également pour les tableaux C P> str [0] code> est équivalent à 0 [str] code>, ou plus généralement str [i] code> est i [str ] code> et i [str] code> est * (str + i) code>. p>.
Je ne trouve pas cela incroyablement important, cependant.
Des choses telles que 3 ["Hello"] CODE> Equivalent to "Bonjour" [3] CODE>, tandis que c'est vrai, ne sont vraiment pas originaires de banlieue que personne n'a jamais utilisé.
C'est tout parce que l'addition est commutative. x [y] est * (x + y) et y [x] est * (y + x)
Le Par exemple: de la documentation de MSDN sur La fonction Strncpy copie la
Nombre initial Caractères de Strsource
à la stradest et retourne la Strdest. str code> n code> strong> * code> Variantes dans stdlib Ne pas nécessairement NULL Terminez la chaîne de destination < / fort>. p>
Strncpy code>: p>
En fait, ce n'est pas la famille STRN * complète, seulement Strncpy. Strncat a également eu ses propres problèmes. Néanmoins, écrire le NULL ne ferait pas nécessairement rendre votre programme plus sûr. Et si vous souhaitez transférer le contenu des données de fichier / etc / passwd-archives / publics, mais vos données sont tronquées par Strncpy to / etc / passwd?
Oui, le problème général de l'utilisation de chaînes en toute sécurité dans un environnement de mémoire dynamique non géré est lui-même une thèse de maîtrise en soi. En supposant que vous voulez toujours le faire :)
Une alternative plus utile est strtok code> n'est pas Safe Safe Strong>, car il utilise un tampon privé mutable mutable strong> pour stocker des données entre les appels; Vous ne pouvez pas interlaisser ou annexe strutok code> également. p>
strtok_r code>, l'utiliser quand vous pouvez strong>. p>.
strtok est une fonction de l'enfer. jetonner une chaîne comme celle-ci "asdf" , "FDSA" avec, comme délimiteur, vous obtient 2 résultats au lieu de 5
strtok_r () peut ne pas être disponible dans le concours. Cependant, évitez Strtok () si vous le pouvez.
Vous pouvez mentionner l'adressage indexé. P>
Une adresse d'éléments est l'adresse de base + Index * Taille de l'élément P>
Vous devriez clarifier: dans les tableaux et les pointeurs C, * Tailleof (élément) code> est effectué pour vous par le compilateur, et l'ensemble généré reflétera le facteur Taillef (élément) code>. Mais qu'est-ce que cela a à voir avec des chaînes? Tailleof (Char) == 1 code>
Juste parce que le compilateur le fait pour vous et la taille d'un caractère ne signifie pas que la mise en œuvre n'est pas importante.
Tailleof (Char) Code> ne "i> arrive i> doit être 1 - il est spécifié dans la norme.
Vous avez raison, personne ne devrait jamais connaître ces informations car les caractères sont un octet.
Je ne dis pas que cela n'a pas d'importance, je dis que cela n'a rien à voir avec des cordes.
Une erreur commune est la suivante: Il fonctionne jusqu'à ce que vous utilisiez jusqu'à avec Char * P Vous allouez de l'espace pour contenir un pointeur ( Tailleof (p) code> octets .. Alors que les choses drôles se produisent (bienvenue dans la jungle) . P> Tailleof (VOID *) CODE> BYTES) sur la pile. La bonne chose ici est d'allouer un tampon ou de spécifier simplement la taille du pointeur au moment de la compilation: p>
Votre premier exemple ne doit jamais fonctionner, même si vous utilisez moins de Tailleof (* p) code> octets, car snprintf code> ne copiera pas une chaîne dans le pointeur, mais la mémoire qui Le pointeur pointe vers i>. A char * p code> n'est pas identique à un charp [] code>. Dans votre deuxième exemple, * p code> est superflu, car buf code> pourrait être transmis à snaprintf code> directement pour rendre le code plus clair.
L'ancien exemple fonctionne, essayez-le avec un compilateur :) dans ce dernier, je sais que * p code> est superflu mais cela servira à propos de montrer "Comment allouer la mémoire"
Il fonctionne car * p code>, lors de la déclaration, contient une valeur aléatoire et indique donc à un segment de mémoire aléatoire pouvant être écritable, vous donnant ainsi l'illusion qu'il fonctionne lors de la rédaction de petites quantités de texte à cela, et pourquoi cela se casse lorsque vous essayez d'écrire trop.
En outre, je viens de l'essayer sur mon compilateur. Premier exemple: erreur bus code>. (GCC 4.0, OS X léopard)
Vous pouvez essayer avec un plus ancien compilateur sur une université plus ancienne, probablement MacOS Randomise Segments pour minimiser les mauvaises choses comme les débordements tampons, etc.
Des choses telles que "Works sur votre machine" ou "Vous pouvez le faire fonctionner sur une université plus ancienne" ne signifie pas que c'est correct. Votre code est un comportement indéfini conformément à la norme C, ce qui signifie qu'il pourrait fonctionner, il pourrait s'écraser ou effacer votre disque dur. C'est ce que c'est un comportement indéfini.
confondre strlen () code> avec Tailleof () code> Lorsque vous utilisez une chaîne: char *p = "hello!!";
strlen(p) != sizeof(p)
J'ai trouvé que la technique vs p> voir https://stackoverflow.com/questions/295027 p> Voir le lien pour les implications et les variations p> p> Char Buff [0] code> a été incroyablement utile.
Considérons:
Je signalerais les pièges de performance de sur-dépendance sur les fonctions de chaîne intégrées.
char* triple(char* source)
{
int n=strlen(source);
char* dest=malloc(n*3+1);
strcpy(dest,src);
strcat(dest,src);
strcat(dest,src);
return dest;
}
... avec les pièges d'optimisation prématurée? :-)
Je discuterais quand et quand ne pas utiliser strcpy code> et strncpy code> et que peut aller mal: if (stricmp("StrInG 1", "string 1")==0)
{
.
.
.
}
stricmp () code> n'est pas une fonction standard ANSI C, il s'agit d'une extension fournie par MS VC ++ et peut-être d'autres implémentations. Dans GCC, la fonction s'appelle strcasecmpmp () code> (probablement la fois que je vais réellement avec Microsoft sur quelque chose), mais n'est toujours pas standard.
Peut-être que vous pourriez illustrer la valeur de Sentinel '\ 0' avec l'exemple suivant p>
char * a = "bonjour \ 0 monde"; char b [100]; Strcpy (B, A); printf (b); p>
J'ai eu une fois que mes doigts brûlaient quand dans mon zèle, j'ai utilisé Strcpy () pour copier des données binaires. Cela a fonctionné la plupart du temps mais a échoué mystérieusement parfois. Le mystère a été révélé lorsque j'ai réalisé que l'entrée binaire contenait parfois un octet zéro et Strcpy () se terminerait là-bas. P>
Vos doigts guérissent-ils? Snark> Code>
Oh c'était il y a longtemps ... Depuis lors, j'ai même grandi de nouveaux ;-)
Abuser Strlen () aggravera considérablement la performance.
int length = strlen( string );
for( int i = 0; i < length; i++ ) {
processChar( string[i] );
}
Mais le compilateur peut-il optimiser cela et n'accumule-t-il que vraiment la fonction strallen () code> une fois?
@jaska peut-être que ce sera peut-être peut-être pas - dépend de nombreux facteurs. La norme ne nécessite certainement pas l'optimisation de l'optimisation et il n'interdit ni une telle optimisation.
Les pointeurs et les tableaux, tout en ayant la syntaxe similaire, ne sont pas du tout de même. Donné: p>
Char A [100]; char * p = a; p>
Pour le tableau, A, il n'y a pas de pointeur stocké nulle part. Tailleof (a)! = Tailleof (P), pour la matrice, il s'agit de la taille du bloc de la mémoire, pour le pointeur, c'est la taille du pointeur. Cela devient important si vous utilisez quelque chose comme: Tailleof (A) / Tailleof (A [0]). De plus, vous ne pouvez pas ++ A, et vous pouvez rendre le pointeur A 'const' pointeur des caractères «const», mais le tableau ne peut être que des caractères «const», auquel cas vous seriez l'introduction en premier. c etcc etc p>
Si possible, utilisez strlcpy (au lieu de Strncpy) et strlcat.
Mieux encore mieux, pour rendre la vie un peu plus sûre, vous pouvez utiliser une macro comme: p>
#define strlcpy_sz(dst, src) (strlcpy(dst, src, sizeof(dst)))
KMM a déjà une bonne liste. Voici les choses que j'ai eu des problèmes avec quand j'ai commencé à coder c. P>
Les littéraux de chaîne ont une propre section de mémoire et sont toujours accessibles. Par conséquent, ils peuvent par exemple être une valeur de retour de la fonction. P> li>
Gestion de la mémoire des chaînes, en particulier avec une bibliothèque de haut niveau (non libc). Qui est responsable de libérer la chaîne s'il est renvoyé par fonction ou transmis à une fonction? P> li>
Quand faut-il "Const Char *" et quand "Char *" être utilisé. Et qu'est-ce que cela me dit si une fonction renvoie un "const char *". P> li> ol>
Toutes ces questions ne sont pas trop difficiles à apprendre, mais difficiles à comprendre si vous ne vous en avez pas appris. P>
N'ayez pas à l'esprit que les littéraux de chaîne sont Const Char *, et il est un comportement indéfini si vous essayez de les changer.
Amende. Le titre a été changé.
* STR n'est pas équivalent à STR [0]. Alors, commencez avec ça.
@Hooked: Comment pas?
A [i] code> est équivalent à* (A + i) code>, SignificationA [0] code> est équivalent à* (A + 0) code>, qui est à son tour équivalent à* A code>.A [0] renvoie une référence de direction. * STR DÉRÉERFERENCES UN POINTAIRE (C'est pourquoi cela s'appelle l'indirection). Deux choses différentes.
Mes compétences Google ne trouvent aucune utilisation de la phrase «référence de la direction» par rapport à C. L'équivalence des tableaux et des pointeurs en C que j'ai illustré précédemment est assez connu - c'est même sur la page Wikipedia - donc je ne peux vraiment pas déterminez ce que vous essayez de dire.
@Accroché. Votre commentaire est faux factuellement. Cela vous dérangerait-il de la supprimer, alors cela ne confond pas d'autres personnes?
Err, référence directe. Qui est factuellement correct. A [0] renvoie toujours une référence, c'est pourquoi cela peut être un lvalue. Je comprends que les pointeurs et les tableaux sont étroitement liés (en particulier pour les CStrings), mais * STR renvoie une référence à la notice, et un [0] renvoie toujours une référence au premier élément. Qui est factuellement correct.
Est le premier élément de
A code> jamais différent de l'élément à quela code> pointe-t-il? Sinon, on dirait que vous venez de dire qu'ils sont les mêmes.@Hooked: A [0] retourne toujours un lvalue (je ne sais pas tout à fait ce que vous entendez par référence ici) où A est pointé. * A retourne toujours un lvalu sur lequel A est pointé. Lisez l'excellent commentaire de Chuck montrant pourquoi ils sont la même chose.