std :: string a char *

335

Quiero convertir un std :: string en un tipo de datos char * o char [] .

std::string str = "string";
char* chr = str;

Resulta en: "error: no se puede convertir 'std :: string' a 'char' ..." .

¿Qué métodos hay disponibles para hacer esto?


fuente

Respuestas:

672

No se convertirá automáticamente (gracias a Dios). Tendrá que usar el método c_str()para obtener la versión de cadena C.

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

Tenga en cuenta que devuelve a const char *; no puede cambiar la cadena de estilo C devuelta por c_str(). Si desea procesarlo, primero deberá copiarlo:

std::string str = "string";
char *cstr = new char[str.length() + 1];
strcpy(cstr, str.c_str());
// do stuff
delete [] cstr;

O en C ++ moderno:

std::vector<char> cstr(str.c_str(), str.c_str() + str.size() + 1);
orlp
fuente
44
@Kerrek SB: Era un ejemplo, usaría un puntero inteligente en código real, o más probablemente evitaría esta c_strlocura por completo.
orlp
14
La respuesta es voluminosa, poco elegante, no local, utiliza matrices sin procesar y requiere atención a la seguridad de excepción. vectorfue inventado precisamente como un contenedor para matrices dinámicas, por lo que no usarlo parece una oportunidad perdida en el mejor de los casos, y en el peor de los casos, viola el espíritu de C ++.
Kerrek SB
21
En primer lugar, sí, la respuesta es voluminosa. Primero explico el error del OP (pensando que std::stringse convertiría automáticamente) y luego explico lo que debería usar, con un ejemplo de código corto. Mirando hacia el futuro, también explico algunos efectos secundarios del uso de esta función, de los cuales uno no puede editar la cadena devuelta por c_str(). Usted ve erróneamente mis ejemplos breves como un código de resolución de problemas real, que no lo es.
orlp
8
Voté en contra de la respuesta. Esta respuesta de hecho no es útil y el hecho de que fue aceptado es muy lamentable. Esta respuesta ignora por completo las buenas prácticas de programación en C ++ y la seguridad de excepción, y existen soluciones muy superiores, algunas de las cuales se dan en otras respuestas a esta pregunta (por ejemplo, la respuesta dada por ildjarn que usa std::vector<char>).
James McNellis
114
@ james-mcnellis, elegí esta respuesta como la correcta porque respondía EXACTAMENTE lo que estaba preguntando ... Ni más ni menos. No pregunté qué crees que debería hacer, no pedí una solución diferente para lo que crees que estoy haciendo, no pedí buenas prácticas. No tiene idea de en qué estoy trabajando, dónde se implementará mi código y en qué condiciones. Algunos deberían aprender a leer, comprender preguntas y responder lo que realmente se les pregunta. No hay necesidad de presumir aquí.
151

Más detalles aquí , y aquí, pero puedes usar

string str = "some string" ;
char *cstr = &str[0];
bobobobo
fuente
15
FWIW, en mi libro, esta es la única respuesta correcta a la pregunta que realmente se hizo. Un std :: string es inherentemente mutable: las personas que lo hacen sonar como modificar el contenido de la cadena es de alguna manera el trabajo del diablo parece estar perdiendo este hecho.
Jay Freeman -saurik-
2
Sí, esta es la respuesta correcta. Es una tontería que, dada la frecuencia de uso, no haya un método estándar para hacer esto, como el lockbuffer de msoft.
Erik Aronesty
1
Cambié 0 a 0u. Debido a que algunos compiladores / bibliotecas (lo crean o no) se quejan de cierta ambigüedad cuando se activan las advertencias para la construcción & str [0]
Erik Aronesty
Dudo que cuando se elimine el str, el char cstr se vuelva nulo. Así que supongo que aquí solo se asigna un puntero de la cadena al puntero de caracteres. Entonces, la conversión de string a char no está literalmente completa. La cadena solo apunta a char * pero su valor no se convierte. ¿¿¿Estoy en lo correcto???
Samitha Chathuranga
55
Tenga en cuenta que esto es solo C ++ 11. Las versiones anteriores pueden no tener almacenamiento continuo o les falta el nulo final
Flamefire
39

Si necesitara una copia cruda mutable del contenido de la cadena de c ++, entonces haría esto:

std::string str = "string";
char* chr = strdup(str.c_str());

y después:

free(chr); 

Entonces, ¿por qué no juego con std :: vector o new [] como cualquier otra persona? Porque cuando necesito una cadena char * sin procesar de estilo C mutable, entonces porque quiero llamar al código C que cambia la cadena y el código C desasigna cosas con free () y asigna malloc () (strdup usa malloc) . Entonces, si paso mi cadena sin procesar a alguna función X escrita en C , podría tener una restricción en su argumento de que tiene que asignarse en el montón (por ejemplo, si la función podría llamar a realloc en el parámetro). ¡Pero es muy poco probable que espere un argumento asignado con (algunos redefinidos por el usuario) nuevo []!

Mainframe nórdico
fuente
Deberías explicar de dónde strdupes.
LF
22

(Esta respuesta se aplica solo a C ++ 98).

Por favor, no uses un crudo char*.

std::string str = "string";
std::vector<char> chars(str.c_str(), str.c_str() + str.size() + 1u);
// use &chars[0] as a char*
ildjarn
fuente
1
De hecho, solo necesitaba algo como esto hoy más temprano. Me preguntaba, ¿está bien decirlo vector<char>(str.c_str(), str.c_str() + str.size() + 1), sin asignar el puntero a un carácter temporal?
Kerrek SB
1
@Kerrek: Sí, el valor de retorno de std::basic_string<>::c_str()es válido hasta que stringse cambie o se destruya. Esto también implica que devuelve el mismo valor en llamadas posteriores siempre que stringno se modifique.
ildjarn
2
@friendzis: no hay velocidad o espacio de arriba utilizando vectorde esta manera. Y si uno escribiera código seguro de excepción sin un mecanismo RAII (es decir, utilizando punteros sin formato), la complejidad del código sería mucho mayor que esta simple línea.
ildjarn
77
Es un mito que vectortiene una gran cantidad de gastos generales y complejidad. Si su requisito es que tenga una matriz de caracteres mutable , entonces, de hecho, un vector de caracteres es prácticamente el contenedor ideal de C ++. Si su requerimiento realmente solo requiere un puntero const-char, entonces simplemente use c_str()y ya está.
Kerrek SB
3
@ildjarn: En realidad, básicamente lo fue .
Carreras de ligereza en órbita
14
  • Si solo desea una cadena de estilo C que represente el mismo contenido:

    char const* ca = str.c_str();
  • Si desea una cadena de estilo C con nuevos contenidos, una forma (dado que no conoce el tamaño de la cadena en tiempo de compilación) es la asignación dinámica:

    char* ca = new char[str.size()+1];
    std::copy(str.begin(), str.end(), ca);
    ca[str.size()] = '\0';

    No lo olvides delete[]más tarde.

  • Si desea una matriz de longitud limitada estáticamente asignada:

    size_t const MAX = 80; // maximum number of chars
    char ca[MAX] = {};
    std::copy(str.begin(), (str.size() >= MAX ? str.begin() + MAX : str.end()), ca);

std::stringno se convierte implícitamente a estos tipos por la simple razón de que la necesidad de hacer esto suele ser un olor a diseño. Asegúrate de que realmente necesitas.

Si definitivamente necesita un char*, la mejor manera es probablemente:

vector<char> v(str.begin(), str.end());
char* ca = &v[0]; // pointer to start of vector
Carreras de ligereza en órbita
fuente
1
¿Por qué &str.front(), &str.back()(que no están presentes en C ++ 03) en lugar de los más comunes str.begin()y str.end()?
Armen Tsirunyan
1
¿Qué pasa str.begin(), o incluso std::begin(str), como un iterador? No creo que stringtenga ninguna obligación de estar en memoria contigua vector, ¿o sí?
xtofl
1
@xtofl: ya los edité. Y sí, a partir de C ++ 11 hay una obligación; Esto estaba implícito en C ++ 03.
Carreras de ligereza en órbita el
@xtofl: no en C ++ 03. En C ++ 11 tenemos esa garantía, junto con las funciones front () y back (), que se
utilizaron
1
@Tomalak: Fueron mal utilizados en lo que necesitabas &back() + 1, no&back()
Armen Tsirunyan
12

Esto sería mejor como un comentario sobre la respuesta de bobobobo, pero no tengo el representante para eso. Logra lo mismo pero con mejores prácticas.

A pesar de las otras respuestas son útiles, si alguna vez necesita para convertir std::stringa char*forma explícita y sin const, const_castes su amigo.

std::string str = "string";
char* chr = const_cast<char*>(str.c_str());

Tenga en cuenta que esto no le dará una copia de los datos; le dará un puntero a la cadena. Por lo tanto, si modifica un elemento de chr, lo modificará str.

oso sin pelo
fuente
6

Suponiendo que solo necesita una cadena de estilo C para pasar como entrada:

std::string str = "string";
const char* chr = str.c_str();
Mark B
fuente
4

Para ser estrictamente pedante, no puede "convertir una cadena std :: en un tipo de datos char * o char []".

Como han mostrado las otras respuestas, puede copiar el contenido de std :: string a una matriz de caracteres, o hacer un const char * al contenido de std :: string para que pueda acceder a él en un "estilo C" .

Si está intentando cambiar el contenido de std :: string, el tipo std :: string tiene todos los métodos para hacer cualquier cosa que pueda necesitar.

Si está tratando de pasarlo a alguna función que toma un char *, hay std :: string :: c_str ().

Rob K
fuente
4

Aquí hay una versión más robusta de Protocol Buffer

char* string_as_array(string* str)
{
    return str->empty() ? NULL : &*str->begin();
}

// test codes
std::string mystr("you are here");
char* pstr = string_as_array(&mystr);
cout << pstr << endl; // you are here
zangw
fuente
+1 para comprobar que la cadena está vacía. También agregaría un cheque para asegurarme de que la cadena esté terminada en cero: if (str[str.length()-1] != 0) str.push_back(0)
GaspardP
4

Conversión en estilo OOP

converter.hpp

class StringConverter {
    public: static char * strToChar(std::string str);
};

converter.cpp

char * StringConverter::strToChar(std::string str)
{
    return (char*)str.c_str();
}

uso

StringConverter::strToChar("converted string")
Patryk Merchelski
fuente
Me gusta cómo la conversión a char * elimina el const de la salida de c_str, creo que la razón por la que c_str devuelve const char * es para eliminar posibles problemas de acceso a la memoria, proporcionando una versión de solo lectura. el OP quiere tener un char *, pero creo que podría ser mejor servido por la salida const char * de c_str, ya que eso es más seguro, y las funciones que toman char * generalmente también toman const char * (suponiendo que las funciones no hacer algo como cambiar sus entradas, que en general, no deberían).
Felipe Valdés
3

Por completo, no lo olvides std::string::copy().

std::string str = "string";
const size_t MAX = 80;
char chrs[MAX];

str.copy(chrs, MAX);

std::string::copy()no termina NUL. Si necesita asegurar un terminador NUL para usar en funciones de cadena C:

std::string str = "string";
const size_t MAX = 80;
char chrs[MAX];

memset(chrs, '\0', MAX);
str.copy(chrs, MAX-1);
Jeffery Thomas
fuente
3

Puedes hacerlo usando iterador.

std::string str = "string";
std::string::iterator p=str.begin();
char* chr = &(*p);

Buena suerte.

TS.PARK
fuente
3

Una versión segura de la respuesta char * de orlp usando unique_ptr:

std::string str = "string";
auto cstr = std::make_unique<char[]>(str.length() + 1);
strcpy(cstr.get(), str.c_str());
Enhex
fuente
3

Para obtener un const char *de un std::stringuso de la c_str()función miembro:

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

Para obtener un no constante char *de un std::stringpuede usar la data()función miembro que devuelve un puntero no constante desde C ++ 17:

std::string str = "string";
char* chr = str.data();

Para versiones anteriores del lenguaje, puede usar la construcción de rango para copiar la cadena en un vector del que se puede obtener un puntero sin constante:

std::string str = "string";
std::vector<char> str_copy(str.c_str(), str.c_str() + str.size() + 1);
char* chr = str_copy.data();

Pero tenga en cuenta que esto no le permitirá modificar la cadena contenida str, solo los datos de la copia se pueden cambiar de esta manera. Tenga en cuenta que es especialmente importante en versiones anteriores del lenguaje usar c_str()aquí porque en aquel entonces std::stringno se garantizaba que se anulara hasta que c_str()se llamara.

François Andrieux
fuente
2
char* result = strcpy((char*)malloc(str.length()+1), str.c_str());
cegprakash
fuente
2

Alternativamente, puede usar vectores para obtener un carácter de escritura * como se muestra a continuación;

//this handles memory manipulations and is more convenient
string str;
vector <char> writable (str.begin (), str.end) ;
writable .push_back ('\0'); 
char* cstring = &writable[0] //or &*writable.begin () 

//Goodluck  

fuente
Esto asignará nueva memoria para el vector y luego copiará cada carácter. std :: string ya es un contenedor, también podría empujar_back (0) a su cadena y hacer & str [0]
GaspardP
1

Esto también funcionará

std::string s;
std::cout<<"Enter the String";
std::getline(std::cin, s);
char *a=new char[s.size()+1];
a[s.size()]=0;
memcpy(a,s.c_str(),s.size());
std::cout<<a;  
Genocidio_Hoax
fuente