¿Cómo convertir un std :: string a const char * o char *?
Frecuentes
Visto 995,583 equipos
8 Respuestas
1127
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 grabable, 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 seguro para excepciones. Si algo entre el new
llamar y el delete
llamadas lanzadas, perderás memoria, ya que nada llamará delete
para usted automáticamente. Hay dos formas inmediatas de solucionar este problema.
boost :: scoped_array
boost::scoped_array
borrará la memoria por ti cuando salgas 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 por 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()
Respondido 06 Oct 14, 08:10
Simplemente use char * result = strdup (str.c_str ()); - Jasper Bekkers
podría, pero strdup no es una función estándar de ac o c ++, es de posix :) - Johannes Schaub - litb
lo que probablemente preferiría en general es std :: vector escribible (str.begin (), str.end ()); writable.push_back ('\ 0'); char * c = & escribible [0]; - Johannes Schaub - litb
std :: copy es la forma en que C ++ hace esto, sin la necesidad de llegar al puntero de la cadena. Intento evitar el uso de funciones C tanto como puedo. - Johannes Schaub - litb
A partir de C ++ 17, std::string::data()
ahora devuelve un CharT*
en lugar de un const CharT*
. Podría ser una buena idea actualizar esta respuesta :) - Cohete 1111
198
Dado decir ...
std::string x = "hello";
Obteniendo un `char *` o `const char *` de una `string`
Cómo obtener un puntero de carácter 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();
char* p_writable_data = x.data(); // for non-const x from C++17
const char* p_x0 = &x[0];
char* p_x0_rw = &x[0]; // compiles iff x is not const...
Todos los punteros anteriores contendrán mismo valor - la dirección del primer carácter del 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 de terminación NUL / 0 adicional después del contenido de la cadena asignado explícitamente (p. Ej. std::string("this\0that", 9)
tendrá una retención de búfer "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 p_writable_data
y desde &x[0]
:
p_writable_data[n] = c;
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 string
's size()
; string
pueden contener cualquier número de NUL; no reciben un tratamiento especial por parte de std::string
(lo mismo en C ++ 03).
In C ++ 03, las cosas eran considerablemente más complicadas (diferencias clave destacó):
x.data()
- devoluciones
const char*
al búfer 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 a los mismos teniendo comportamiento indefinido).x.size()
los caracteres son seguros de leer, es decirx[0]
ax[x.size() - 1]
- para cadenas vacías, tiene garantizado algún puntero no NULL al que se puede agregar 0 de manera segura (¡hurra!), pero no debe eliminar la referencia a ese puntero.
- devoluciones
&x[0]
- para cadenas vacías, esto tiene un comportamiento indefinido (21.3.4)
- por ejemplo, dado
f(const char* p, size_t n) { if (n == 0) return; ...whatever... }
no debes llamarf(&x[0], x.size());
cuandox.empty()
- Solo usaf(x.data(), ...)
.
- por ejemplo, dado
- de lo contrario, según
x.data()
pero:- para los no-
const
x
esto produce una noconst
char*
puntero; puede sobrescribir el contenido de la cadena
- para los no-
- para cadenas vacías, esto tiene un comportamiento indefinido (21.3.4)
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 optaron por hacerlo, el estándar C ++ 03 se redactó para permitir a la implementación de cadenas la libertad de crear un búfer terminado en NUL distinto sobre la marcha, del búfer potencialmente no terminado en NUL "expuesto" por
x.data()
e&x[0]
x.size()
+ 1 caracteres son seguros para leer.- seguro garantizado incluso para cadenas vacías (['\ 0']).
- devoluciones
Consecuencias de acceder a índices legales externos
Cualquiera que sea la forma en 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 fallas en la aplicación y resultados basura incluso para lecturas, y además datos al por mayor, corrupción de pila y / o vulnerabilidades de seguridad para escrituras.
¿Cuándo se invalidan esos indicadores?
Si llamas a alguien string
función miembro que modifica el string
o reserva más capacidad, cualquier valor de puntero devuelto de antemano por cualquiera de los métodos anteriores es invalidado. Puede usar esos métodos nuevamente para obtener otro puntero. (Las reglas son las mismas que para los iteradores en string
s).
Vea también Cómo hacer que un puntero de carácter sea válido incluso después x
deja el alcance o se modifica más debajo....
Entonces, cual es mejor ¿usar?
Desde C ++ 11, use .c_str()
para datos ASCIIZ, y .data()
para datos "binarios" (se explica más adelante).
En C ++ 03, use .c_str()
a menos que esté seguro de que .data()
es adecuado, y prefiero .data()
Más de &x[0]
ya que es seguro para cadenas vacías ...
... intente 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 tanto a C ++ - solo funciones como say fstream::fstream(const char* filename, ...)
y funciones compartidas con C como strchr()
y printf()
.
Dado C ++ 03's .c_str()
Las garantías sobre el búfer devuelto son un superconjunto de .data()
's, siempre puedes usar de forma segura .c_str()
, pero la gente a veces no lo hace porque:
- usando
.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 información crucial para garantizar que los cambios de código de otros programadores continúen manejando los datos correctamente. - Solo C ++ 03: existe una pequeña posibilidad de que su
string
La implementación necesitará hacer una asignación de memoria adicional y / o copia de datos para preparar el búfer terminado en NUL
Como sugerencia adicional, si los parámetros de una función requieren el (const
) char*
pero no insistas en conseguir x.size()
, la función probablemente necesita una entrada ASCIIZ, por lo que .c_str()
es una buena elecció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 alguna longitud fija esperada).
Cómo hacer que un puntero de carácter sea válido incluso después x
deja el alcance o se modifica más
Necesitarás copia el contenido de la string
x
a una nueva área de memoria fuera x
. Este búfer 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 la x
debido a estar en un ámbito diferente (por ejemplo, espacio de nombres, global, estático, montón, memoria compartida, archivo mapeado en memoria).
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*
or 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 do ¿con eso? Un puñado de ejemplos al azar ...
- dar acceso de código "C" a C ++
string
el texto, como enprintf("x is '%s'", x.c_str());
- copia
x
el texto a un búfer especificado por la persona que llama a la función (p. ej.strncpy(callers_buffer, callers_buffer_size, x.c_str())
) o memoria volátil utilizada para la E / S del dispositivo (p. ej.for (const char* p = x.c_str(); *p; ++p) *p_device = *p;
) - anexar
x
's texto a una matriz de caracteres que ya contiene algún texto ASCIIZ (p. ej.strcat(other_buffer, x.c_str())
): tenga cuidado de no sobrepasar el búfer (en muchas situaciones, es posible que deba usarstrncat
) - devolver un
const char*
orchar*
de una función (quizás por razones históricas - el cliente está usando su API existente - o por compatibilidad con C no desea devolver unstd::string
, pero quiero copiar tustring
datos en algún lugar 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 apuntó ese puntero ha dejado el alcance - algunos proyectos con objetos compartidos compilados / vinculados para diferentes
std::string
las implementaciones (por ejemplo, STLport y compilador nativo) pueden pasar datos como ASCIIZ para evitar conflictos
- tenga cuidado de no devolver un puntero que pueda ser desreferenciado por la persona que llama después de un local
Respondido el 10 de junio de 19 a las 15:06
Bonita. Otra razón para querer un char * (no constante) es operar con transmisión MPI. Se ve mejor si no tiene que copiar de un lado a otro. Yo personalmente habría ofrecido un captador char * const para encadenar. Puntero constante, pero cadena editable. Aunque puede haber interferido con la conversión implícita de const char * a string ... - Bartgol
35
Use el .c_str()
método para const char *
.
Puedes usar &mystring[0]
conseguir un char *
puntero, pero hay un par de errores: 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 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
funcionó de esa manera de todos modos; ver ¿"& S [0]" apunta a caracteres contiguos en un std :: string?.
Tenga en cuenta que muchos string
las funciones miembro reasignarán el búfer interno e invalidarán cualquier puntero que pueda haber guardado. Es mejor usarlos inmediatamente y luego desecharlos.
contestado el 23 de mayo de 17 a las 13:05
debe tener en cuenta que data () devuelve const char * :) lo que quiere decir es & str [0], que devuelve una cadena contigua, pero no necesaria, terminada en nulo. - Johannes Schaub - litb
@litb, ¡Argh! Eso es lo que obtengo por intentar obtener una respuesta rápida. He usado su solución en el pasado, no sé por qué no fue lo primero que me vino a la mente. He editado mi respuesta. - marca rescate
Técnicamente, el almacenamiento std :: string será contiguo solo en C ++ 0x. - MSalters
@MSalters, gracias, no lo sabía. Sin embargo, sería difícil encontrar una implementación donde ese no fuera el caso. - marca rescate
char * resultado = strcpy (malloc (str.length () + 1), str.c_str ()); - cegprakash
21
C ++ 17
C ++ 17 (próximo estándar) cambia la sinopsis de la plantilla basic_string
agregando una sobrecarga no constante de data()
:
charT* data() noexcept;
Devuelve: Un puntero p tal que p + i == & operador para cada i en [0, size ()].
CharT const *
del std::basic_string<CharT>
std::string const cstr = { "..." };
char const * p = cstr.data(); // or .c_str()
CharT *
del std::basic_string<CharT>
std::string str = { "..." };
char * p = str.data();
C ++ 11
CharT const *
del std::basic_string<CharT>
std::string str = { "..." };
str.c_str();
CharT *
del std::basic_string<CharT>
Desde C ++ 11 en adelante, el estándar dice:
- Los objetos carbonizados en un
basic_string
El objeto se almacenará de forma contigua. Es decir, para cualquierbasic_string
objetos
, la identidad&*(s.begin() + n) == &*s.begin() + n
se mantendrá para todos los valores den
tal que0 <= n < s.size()
.
const_reference operator[](size_type pos) const;
reference operator[](size_type pos);
Devoluciones:
*(begin() + pos)
ifpos < size()
, de lo contrario una referencia a un objeto de tipoCharT
con valorCharT()
; el valor de referencia no se modificará.
const charT* c_str() const noexcept;
const charT* data() const noexcept;
Devuelve: Un puntero p tal que
p + i == &operator[](i)
para cadai
in[0,size()]
.
Hay varias formas posibles de obtener un puntero de carácter no constante.
1. Utilice el almacenamiento contiguo de C ++ 11
std::string foo{"text"};
auto p = &*foo.begin();
Pro
- Simple y corto
- Rápido (único método sin copia involucrada)
Desventajas
- Final
'\0'
no debe ser alterado / no es necesariamente parte de la memoria no constante.
2. Utilizar 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 memoria
- Dynamic
Desventajas
- Requiere copia de cadena
3. Utilizar std::array<CharT, N>
if N
es constante en el tiempo de compilación (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 memoria de pila
Desventajas
- Estático
- Requiere copia de cadena
4. Asignación de memoria sin procesar con eliminación automática del 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
- Pequeña huella de memoria
- Borrado automático
- Sencillo
Desventajas
- Requiere copia de cadena
- Estático (el uso dinámico requiere mucho más código)
- Menos características que un vector o una matriz
5. Asignación de memoria sin procesar 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'
Con
- Requiere copia de cadena
- Máxima responsabilidad / susceptibilidad a errores
- Complejo
Respondido el 30 de junio de 16 a las 12:06
9
Estoy trabajando con una API con muchas funciones que obtienen como entrada un char*
.
He creado una clase pequeña para afrontar 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 (la DeepString
no se puede copiar) de una cadena existente.
Respondido 06 Oct 14, 08:10
Evitaría esta convención de nomenclatura. c_str()
según lo utilizado por std
es una abreviatura de "C-string" no "const string" y str()
siempre devuelve un std::basic_string
no, char*
(por ejemplo std::stringstream::str()
) - cristo
9
Solo mira esto:
string str1("stackoverflow");
const char * str2 = str1.c_str();
Sin embargo, tenga en cuenta que esto devolverá un const char *
.
Para una char *
, Utilizar strcpy
para copiarlo en otro char
formación.
Respondido 19 Abr '20, 18:04
Hola, lo que publicaste ya se ha dicho varias veces, con más detalles, en otras respuestas a la pregunta de los 5 años. Está bien responder preguntas anteriores, pero solo si agrega nueva información. De lo contrario, es solo ruido. - Sabanilla
Personalmente, agradezco la sencillez. - TankorSmash
8
char* result = strcpy((char*)malloc(str.length()+1), str.c_str());
Respondido 12 Jul 14, 13:07
parece elegante pero realmente difícil de entender ... Simple es lo mejor en mi opinión - Naeem Malik
strcpy (), malloc (), length () y c_str () son funciones básicas y no hay nada difícil en esto. Solo asignando memoria y copiando. - cegprakash
sí, las funciones son básicas, pero las has torcido y doblado para que parezcan un plato de espaguetis o un trazador de líneas del monstruo de Frankenstein :) - Naeem Malik
Sí, las funciones son básicas pero ... ¿Recuerdas cuando empezaste a trabajar con un lenguaje de programación? Algunas líneas más que explicar y realmente ayudarán a un neófito a aprender por qué, por ejemplo, es diferente o mejor que esta respuesta:) - Hastur
@cegprakash: Siempre que haya un malloc (), también debe haber un free (). De lo contrario, el código pierde memoria, al igual que la solución en su respuesta. Asignar memoria sin al menos insinuar la desasignación requerida es una mala práctica para tales preguntas. - Striezel
-4
Prueba esta
std::string s(reinterpret_cast<const char *>(Data), Size);
Respondido 17 Feb 17, 16:02
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas c++ string char constants or haz tu propia pregunta.
En lugar de: char * escribible = new char [str.size () + 1]; Puede utilizar caracteres de escritura [str.size () + 1]; Entonces no necesita preocuparse por eliminar el manejo de excepciones o de escritura. - user372024
No puede usar str.size () a menos que se conozca el tamaño en el momento de la compilación, también podría desbordar su pila si el valor de tamaño fijo es enorme. - paulm
char * resultado = strcpy ((char *) malloc (str.length () + 1), str.c_str ()); - cegprakash
@cegprakash
strcpy
emalloc
no son realmente la forma de C ++. - boycyNo pero
char* dest = new char[str.length() + 1]; std::copy(str.begin(), str.end(), dest)
sería más idiomático C ++.strcpy()
emalloc()
no son incorrectos ni problemáticos, pero parece inconsistente usar una cadena C ++ y las instalaciones de la biblioteca C con equivalentes C ++ en el mismo bloque de código. - boycy