ejemplos - string c++
¿Puedo obtener una cadena C no constante de una cadena C++? (12)
¿Es realmente tan difícil hacerlo usted mismo?
#include <string>
#include <cstring>
char *convert(std::string str)
{
size_t len = str.length();
char *buf = new char[len + 1];
memcpy(buf, str.data(), len);
buf[len] = ''/0'';
return buf;
}
char *convert(std::string str, char *buf, size_t len)
{
memcpy(buf, str.data(), len - 1);
buf[len - 1] = ''/0'';
return buf;
}
// A crazy template solution to avoid passing in the array length
// but loses the ability to pass in a dynamically allocated buffer
template <size_t len>
char *convert(std::string str, char (&buf)[len])
{
memcpy(buf, str.data(), len - 1);
buf[len - 1] = ''/0'';
return buf;
}
Uso:
std::string str = "Hello";
// Use buffer we''ve allocated
char buf[10];
convert(str, buf);
// Use buffer allocated for us
char *buf = convert(str);
delete [] buf;
// Use dynamic buffer of known length
buf = new char[10];
convert(str, buf, 10);
delete [] buf;
La corrección de errores en C ++ todavía me está dando dolores de cabeza. Al trabajar con un código C antiguo, tengo la necesidad de asignar convertir un objeto de cadena C ++ en una cadena C y asignarlo a una variable. Sin embargo, la variable es un char *
y c_str()
devuelve un const char []
. ¿Hay una buena manera de evitar esto sin tener que utilizar mi propia función para hacerlo?
Edición: También estoy tratando de evitar llamar a nuevos. Con mucho gusto cambiaré el código un poco más complicado por menos pérdidas de memoria.
Dado que c_str () le da acceso directo constante a la estructura de datos, probablemente no debería convertirlo. La forma más sencilla de hacerlo sin tener que preasignar un búfer es simplemente usar strdup.
char* tmpptr;
tmpptr = strdup(myStringVar.c_str();
oldfunction(tmpptr);
free tmpptr;
Es rápido, fácil y correcto.
Hay una distinción importante que debe hacer aquí: ¿es el char*
al que desea asignar esta "moralmente constante"? Es decir, ¿está const
constness solo como un tecnicismo, y realmente todavía tratará la cuerda como una const
? En ese caso, puede usar un cast_contenido, ya sea de estilo C o de C ++, como const_cast
. Siempre y cuando usted (y cualquier otra persona que mantenga este código) tenga la disciplina de tratar a ese char*
como un const char*
, estará bien, pero el compilador ya no estará vigilando su espalda, así que si alguna vez lo trata Como no const
, puede estar modificando un búfer en el que se basa otra cosa en su código.
Si su char*
se va a tratar como no const
, y tiene la intención de modificar lo que apunta, debe copiar la cadena devuelta, no desechar su constancia.
Puede utilizar el método de copy :
len = myStr.copy(cStr, myStr.length());
cStr[len] = ''/0'';
Donde myStr
es tu cadena C ++ y cStr
a char *
con al menos myStr.length()
+1 tamaño. Además, len
es de tipo size_t
y es necesario, porque la copia no termina en nulo cStr
.
Si c_str()
le devuelve una copia del búfer interno del objeto de cadena, puede usar const_cast<>
.
Sin embargo, si c_str()
le da acceso directo al búfer interno del objeto string, haga una copia explícita, en lugar de eliminar la constante.
Si puede pagar una asignación adicional, en lugar de una strcpy
recomendada, consideraría usar std::vector<char>
siguiente manera:
// suppose you have your string:
std::string some_string("hello world");
// you can make a vector from it like this:
std::vector<char> some_buffer(some_string.begin(), some_string.end());
// suppose your C function is declared like this:
// some_c_function(char *buffer);
// you can just pass this vector to it like this:
some_c_function(&some_buffer[0]);
// if that function wants a buffer size as well,
// just give it some_buffer.size()
Para mí esto es un poco más de una forma de C ++ que de strcpy
. Eche un vistazo al artículo 16 de STL Effective de Meyers para obtener una explicación mucho mejor que la que yo podría proporcionar.
Si sabe que la std::string
no va a cambiar, funcionará una conversión de estilo C
std::string s("hello");
char *p = (char *)s.c_str();
Por supuesto, p
apunta a un búfer gestionado por la std::string
. Si std::string
se sale del alcance o se cambia el búfer (es decir, se escribe), p
probablemente no sea válido.
Lo más seguro sería copiar la cadena si la refactorización del código está fuera de cuestión.
Siempre hay const_cast ...
std::string s("hello world");
char *p = const_cast<char *>(s.c_str());
Por supuesto, eso es básicamente subvertir el sistema de tipos, pero a veces es necesario cuando se integra con código más antiguo.
Simplemente use const_cast<char*>(str.data())
No te sientas mal o raro al respecto, es un estilo perfectamente bueno para hacer esto.
Está garantizado para trabajar en C ++ 11. El hecho de que esté totalmente calificado es, sin duda, un error de la norma original anterior; en C ++ 03 fue posible implementar la string
como una lista discontinua de memoria, pero nadie lo hizo. No hay un compilador en la tierra que implemente la string
como algo más que un bloque de memoria contiguo, así que siéntase libre de tratarlo como tal con total confianza.
Supongo que siempre hay strcpy
.
O use cadenas char*
en las partes de su código C ++ que deben interactuar con las cosas antiguas.
O refactorice el código existente para compilar con el compilador de C ++ y luego usar std:string
.
Ya que para mí, inexplicables razones, nadie respondió esto de la forma que lo hago ahora, y como ahora se están cerrando otras preguntas que apuntan a esta, la agregaré aquí, aunque el hecho de que llegue un año demasiado tarde signifique que se cuelga por completo. parte inferior de la pila ...
Con C ++ 03, no se garantiza que std::string
almacene sus caracteres en una parte contigua de la memoria, y el resultado de c_str()
no necesita apuntar al búfer interno de la cadena, por lo que la única forma garantizada es el trabajo es este
std::vector<char> buffer(s.begin(), s.end());
foo(&buffer[0], buffer.size());
s.assign(buffer.begin(), buffer.end());
Como no hubo implementaciones conocidas que realmente utilizaron memoria no contigua, y dado que muchos usaron std::string
como si esto estuviera garantizado, las reglas se cambiarán para el próximo estándar, ahora garantizando la memoria contigua para sus caracteres. Así que en C ++ 1x, esto debería funcionar:
foo(&s[0], s.size());
Sin embargo, esto requiere una nota de precaución: el resultado de &s[0]
(como resultado de s.c_str()
, BTW) solo se garantiza que sea válido hasta que se invoque cualquier función miembro que pueda cambiar la cadena. Por lo que no debe almacenar el resultado de estas operaciones en cualquier lugar. Lo más seguro es hacerlo con ellos al final de la expresión completa, como lo hacen mis ejemplos.
std::string vString;
vString.resize(256); // allocate some space, up to you
char* vStringPtr(&vString.front());
// assign the value to the string (by using a function that copies the value).
// don''t exceed vString.size() here!
// now make sure you erase the extra capacity after the first encountered /0.
vString.erase(std::find(vString.begin(), vString.end(), 0), vString.end());
// and here you have the C++ string with the proper value and bounds.
Así es como se convierte una cadena C ++ en una cadena C. Pero asegúrese de saber lo que está haciendo, ya que es muy fácil salir de los límites con funciones de cadena en bruto. Hay momentos en que esto es necesario.