Pregunta Cómo convertir un std :: string a const char * o char *?


¿Cómo puedo convertir un std::string a un char* o una const char*?


777
2017-12-07 19:30


origen


Respuestas:


Si solo quieres pasar un std::string a una función que necesita const char* puedes usar

std::string str;
const char * c = str.c_str();

Si desea obtener una copia escribible, como char *, puedes hacer eso con esto:

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;

Editar: Tenga en cuenta que lo anterior no es una excepción segura. Si hay algo entre el new llamar y el delete llamada lanza, perderá memoria, ya que nada llamará delete para ti automáticamente Hay dos formas inmediatas de resolver esto.

boost :: scoped_array

boost::scoped_array borrará la memoria cuando salga del alcance:

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

Esta es la forma estándar (no requiere ninguna biblioteca externa). Tu usas std::vector, que gestiona completamente la memoria para ti.

std::string str;
std::vector<char> writable(str.begin(), str.end());
writable.push_back('\0');

// get the char* using &writable[0] or &*writable.begin()

932
2017-12-07 19:31



Dado, digamos ...

std::string x = "hello";

 Obteniendo un `char *` o `const char *` de una `cadena`

Cómo obtener un puntero de personaje que sea válido mientras x permanece en el alcance y no se modifica más

C ++ 11 simplifica las cosas; todos los siguientes dan acceso al mismo búfer de cadena interno:

const char* p_c_str = x.c_str();
const char* p_data  = x.data();
const char* p_x0    = &x[0];

      char* p_x0_rw = &x[0];  // compiles iff x is not const...

Todos los indicadores anteriores tendrán el mismo valor - la dirección del primer carácter en el búfer. Incluso una cadena vacía tiene un "primer carácter en el búfer", porque C ++ 11 garantiza mantener siempre un carácter terminador NUL / 0 adicional después del contenido de cadena explícitamente asignado (p. std::string("this\0that", 9) tendrá una reserva de almacenamiento intermedio "this\0that\0")

Dado cualquiera de los indicadores anteriores:

char c = p[n];   // valid for n <= x.size()
                 // i.e. you can safely read the NUL at p[x.size()]

Solo para los noconst puntero desde &x[0]:

p_x0_rw[n] = c;  // valid for n <= x.size() - 1
                 // i.e. don't overwrite the implementation maintained NUL

Escribir un NUL en otra parte de la cadena no no cambiar el stringes size(); stringtienen permitido contener cualquier número de NUL, no reciben ningún tratamiento especial por std::string (lo mismo en C ++ 03).

En C ++ 03, las cosas eran considerablemente más complicadas (diferencias clave resaltado)

  • x.data()

    • devoluciones const char* al buffer interno de la cadena que no fue requerido por el Estándar para concluir con un NUL (es decir, podría ser ['h', 'e', 'l', 'l', 'o'] seguido de valores no inicializados o basura, con accesos accidentales al comportamiento indefinido)
      • x.size() los personajes son seguros de leer, es decir x[0] mediante x[x.size() - 1]
      • para las cadenas vacías, tiene garantizado un puntero no nulo al que se puede agregar 0 con seguridad (¡hurra!), pero no debe desreferenciar ese puntero.
  • &x[0]

    • para cuerdas vacías esto tiene un comportamiento indefinido (21.3.4)
      • p.ej. dado f(const char* p, size_t n) { if (n == 0) return; ...whatever... } no debes llamar f(&x[0], x.size()); cuando x.empty() - Solo usa f(x.data(), ...).
    • de lo contrario, según x.data() pero:
      • para noconst  x esto produce un noconst  char* puntero; puedes sobrescribir el contenido de la cadena
  • x.c_str()

    • devoluciones const char* a una representación ASCIIZ (terminada en NUL) del valor (es decir, ['h', 'e', ​​'l', 'l', 'o', '\ 0']).
    • aunque pocas implementaciones, si es que alguna, eligieron hacerlo, el Estándar C ++ 03 fue redactado para permitir a la implementación de cadenas la libertad de crear un búfer distinto terminado en NUL  sobre la marcha, desde el buffer potencialmente no-NUL terminado "expuesto" por x.data() y &x[0]
    • x.size() + 1 caracteres son seguros de leer.
    • seguro garantizado incluso para cadenas vacías (['\ 0']).

Consecuencias de acceder a índices legales externos

De cualquier forma que obtenga un puntero, no debe acceder a la memoria más allá del puntero que los caracteres garantizados presentes en las descripciones anteriores. Los intentos de hacerlo tienen comportamiento indefinido, con una posibilidad muy real de bloqueos de aplicaciones y resultados de basura incluso para lecturas, y datos adicionales al por mayor, acumulación de vulnerabilidades de seguridad y / o corrupción para escrituras.

¿Cuándo se invalidan esos indicadores?

Si llamas a algunos string función miembro que modifica el string o reserva capacidad adicional, cualquier valor de puntero devuelto de antemano por cualquiera de los métodos anteriores son invalidado. Puede usar esos métodos nuevamente para obtener otro puntero. (Las reglas son las mismas que para los iteradores en strings).

Ver también Cómo obtener un puntero de personaje válido incluso después x deja alcance o se modifica más abajo....

Entonces, cual es mejor ¿usar?

Desde C ++ 11, use .c_str() para datos ASCIIZ, y .data() para datos "binarios" (se explican más abajo).

En C ++ 03, use .c_str() a menos que sea cierto que .data() es adecuado y prefiere .data() encima &x[0] ya que es seguro para cadenas vacías ...

... intenta comprender el programa lo suficiente como para usarlo data() cuando sea apropiado, o probablemente cometerá otros errores ...

El carácter ASCII NUL '\ 0' garantizado por .c_str() es utilizado por muchas funciones como un valor centinela que denota el final de los datos relevantes y de acceso seguro. Esto se aplica a las funciones solo de C ++ como, por ejemplo, fstream::fstream(const char* filename, ...) y funciones compartidas con C como strchr()y printf().

Dado C ++ 03 .c_str()Las garantías sobre el buffer devuelto son un súper conjunto de .data()'s, siempre puedes usar de forma segura .c_str(), pero a veces las personas no lo hacen porque:

  • utilizando .data() comunica a otros programadores que leen el código fuente que los datos no son ASCIIZ (más bien, estás usando la cadena para almacenar un bloque de datos (que a veces ni siquiera es realmente textual)), o que lo estás pasando a otro función que lo trata como un bloque de datos "binarios". Esta puede ser una idea crucial para garantizar que los cambios en el código de otros programadores continúen manejando los datos correctamente.
  • C ++ 03 solamente: hay una pequeña posibilidad de que su string la implementación necesitará hacer una asignación adicional de memoria y / o copia de datos para preparar el buffer terminado en NUL

Como una sugerencia adicional, si los parámetros de una función requieren el (const) char* pero no insista en obtener x.size(), la función probablemente necesita una entrada ASCIIZ, entonces .c_str() es una buena opción (la función necesita saber dónde termina el texto de alguna manera, por lo que si no es un parámetro separado, solo puede ser una convención como un prefijo de longitud o centinela o una longitud esperada fija).

Cómo obtener un puntero de personaje válido incluso después x deja alcance o se modifica más

Necesitarás dupdo el contenido de la string  x a una nueva área de memoria afuera x. Este buffer externo podría estar en muchos lugares, como en otro string o variable de matriz de caracteres, puede o no tener una vida útil diferente a x debido a que está en un ámbito diferente (por ejemplo, espacio de nombres, global, estático, montón, memoria compartida, archivo de memoria asignada).

Para copiar el texto de std::string x en una matriz de caracteres independiente:

// USING ANOTHER STRING - AUTO MEMORY MANAGEMENT, EXCEPTION SAFE
std::string old_x = x;
// - old_x will not be affected by subsequent modifications to x...
// - you can use `&old_x[0]` to get a writable char* to old_x's textual content
// - you can use resize() to reduce/expand the string
//   - resizing isn't possible from within a function passed only the char* address

std::string old_x = x.c_str(); // old_x will terminate early if x embeds NUL
// Copies ASCIIZ data but could be less efficient as it needs to scan memory to
// find the NUL terminator indicating string length before allocating that amount
// of memory to copy into, or more efficient if it ends up allocating/copying a
// lot less content.
// Example, x == "ab\0cd" -> old_x == "ab".

// USING A VECTOR OF CHAR - AUTO, EXCEPTION SAFE, HINTS AT BINARY CONTENT, GUARANTEED CONTIGUOUS EVEN IN C++03
std::vector<char> old_x(x.data(), x.data() + x.size());       // without the NUL
std::vector<char> old_x(x.c_str(), x.c_str() + x.size() + 1);  // with the NUL

// USING STACK WHERE MAXIMUM SIZE OF x IS KNOWN TO BE COMPILE-TIME CONSTANT "N"
// (a bit dangerous, as "known" things are sometimes wrong and often become wrong)
char y[N + 1];
strcpy(y, x.c_str());

// USING STACK WHERE UNEXPECTEDLY LONG x IS TRUNCATED (e.g. Hello\0->Hel\0)
char y[N + 1];
strncpy(y, x.c_str(), N);  // copy at most N, zero-padding if shorter
y[N] = '\0';               // ensure NUL terminated

// USING THE STACK TO HANDLE x OF UNKNOWN (BUT SANE) LENGTH
char* y = alloca(x.size() + 1);
strcpy(y, x.c_str());

// USING THE STACK TO HANDLE x OF UNKNOWN LENGTH (NON-STANDARD GCC EXTENSION)
char y[x.size() + 1];
strcpy(y, x.c_str());

// USING new/delete HEAP MEMORY, MANUAL DEALLOC, NO INHERENT EXCEPTION SAFETY
char* y = new char[x.size() + 1];
strcpy(y, x.c_str());
//     or as a one-liner: char* y = strcpy(new char[x.size() + 1], x.c_str());
// use y...
delete[] y; // make sure no break, return, throw or branching bypasses this

// USING new/delete HEAP MEMORY, SMART POINTER DEALLOCATION, EXCEPTION SAFE
// see boost shared_array usage in Johannes Schaub's answer

// USING malloc/free HEAP MEMORY, MANUAL DEALLOC, NO INHERENT EXCEPTION SAFETY
char* y = strdup(x.c_str());
// use y...
free(y);

Otras razones para querer un char* o const char* generado a partir de un string

Entonces, arriba has visto cómo obtener un (const) char*y cómo hacer una copia del texto independiente del original string, pero que puedes hacer ¿con eso? Un puñado aleatorio de ejemplos ...

  • dar acceso al código "C" al C ++ stringel texto de printf("x is '%s'", x.c_str());
  • dupdo xtexto a un búfer especificado por la persona que llama a su función (p. strncpy(callers_buffer, callers_buffer_size, x.c_str())), o memoria volátil utilizada para la E / S del dispositivo (p. for (const char* p = x.c_str(); *p; ++p) *p_device = *p;)
  • adjuntar xEl texto de una matriz de caracteres que ya contiene texto ASCIIZ (p. strcat(other_buffer, x.c_str())) - tenga cuidado de no rebasar el búfer (en muchas situaciones puede necesitar usar strncat)
  • devolver un const char* o char* de una función (tal vez por razones históricas: el cliente usa su API existente) o para la compatibilidad C no desea devolver un std::string, pero quiero copiar tu stringdatos de alguna parte para la persona que llama)
    • tenga cuidado de no devolver un puntero que pueda ser desreferenciado por la persona que llama después de un local string variable a la que ese puntero apunta ha dejado alcance
    • algunos proyectos con objetos compartidos compilados / vinculados para diferentes std::string las implementaciones (por ejemplo, STLport y nativo del compilador) pueden pasar datos como ASCIIZ para evitar conflictos

173
2018-01-12 15:53



Utilizar el .c_str() método para const char *.

Puedes usar &mystring[0] conseguir un char * puntero, pero hay un par de gotcha: no necesariamente obtendrá una cadena terminada en cero, y no podrá cambiar el tamaño de la cadena. Especialmente debe tener cuidado de no agregar caracteres más allá del final de la cadena o obtendrá un desbordamiento del búfer (y un posible bloqueo).

No había ninguna garantía de que todos los caracteres fueran parte del mismo búfer contiguo hasta C ++ 11, pero en la práctica todas las implementaciones conocidas de std::string trabajó de esa manera de todos modos; ver ¿"& S [0]" apunta a caracteres contiguos en std :: string?.

Tenga en cuenta que muchos string las funciones de los miembros reasignarán el búfer interno e invalidarán los punteros que haya guardado. Es mejor usarlos inmediatamente y luego descartarlos.


31
2018-03-29 13:32



C ++ 17

C ++ 17 (próxima norma) cambia la sinopsis de la plantilla basic_string agregando una sobrecarga no const de data():

charT* data() noexcept;

Devuelve: Un puntero p tal que p + i == & operador para cada i en [0, tamaño ()].


CharT const * de std::basic_string<CharT>

std::string const cstr = { "..." };
char const * p = cstr.data(); // or .c_str()

CharT * de std::basic_string<CharT>

std::string str = { "..." };
char * p = str.data();

C ++ 11

CharT const * de std::basic_string<CharT>

std::string str = { "..." };
str.c_str();

CharT * de std::basic_string<CharT>

Desde C ++ 11 en adelante, el estándar dice:

  1. Los objetos similares a los carboncillos en una basic_string el objeto se almacenará contiguamente. Es decir, para cualquier basic_string objeto s, la identidad &*(s.begin() + n) == &*s.begin() + n se mantendrá para todos los valores de ntal que 0 <= n < s.size().

  1. const_reference operator[](size_type pos) const; 
      reference operator[](size_type pos); 

    Devoluciones: *(begin() + pos) Si pos < size(), de lo contrario, una referencia a un objeto de tipo CharT con valor CharT(); el valor referenciado no se modificará.


  1. const charT* c_str() const noexcept;
    const charT* data() const noexcept;

    Devuelve: un puntero p tal que p + i == &operator[](i) para cada i en [0,size()].

Hay varias formas posibles de obtener un puntero de carácter no const.

1. Utilice el almacenamiento contiguo de C ++ 11

std::string foo{"text"};
auto p = &*foo.begin();

Pro

  • Simple y corto
  • Rápido (solo método sin copia)

Contras

  • Final '\0' no debe ser alterado / no necesariamente parte de la memoria no const.

2. Uso std::vector<CharT>

std::string foo{"text"};
std::vector<char> fcv(foo.data(), foo.data()+foo.size()+1u);
auto p = fcv.data();

Pro

  • Sencillo
  • Manejo automático de la memoria
  • Dinámica

Contras

  • Requiere copia de cadena

3. Uso std::array<CharT, N> Si N es tiempo de compilación constante (y lo suficientemente pequeño)

std::string foo{"text"};
std::array<char, 5u> fca;
std::copy(foo.data(), foo.data()+foo.size()+1u, fca.begin());

Pro

  • Sencillo
  • Manejo de la memoria de pila

Contras

  • Estático
  • Requiere copia de cadena

4. Asignación de memoria sin procesar con eliminación automática de almacenamiento

std::string foo{ "text" };
auto p = std::make_unique<char[]>(foo.size()+1u);
std::copy(foo.data(), foo.data() + foo.size() + 1u, &p[0]);

Pro

  • Huella de memoria pequeña
  • Eliminación automática
  • Sencillo

Contras

  • Requiere copia de cadena
  • Estático (el uso dinámico requiere mucho más código)
  • Menos funciones que vector o matriz

5. Asignación de memoria bruta con manejo manual

std::string foo{ "text" };
char * p = nullptr;
try
{
  p = new char[foo.size() + 1u];
  std::copy(foo.data(), foo.data() + foo.size() + 1u, p);
  // handle stuff with p
  delete[] p;
}
catch (...)
{
  if (p) { delete[] p; }
  throw;
}

Pro

  • Máximo 'control'

Estafa

  • Requiere copia de cadena
  • Máxima responsabilidad / susceptibilidad por errores
  • Complejo

18
2017-07-12 12:06



Estoy trabajando con una API con muchas funciones obtengo como entrada una char*.

He creado una clase pequeña para enfrentar este tipo de problema, he implementado el modismo 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_; }
};

Y puedes usarlo como:

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

He llamado a la clase DeepString porque está creando una copia profunda y única (el DeepString no se puede copiar) de una cadena existente.


9
2018-05-12 08:18



char* result = strcpy((char*)malloc(str.length()+1), str.c_str());

7
2018-02-17 16:45



Solo mira esto:

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

Sin embargo, tenga en cuenta que esto devolverá un const char *.Para char *, utilizar strcpy para copiarlo en otro char formación.


7



Prueba esto

std::string s(reinterpret_cast<const char *>(Data), Size);

-4