Comment faire pour convertir un std::string const char* ou char*?
Comment puis-je convertir un std::string
à un char*
ou un const char*
?
- Au lieu de: char * writable = new char[str.size() + 1]; Vous pouvez utiliser char inscriptible[str.size() + 1]; Alors vous n'avez pas besoin de s'inquiéter à propos de la suppression écriture ou la gestion des exceptions.
- Vous ne pouvez pas utiliser str.size (), sauf si la taille est connue à la compilation, il peut aussi débordement de la pile si la taille fixe de la valeur est énorme.
- char* result = strcpy((char*)malloc(str.length()+1), str.c_str());
strcpy
etmalloc
ne sont pas vraiment le C++ façon.- vous voulez dire qu'ils sont imaginaires?
- Non, mais
char* dest = new char[str.length() + 1]; std::copy(str.begin(), str.end(), dest)
serait plus idiomatiques C++.strcpy()
etmalloc()
ne sont pas mauvais ou problématiques, mais il semble incohérent d'utiliser une chaîne C++ et C installations de la bibliothèque C++ d'équivalents dans le même bloc de code. stringName.c_str()
tant que c'est unstd::string
,std::wstring
, ou quelque chose comme unwinrt::hstring
.
Vous devez vous connecter pour publier un commentaire.
Si vous voulez juste passer un
std::string
à une fonction qui doitconst char*
vous pouvez utiliserSi vous souhaitez obtenir une copie accessible en écriture, comme
char *
, vous pouvez le faire avec cette:Modifier: à noter que le ci-dessus n'est pas une exception coffre-fort. Si quoi que ce soit entre les
new
appel et ladelete
appel jette, vous aurez une fuite de mémoire, que rien ne va appelerdelete
automatiquement pour vous. Il y a deux façons de résoudre ce problème.boost::scoped_array
boost::scoped_array
va supprimer de la mémoire pour vous au moment d'aller hors de portée:std::vector
C'est la manière standard (ne nécessite aucune bibliothèque externe). Vous utilisez
std::vector
, qui gère complètement la mémoire pour vous.vector<char> writable(str.c_str(), str.size() + 1);
à l'aide?char &operator[]
: c'est précisé et garanti de comportement.char *p = const_cast<char*>(str.c_str())
une option (même mauvaise)?new char[..]
déclaration. Je soupçonne que beaucoup de gens il suffit de copier/coller le code de l'échantillon, sans lire le texte d'accompagnement.std::copy
quand j'ai le temps de faire de jolies code. N'oublions pas qu'il y a une différence (même s'il est peu probable que l'un avec de vraies cordes, mais qui sait ce qu'il va stocker). Lestd::copy
copie incorporé des octets nuls aswell, jusqu'à la fin de lastd::string
.std::copy(str.begin(), str.end(), writable); writable[str.size()] = '\0';
, pourquoi ne pas simplement utiliserstd::copy(str.begin(),str.end() + 1,writable);
?end() + 1
, pas tellement sur le terminateur null (je ne suis pas un expert de la bibliothèque, mais je ne pense pas que tout le populaire implémentations de la bibliothèque autour d'aujourd'hui ontstd::string
sans une fuite\0
). Dans les versions debug, certaines implémentations de la bibliothèque ont des récipients où.end()
renvoie un objet de classe qui jette/core dumps.end() + 1
. Donc je ferais mieux d'être prudent et d'écrire un code que je sais avec certitude fonctionne 🙂.end()
serait de retour d'un pointeur-taille int, ou quelque chose de similaire.strcpy()
oustrdup()
peut échouer si lestd::string
contient des caractères null.boost::scoped_array<char>
, on peut aussi utiliserstd::unique_ptr<char[]>
de la STL:std::unique_ptr<char[]> writable(new char[str.size() + 1]);
. Il libère également le tableau à l'aide dedelete[]
quand elle est hors de portée.std::string::data()
maintenant, retourne unCharT*
au lieu d'unconst CharT*
. Il pourrait être une bonne idée de mettre à jour cette réponse 🙂data
ou&s[0]
ont été fixés pour les trois libéré versions linguistiques maintenant, tout cela semble trop compliqué. Même si la chaîne estconst
, une simple copie de celui-ci devrait être suffisant.Donné le dire...
L'obtention d'un `char *` ou de `const char*` d'une `chaîne`
Comment obtenir un pointeur de caractère valide alors que
x
reste dans la portée et n'est pas modifiéC++11 simplifie les choses; dans les cas suivants donnent tous accès à la même chaîne de la mémoire tampon:
Tous les pointeurs tiendra le même valeur - l'adresse du premier caractère dans la mémoire tampon. Même une chaîne vide est un "premier caractère dans la mémoire tampon", parce que le C++11 garantit de toujours garder un extra NUL/0 caractère de terminaison après explicitement attribué chaîne de contenu (par exemple,
std::string("this\0that", 9)
aura un tampon holding"this\0that\0"
).Compte tenu de tout ce qui précède pointeurs:
Seulement pour les non-
const
pointeurp_writable_data
et de&x[0]
:L'écriture d'un NUL ailleurs dans la chaîne de ne pas changer le
string
'ssize()
;string
's sont autorisés à contenir n'importe quel nombre de NULs - ils ne sont pas un traitement spécial, parstd::string
(même en C++03).Dans C++03, les choses étaient beaucoup plus compliquées (les principales différences mis en évidence):
x.data()
const char*
de la chaîne de la mémoire tampon interne qui n'était pas requis par la Norme de conclure avec un NUL (c'est à dire peut-être['h', 'e', 'l', 'l', 'o']
suivie par non initialisée ou de déchets de valeurs, avec accidentelle accède à y avoir comportement indéfini).x.size()
personnages sont sûrs à lire, c'est à direx[0]
parx[x.size() - 1]
&x[0]
f(const char* p, size_t n) { if (n == 0) return; ...whatever... }
vous ne devez pas appelerf(&x[0], x.size());
quandx.empty()
- il suffit d'utiliserf(x.data(), ...)
.x.data()
mais:const
x
cela aboutit à un non-const
char*
pointeur; vous pouvez remplacer la chaîne de contenux.c_str()
const char*
à un ASCIIZ (NUL-fin) la représentation de la valeur (c'est à dire ['h', 'e', 'l', 'l', 'o', '\0']).x.data()
et&x[0]
x.size()
+ 1 caractères sont sûrs à lire.Conséquences de l'accès, en dehors des indices
N'importe quelle manière que vous obtenez un pointeur, vous ne devez pas accéder à la mémoire, plus loin le long du pointeur que les personnages de la garantie présents dans les descriptions ci-dessus. Tentatives n'ont comportement indéfini, avec une chance très réelle de l'application se bloque et les ordures résultats, même pour les lectures, et de plus gros, de données, de corruption de la pile et/ou des failles de sécurité pour les écritures.
Moment ces pointeurs invalidé?
Si vous appelez
string
fonction membre qui modifie lastring
ou se réserve en outre la capacité, toutes les valeurs de pointeur retourné à l'avance par l'une des méthodes ci-dessus sont invalidé. Vous pouvez utiliser ces méthodes pour obtenir un autre pointeur. (Les règles sont les mêmes que pour les itérateurs enstring
s).Voir aussi Comment obtenir un pointeur de caractère valide même après
x
champ d'application de feuilles ou est modifiée ci-dessous....Donc, ce qui est mieux à utiliser?
À partir de C++11, utiliser
.c_str()
pour ASCIIZ de données, et.data()
pour "binaire" des données (expliqué ci-dessous).En C++03, utilisez
.c_str()
moins certain que.data()
est adéquate, et préférez.data()
sur&x[0]
comme il est sans danger pour les cordes à vide.......essayer de comprendre le programme à utiliser
data()
le cas échéant, ou vous aurez probablement faire d'autres erreurs...Le code ASCII du caractère NUL '\0' caractère garanti par
.c_str()
est utilisé par de nombreuses fonctions comme une sentinelle de la valeur indiquant la fin de coffre-fort-à-l'accès aux données. Cela s'applique à la fois en C++des fonctions comme le disentfstream::fstream(const char* filename, ...)
et partagé avec les fonctions C commestrchr()
, etprintf()
.Donné C++03 du
.c_str()
's garanties sur le retour de la mémoire tampon sont un super-ensemble de.data()
's, vous pouvez toujours l'utiliser en toute sécurité.c_str()
, mais parfois les gens ne le font pas car:.data()
communique à d'autres programmeurs lisant le code source que les données n'est pas ASCIIZ (plutôt, vous utilisez la chaîne pour stocker un bloc de données (qui parfois n'est même pas vraiment textuel)), ou que vous êtes de passage à une autre fonction qui le traite comme un bloc de "binaire" des données. Cela peut être une idée cruciale de veiller à ce que d'autres programmeurs modifications du code de continuer à traiter les données correctement.string
mise en œuvre aurez besoin de faire quelques extra allocation de mémoire et/ou de copie de données dans le but de préparer le NUL résilié tamponComme un autre indice, si une fonction des paramètres d'exiger de l' (
const
)char*
mais de ne pas insister sur l'obtention dex.size()
, la fonction probablement besoin d'un ASCIIZ d'entrée, de sorte.c_str()
est un bon choix (la fonction a besoin de savoir où le texte se termine en quelque sorte, donc, si ce n'est pas un paramètre individuel, il ne peut être qu'une convention comme une longueur de préfixe ou de sentinelle ou de certains fixe la durée prévue).Comment obtenir un pointeur de caractère valide même après
x
champ d'application de feuilles ou est modifiéeVous aurez besoin de copie le contenu de la
string
x
à une nouvelle zone de mémoire à l'extérieurx
. Cette mémoire tampon peut être dans de nombreux endroits comme un autrestring
ou tableau de caractères de la variable, il peut ou peut ne pas avoir une autre vie quex
en raison d'être dans un autre champ (par exemple, l'espace de noms global, statique, de segment de mémoire partagée, fichier mappé en mémoire).Pour copier le texte à partir de
std::string x
d'autonomie d'un tableau de caractères:D'autres raisons de vouloir un
char*
ouconst char*
généré à partir d'unstring
Donc, ci-dessus, vous avez vu comment obtenir une (
const
)char*
, et comment faire pour faire une copie du texte indépendant de l'originalstring
, mais que pouvez-vous ne avec elle? Aléatoire d'une poignée d'exemples...string
s'du texte, comme dansprintf("x is '%s'", x.c_str());
x
s'du texte à un tampon spécifié par votre fonction de l'appelant (par exemplestrncpy(callers_buffer, callers_buffer_size, x.c_str())
), et la volatilité de la mémoire utilisée pour les e/S de périphérique (par exemple,for (const char* p = x.c_str(); *p; ++p) *p_device = *p;
)x
s'du texte à un tableau de caractères contenant déjà quelques ASCIIZ du texte (par exemplestrcat(other_buffer, x.c_str())
) - attention à ne pas provoquer un dépassement de la mémoire tampon (dans de nombreux cas, vous pouvez avoir besoin d'utiliserstrncat
)const char*
ouchar*
à partir d'une fonction (peut-être pour des raisons historiques - client à l'aide de votre API existantes - ou pour C compatibilité, vous ne voulez pas retourner unstd::string
, mais ne voulez copier votrestring
de données de l'quelque part pour l'appelant)string
variable à laquelle le pointeur de relever a gauche de la portéestd::string
implémentations (par exemple STLport et le compilateur natif) peut transmettre des données comme ASCIIZ pour éviter les conflitsUtiliser le
.c_str()
méthode pourconst char *
.Vous pouvez utiliser
&mystring[0]
pour obtenir unchar *
pointeur, mais il ya un couple de gotcha: vous n'aurez pas nécessairement obtenir un zéro chaîne terminée, et vous ne serez pas en mesure de changer la chaîne de la taille. Vous devez être prudent de ne pas ajouter des personnages après la fin de la chaîne ou vous aurez un dépassement de la mémoire tampon (et probable crash).Il n'y a aucune garantie que tous les personnages feraient partie de la même contiguë de la mémoire tampon jusqu'à ce que le C++11, mais dans la pratique, connues de tous les implémentations de
std::string
travaillé de cette façon toute façon; voir N' “&s[0]” point de caractères contigus dans une std::string?.Noter que de nombreux
string
fonctions de membre va réallouer de la mémoire tampon interne et de l'invalider tous les pointeurs vous ont peut-être sauvé. Mieux les utiliser immédiatement et puis jetez-la.C++17
C++17 (norme à venir) modifie le synopsis du modèle
basic_string
l'ajout d'un non const surcharge dedata()
:CharT const *
destd::basic_string<CharT>
CharT *
destd::basic_string<CharT>
C++11
CharT const *
destd::basic_string<CharT>
CharT *
destd::basic_string<CharT>
À partir de C++11, la norme dit:
Il y a séparable des moyens possibles pour obtenir un non const pointeur de caractère.
1. Utiliser la zone de stockage de C++11
Pro
Contre
'\0'
ne sera pas modifié /ne faisant pas nécessairement partie de la non-const de la mémoire.2. Utilisation
std::vector<CharT>
Pro
Contre
3. Utilisation
std::array<CharT, N>
siN
est compiler constante de temps (et d'assez petite taille)Pro
Contre
4. Brut de l'allocation de mémoire avec stockage automatique de suppression
Pro
Contre
5. Brut de l'allocation de mémoire avec la manutention manuelle
Pro
Con
Je travaille avec une API avec beaucoup de fonctions comme un entrée d'un
char*
.J'ai créé une petite classe pour faire face à ce genre de problème, j'ai mis en œuvre l'idiome RAII.
Et vous pouvez l'utiliser comme:
J'ai appelé la classe
DeepString
parce que c'est la création d'un profond et unique exemplaire (leDeepString
n'est pas copiable) d'une chaîne existante.c_str()
utilisé parstd
est une abréviation pour "C-string" pas "const string" etstr()
retourne toujours unestd::basic_string
, paschar*
(par exemplestd::stringstream::str()
)Viens de voir ceci :
Cependant , notez qu'il sera de retour un
const char *
.Pour unchar *
, utilisezstrcpy
pour le copier dans un autrechar
tableau.Essayer cette