Comment puis-je convertir un std::string
en un char*
ou un const char*
?
Réponses
Trop de publicités?Si vous voulez juste passer un std::string
à une fonction qui a besoin d' const char*
vous pouvez utiliser
std::string str;
const char * c = str.c_str();
Si vous souhaitez obtenir une copie accessible en écriture, comme char *
, vous pouvez le faire avec ceci:
std::string str;
char * writable = new char[str.size() + 1];
std::copy(str.begin(), str.end(), writable);
writable[str.size()] = '\0'; // don't forget the terminating 0
// don't forget to free the string after finished using it
delete[] writable;
Edit: à noter que le ci-dessus n'est pas une exception coffre-fort. Si quoi que ce soit entre le nouvel appel et de le supprimer appel jette, vous aurez une fuite de mémoire, que rien ne va appeler delete automatiquement pour vous. Il y a deux façons de résoudre ce problème.
boost::scoped_array
boost::scoped_array
effacera de la mémoire pour vous au moment de sortir de la portée:
std::string str;
boost::scoped_array<char> writable(new char[str.size() + 1]);
std::copy(str.begin(), str.end(), writable.get());
writable[str.size()] = '\0'; // don't forget the terminating 0
// get the char* using writable.get()
// memory is automatically freed if the smart pointer goes
// out of scope
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.
std::string str;
std::vector<char> writable(str.begin(), str.end());
writable.push_back('\0');
// get the char* using &writable[0] or &*writable.begin()
Compte tenu de dire...
std::string x = "hello";
L'obtention d'un `char *` ou de `const char*` d'un `string`
Comment obtenir un pointeur de caractère valide alors qu' x
reste dans la portée et n'est pas modifié
Utiliser:
-
x.c_str()
- les retours
const char*
pour un ASCIIZ (NUL-fin) la représentation de la valeur (c'est à dire ['h', 'e', 'l', 'l', 'o', '\0']). -
x.size()
+ 1 caractères sont sûrs à lire. - garanti sans danger même pour les cordes à vide (['\0']).
- les retours
-
x.data()
- les retours
const char*
de la chaîne de la mémoire tampon qui n'est pas la promesse de conclure avec un NUL (c'est à dire ['h', 'e', 'l', 'l', 'o']). -
x.size()
personnages sont sûrs à lire. - pour les cordes à vide, vous avez la garantie de certains pointeur non NULL pour qui 0 peut être ajouté sans risque, mais vous ne devriez pas déréférencer le pointeur.
- les retours
-
&x[0]
- comme par
x.data()
mais les rendements potentiellement non-constchar*
pointeur -
x.size()
personnages sont sûrs à lire, et à écrire six
n'a pas étéconst
- l'écriture d'un NUL, ne change pas l'
string
s'size()
;string
s'sont autorisés à contenir n'importe quel nombre de NULs, ils n'ont pas de traitement spécial, enstd::string
.
- l'écriture d'un NUL, ne change pas l'
- pour les cordes à vide, ce qui a un comportement indéterminé(21.3.4)
- par exemple, avec
f(const char* p, size_t n) { if (n == 0) return; ...whatever... }
vous ne devez pas appeler à l'f(&x[0], x.size());
lorsquex.empty()
-f(x.data(), ...)
.
- par exemple, avec
- comme par
Si vous appelez string
fonction membre qui modifie l' string
ou de réserves de capacité, de toutes les valeurs de pointeur retourné à l'avance par l'une des méthodes ci-dessus sont invalidées. Vous pouvez utiliser ces méthodes pour obtenir un autre pointeur. (Les règles sont les mêmes que pour les itérateurs en string
s).
Quel que soit votre utilisation, 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 pas défini de comportement, avec un très-réelle chance de l'application se bloque, 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.
Astuce: utilisez .c_str()
moins que certain qu' .data()
est suffisante.
...mais essayer de comprendre le programme, assez pour 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 l' .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, disons, fstream::fstream(const char* filename, ...)
et partagé avec les fonctions C comme strchr()
, et printf()
.
Compte tenu de .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:
- il ya une petite chance que votre
string
mise en oeuvre devra faire quelques extra allocation de mémoire et/ou de copie de données dans le but de préparer le NUL résilié tampon (conseil: méfiez-vous prématuré d'optimisation) - à l'aide de
.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.
Une autre astuce, si une fonction des paramètres d'exiger de l' (const
) char*
mais de ne pas insister sur l'obtention x.size()
, la fonction probablement besoin .c_str()
(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 l' x
champ d'application de feuilles ou est modifiée
Vous aurez besoin de copier le contenu de l' string
x
d'une nouvelle zone de mémoire à l'extérieur x
. Cette mémoire tampon peut être dans de nombreux endroits comme un autre string
ou tableau de caractères de la variable, il peut ou peut ne pas avoir une autre vie que x
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 d' std::string x
dans un indepedent tableau de caractères:
// UTILISATION D'UNE AUTRE CHAÎNE AUTOMATIQUE DE GESTION DE LA MÉMOIRE, À L'EXCEPTION DE SÉCURITÉ std::string old_x = x; // - old_x ne sera pas affectée par les modifications de x... / / - , vous pouvez utiliser `&old_x[0]` pour obtenir une écriture char* old_x du contenu textuel / / - , vous pouvez utiliser redimensionner() pour réduire/développer la chaîne // - le redimensionnement n'est pas possible depuis l'intérieur d'une fonction réussi que le char* adresse std::string old_x = x.c_str(); // old_x prendra fin au début si x intègre NUL // Copie ASCIIZ de données, mais pourrait être moins efficace qu'il doit scan de la mémoire à // trouver le NUL de terminaison indiquant la longueur de la chaîne avant la répartition de ce montant // de la mémoire à copier dans, ou plus efficace si elle se retrouve allocation/copie d'un // beaucoup moins de contenu. // Exemple, x == "ab\0cd" -> old_x == "ab". // UTILISATION D'UN VECTEUR DE CHAR - AUTOMATIQUE, À L'EXCEPTION COFFRE-FORT, D'INDICES SUR LE CONTENU BINAIRE GARANTI CONTIGU MÊME EN C++03 std::vector old_x(x.de données(), x.size()); // sans NUL std::vector old_x(x.c_str(), x.size() + 1); // avec le NUL // UTILISATION de la PILE OÙ la TAILLE MAXIMALE DE x EST CONNU POUR ÊTRE CONSTANTE à la COMPILATION "N" // (un peu dangereux, comme "connu" les choses sont parfois mal et deviennent souvent mal) char y[N + 1]; strcpy(y, x.c_str()); // UTILISATION de la PILE OÙ INATTENDUE de LONG x EST TRONQUÉE (par exemple: Hello\0->Hel\0) char y[N + 1]; strncpy(y, x.c_str(), N); // copie au plus N, zéro-padding si courte y[N] = '\0'; // s'assurer que NUL résilié // UTILISATION de LA PILE DE la POIGNÉE x DE l'INCONNU (MAIS SAIN d'esprit) de LONGUEUR char* y = alloca(x.size() + 1); strcpy(y, x.c_str()); // UTILISATION de LA PILE DE la POIGNÉE de x DE LONGUEUR INCONNUE (NON-STANDARD GCC EXTENSION) char y[x.size() + 1]; strcpy(y, x.c_str()); // À l'AIDE de new/delete SEGMENT de MÉMOIRE, MANUEL DEALLOC, PAS INHÉRENT à l'EXCEPTION de SÉCURITÉ char* y = new char[x.size() + 1]; strcpy(y, x.c_str()); // ou comme un one-liner: char* y = strcpy(new char[x.size() + 1], x.c_str()); // utilisation d'y... delete[] y; // assurez-vous pas de pause, de retour, de jeter ou de branchement contourne ce // À l'AIDE de new/delete SEGMENT de MÉMOIRE, POINTEUR INTELLIGENT de LIBÉRATION de la mémoire, à l'EXCEPTION de SÉCURITÉ voir boost shared_array utilisation de Johannes Schaub réponse // À l'AIDE de malloc/free SEGMENT de MÉMOIRE, MANUEL DEALLOC, PAS INHÉRENT à l'EXCEPTION de SÉCURITÉ char* y = strdup(x.c_str()); // utilisation d'y... gratuit(y);
D'autres raisons de vouloir un `char*` ou de `const char*` généré à partir d'une "chaîne"
Donc, ci-dessus, vous avez vu comment obtenir une (const
) char*
, et comment faire pour faire une copie du texte indépendant de l'original string
, mais que pouvez-vous faire avec ça? Aléatoire d'une poignée d'exemples...
- donner "C" code d'accès pour le C++
string
s'du texte, comme enprintf("x is '%s'", x.c_str());
- copiez
x
s'du texte à un tampon spécifié par votre fonction de l'appelant (par exemple,strncpy(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;
) - ajouter
x
s'du texte à un tableau de caractères contenant déjà quelques ASCIIZ texte (par exemple,strcat(other_buffer, x.c_str())
) - attention à ne pas provoquer un dépassement de la mémoire tampon (dans de nombreux cas, vous devez utiliserstrncat
) - de retour d'un
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
's de données quelque part pour l'appelant)- soyez prudent de ne pas retourner un pointeur qui peut être déréférencé par l'appelant après, une
string
variable à laquelle le pointeur de relever a gauche de la portée - certains projets avec des objets partagés compilé/lien pour les différents
std::string
des implémentations (par exemple STLport et le compilateur natif) peut transmettre des données comme ASCIIZ pour éviter les conflits
- soyez prudent de ne pas retourner un pointeur qui peut être déréférencé par l'appelant après, une
Utiliser l' .c_str()
méthode de const char *
.
Vous pouvez utiliser &mystring[0]
pour obtenir un char *
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 l' std::string
a travaillé de cette façon toute façon; voir "&s[0]" point de caractères contigus dans une std::string?.
Notez que de nombreux string
membre les fonctions de 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.
Je travaille avec une API avec beaucoup de fonctions en entrée comme un caractère *.
J'ai créé une petite classe pour faire face à ce genre de problème, j'ai mis en place l'idiome RAII.
class DeepString
{
DeepString(const DeepString& other);
DeepString& operator=(const DeepString& other);
char* internal_;
public:
explicit DeepString( const string& toCopy):
internal_(new char[toCopy.size()+1])
{
strcpy(internal_,toCopy.c_str());
}
~DeepString() { delete[] internal_; }
char* str() const { return internal_; }
const char* c_str() const { return internal_; }
};
Et vous pouvez l'utiliser comme:
void aFunctionAPI(char* input);
// other stuff
aFunctionAPI("Foo"); //this call is not safe. if the function modified the
//literal string the program will crash
std::string myFoo("Foo");
aFunctionAPI(myFoo.c_str()); //this is not compiling
aFunctionAPI(const_cast<char*>(myFoo.c_str())); //this is not safe std::string
//implement reference counting and
//it may change the value of other
//strings as well.
DeepString myDeepFoo(myFoo);
aFunctionAPI(myFoo.str()); //this is fine
J'ai appelé la classe DeepString parce qu'elle crée une copie profonde et unique (le DeepString n'est pas copiable) d'une chaîne existante.