955 votes

Convertir std :: string en const char * ou char *

Comment puis-je convertir un std::string en un char* ou un const char* ?

1147voto

Johannes Schaub - litb Points 256113

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()

205voto

Tony D Points 43962

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']).
  • 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.
  • &x[0]
    • comme par x.data() mais les rendements potentiellement non-const char* pointeur
    • x.size() personnages sont sûrs à lire, et à écrire si x n'a pas été const
      • l'écriture d'un NUL, ne change pas l' strings' size(); strings'sont autorisés à contenir n'importe quel nombre de NULs, ils n'ont pas de traitement spécial, en std::string.
    • 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()); lorsque x.empty() - f(x.data(), ...).

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 strings).

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++ strings'du texte, comme en printf("x is '%s'", x.c_str());
  • copiez xs'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 xs'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 utiliser strncat)
  • de retour d'un const char* ou char* à 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 un std::string, mais ne voulez copier votre string'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

35voto

Mark Ransom Points 132545

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.

9voto

Alessandro Teruzzi Points 1860

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.

9voto

DamnDev Points 161

Voyez juste ceci:

 string str1("stackoverflow");
const char * str2 = str1.c_str();
 

Cependant, notez que cela retournera un const char * . Pour un 'char *', utilisez strcpy pour le copier dans un autre tableau char.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X