Comment concaténer const/literal chaînes de caractères en C?
Je travaille en C, et je dois concaténer un peu les choses.
Maintenant j'ai ceci:
message = strcat("TEXT ", var);
message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar));
Maintenant, si vous avez de l'expérience en C, je suis sûr que vous vous rendez compte que cela vous donne une erreur de segmentation lorsque vous essayez d'exécuter. Alors, comment puis-je contourner cela?
- Je voudrais suggérer que vous utilisez strlcat au lieu de strcat! gratisoft.us/todd/papers/strlcpy.html
- Je voudrais repeart Cette suggestion. Strcat causes de la vulnérabilité de débordement de la mémoire tampon exploits. Quelqu'un peut donner à votre programme de données qui en est la cause pour exécuter du code arbitraire.
Vous devez vous connecter pour publier un commentaire.
En C, "chaînes" sont tout simplement
char
tableaux. Par conséquent, vous ne pouvez pas directement enchaîner avec d'autres "chaînes".Vous pouvez utiliser le
strcat
fonction, ce qui ajoute la chaîne pointée parsrc
à la fin de la chaîne pointée pardest
:Voici un exemple de cplusplus.com:
Pour le premier paramètre, vous devez fournir le tampon de destination lui-même. Le tampon de destination doit être un char tableau tampon. E. g.:
char buffer[1024];
Assurez-vous que que le premier paramètre a suffisamment d'espace pour stocker ce que vous essayez de copier en elle. S'il est disponible pour vous, il est plus sûr d'utiliser des fonctions comme:
strcpy_s
etstrcat_s
où vous explicitement spécifier la taille de la mémoire tampon de destination.Note: Une chaîne de caractères littérale ne peut pas être utilisé comme un tampon, puisque c'est une constante. Ainsi, vous disposez toujours d'allouer un tableau de char pour le tampon.
La valeur de retour de
strcat
peut être simplement ignoré, il ne fait que retourner le pointeur de même qu'a été passé en premier argument. Il est là pour des raisons de commodité, et vous permet de chaîner les appels en une seule ligne de code:De sorte que votre problème pourrait être résolu comme suit:
strcat
plusieurs fois!strcat
doit vérifier tous les précédents octets (recherche de la'\0'
), vous avez déjà concaténées. C'est inutile de traitement.const char *str = "these" "strings" "are" "concatenated";
.Éviter d'utiliser
strcat
dans le code C. Le plus propre et, surtout, de la façon la plus sûre est d'utilisersnprintf
:Certains intervenants ont soulevé une question que le nombre d'arguments peuvent ne pas correspondre à la chaîne de format et le code de la compilation, mais la plupart des compilateurs déjà émettre un avertissement si c'est le cas.
snprintf()
est un GROS no-no.str1
str2
devrait avoir? Puis-je utiliserstd::string
ou seulementchar*
est-elle autorisée?char*
.sizeof(x)
etsizeof x
. La mise entre parenthèses de la notation fonctionne toujours et sans parenthèse notation ne fonctionne que parfois, il faut donc toujours utiliser la mise entre parenthèses de la notation; c'est une règle simple à retenir et qu'il est sécuritaire. Cela nous mène à un religieux de l'argument — j'ai été impliqué dans les discussions avec ceux qui l'objet avant, mais la simplicité de toujours utiliser des parenthèses' l'emporte sur tout le mérite de ne pas les utiliser (IMNSHO, bien sûr). C'est présenté pour l'équilibre.Des gens, l'utilisation strncpy(), strncat(), ou snprintf().
Dépassement de votre espace de mémoire tampon sera corbeille quel que soit le reste en mémoire!
(Et n'oubliez pas de laisser un espace pour le traîner nul '\0' personnage!)
strncpy()
. C'est pas un "plus sûr" de la version destrcpy()
. La cible tableau de caractères peut être inutilement collier supplémentaire'\0'
caractères, ou pire, il peut être laissé indéterminé (c'est à dire, pas une chaîne de caractères). (Il a été conçu pour une utilisation avec une structure de données qui est rarement utilisé de plus, un tableau de caractères rembourré à la fin avec zéro, un ou plusieurs'\0'
caractères.)strncpy
etstrncat
cen
est le nombre maximum de caractères à copier, pas de la taille de la cible de la mémoire tampon. Ce et la non-terminaison de chaînes en cas de troncature, et les différentes troncature de la manipulation sur les différentes plateformes, il est dangereux de trop. Veuillez considérerstrlcpy
etstrlcat
. Voir aussi mon petit article sur ce sujet: gergap.wordpress.com/2013/04/05/...Aussi malloc et realloc sont utiles si vous ne savez pas à l'avance combien de chaînes sont concaténées.
num_words>INT_MAX
, peut-être que vous devriez utilisersize_t
pouri
Les chaînes peuvent aussi être concaténés au moment de la compilation.
Ne pas oublier d'initialiser la mémoire tampon de sortie. Le premier argument de strcat doit être une chaîne terminée par null avec suffisamment d'espace supplémentaire alloué pour la suite de la chaîne:
Le premier argument de strcat() doit être en mesure de conserver suffisamment d'espace pour la chaîne concaténée. Donc allouer un tampon avec suffisamment d'espace pour recevoir le résultat.
strcat() permet de concaténer le deuxième argument avec le premier argument, et stocker le résultat dans le premier argument, le retour char* est, tout simplement, ce premier argument, et uniquement pour votre commodité.
Vous n'obtenez pas une nouvelle chaîne alloué par la première et la deuxième argument concaténés, qui je pense vous prévu sur la base de votre code.
Que des personnes ont souligné la manipulation des chaînes de beaucoup d'améliorations. De sorte que vous pouvez apprendre comment utiliser le C++ de la bibliothèque string au lieu de C-style chaînes. Cependant voici une solution en pur C
Je ne suis pas sûr de savoir si c'est correct/safe mais pour l'instant, je ne pouvais pas trouver une meilleure façon de le faire dans la norme ANSI C.
<string.h>
est de style C++. Vous souhaitez"string.h"
. Vous aussi calculerstrlen(s1)
deux fois, ce qui n'est pas nécessaire.s3
devrait êtretotalLenght+1
de long.#include <string.h>
est correcte C. Utiliser des crochets pour le standard et système d'en-têtes (y compris<string.h>
), des guillemets pour les en-têtes qui font partie de votre programme. (#include "string.h"
va se passer si vous ne disposez pas de votre propre en-tête de fichier de ce nom, mais l'utilisation<string.h>
de toute façon.)strcat
plutôt questrncat
, puisque vous avez déjà garanti que la cible est assez grand.-1
dans un+1
. (Cette réponse a été "inspiré" par une discussion sur le C vs C++ manipulation des chaînes en C++ de la salle de chat. Je pense que, Nils, qui avec cette débâcle, vous avez démontré l'efficacité de vos adversaires POV.:^>
)Meilleure façon de le faire sans avoir un limitées taille de la mémoire tampon est par l'utilisation de asprintf()
char *
, pasconst char *
. La valeur de retour devra être transmis àfree
.asprintf
n'est qu'une extension GNU.C'est un comportement indéterminé pour tenter de modifier les littéraux de chaîne, qui est ce que quelque chose comme:
va tenter de faire. Il va essayer de virer de bord sur le
name
chaîne à la fin de la chaîne littérale"Hello, "
, ce qui n'est pas bien défini.Essayer quelque chose de cela. Il réalise ce qui vous semble être d'essayer de faire:
Cela crée une zone tampon qui est autorisé à être modifiée et puis d'exemplaires à la fois la chaîne de caractères littérale et d'autres du texte. Juste être prudent avec les débordements de tampon. Si vous contrôlez les données d'entrée (ou de la vérifier avant de la main), c'est bien d'utiliser fixe la longueur des tampons, comme je l'ai.
Sinon, vous devez utiliser des stratégies d'atténuation comme l'allocation de suffisamment de mémoire dans le tas pour vous assurer que vous pouvez le manipuler. En d'autres termes, quelque chose comme:
Vous pouvez écrire votre propre fonction qui fait la même chose que
strcat()
mais ça ne change rien:Si les deux chaînes sont plus de 1000 caractères, il s'agit de couper la chaîne à 1000 caractères. Vous pouvez modifier la valeur de
MAX_STRING_LENGTH
pour répondre à vos besoins.strlen(str1) + strlen(str2)
, mais vous écrivezstrlen(str1) + strlen(str2) + 1
caractères. Alors pouvez-vous vraiment écrire votre propre fonction?return buffer; free(buffer);
sizeof(char) == 1
(en plus il y a d'autres plus subtiles erreurs ...) voyez-vous maintenant pourquoi vous n'avez pas à écrire votre propre fonction ?free(buffer);
.char* mycat = strcat_const("Hello ","world"); free(mycat);
Il y a une différence, n'est-ce pas ?printf("%s",strcat_const("Hello ","world"));
et puis libérer la mémoire, donc si vous mettez plus de après que, dans lemain()
fonction, il vous permettra de libérer de la mémoire avant. Dites-moi si je me trompe.free(buffer);
aprèsreturn buffer;
n'est jamais exécutée, le voir dans un débogueur 😉 je vois maintenant: oui, vous avez pour libérer de la mémoire dans lamain
fonctionstrlen(str1) >= MAX_STRING_LENGTH
?buffer[strlen(buffer)] = '\0';
Est là quelque chose d'étrange dans cette ligne ? Devinez comment strlen fonctionne 😉 ! Je serai de retour le lundi, bon week-end!MAX_STRING_LENGTH
en tant que paramètre àstrcat_const
(avec un autre nom, bien sûr).buffer
variable n'est définie qu'à l'intérieur destrcat_const
). Je pense que vous devriez rester avec l'allocation dynamique de la solutionEn supposant que vous avez un char[fixed_size] plutôt qu'un char*, vous pouvez utiliser un seul, de création de macro pour le faire tout à la fois avec
<<cout<<like
de la commande ("plutôt %s disjoints %s\n", "que", "printf format de style"). Si vous travaillez avec des systèmes embarqués, cette méthode vous permettra également de laisser de côté les malloc et le grand*printf
famille de fonctions commesnprintf()
(Cela empêche dietlibc de se plaindre de *printf trop)Vous essayez de copier une chaîne dans une adresse qui est allouée statiquement. Vous avez besoin d'un chat dans une mémoire tampon.
Spécifiquement:
...snip...
destination
...snip...
http://www.cplusplus.com/reference/clibrary/cstring/strcat.html
Il y a un exemple ici.
Si vous avez de l'expérience en C, vous remarquerez que les chaînes ne sont que des tableaux de char où le dernier caractère est un caractère null.
Maintenant que c'est assez gênant comme vous l'avez trouver le dernier caractère dans le but d'ajouter quelque chose.
strcat
le fera pour vous.Donc strcat de recherches par l'intermédiaire du premier argument par un caractère nul. Puis il va le remplacer par le deuxième argument du contenu (jusqu'à ce que se termine par un nul).
Maintenant, nous allons passer par votre code:
Ici vous ajouter quelque chose pour le pointeur sur le texte "TEXTE" (le type de "TEXTE" est const char*. Un pointeur.).
Que ne fera pas le travail. Modifier également le "TEXTE" tableau ne fonctionnera pas comme il est habituellement placé dans un souci constant de segment.
Qui pourrait mieux fonctionner, sauf que vous êtes à nouveau essayer de modifier les textes statiques. strcat est de ne pas allouer de mémoire pour le résultat.
Je souhaiterais vous proposer de faire quelque chose comme ceci à la place:
Lire la documentation de
sprintf
pour vérifier les options.Et maintenant un point important:
S'assurer que le tampon a suffisamment d'espace pour contenir le texte ET le caractère null. Il ya un couple de fonctions qui peuvent vous aider, par exemple, strncat et des versions spéciales de printf qui allouer de la mémoire tampon pour vous.
Ne s'assurant pas de la taille de la mémoire tampon va entraîner une corruption de la mémoire et exploitable à distance de bugs.
"TEXT"
estchar[5]
, pasconst char*
. Il se désintègre àchar*
dans la plupart des contextes. Pour des raisons de compatibilité descendante, les littéraux de chaîne ne sont pasconst
, mais de tenter de modifier les résultats dans un comportement indéfini. (En C++, les littéraux de chaîne sontconst
.)C'était ma solution
mais vous avez besoin de spécifier le nombre de chaînes que vous allez pour concaténer
Essayer quelque chose de similaire à ceci: