Quiero copiar una cadena en una matriz de caracteres y no sobrecargar el búfer.
Entonces, si tengo una matriz de caracteres de tamaño 5, entonces quiero copiar un máximo de 5 bytes de una cadena en ella.
¿Cuál es el código para hacer eso?
Esto es exactamente lo que std::string
La función de copia de sí lo hace.
#include <string>
#include <iostream>
int main()
{
char test[5];
std::string str( "Hello, world" );
str.copy(test, 5);
std::cout.write(test, 5);
std::cout.put('\n');
return 0;
}
Si necesita una terminación nula, debe hacer algo como esto:
str.copy(test, 4);
test[4] = '\0';
-
buena solución pero no hoy en día ya no está libre de advertencias:
warning C4996: 'std::basic_string<_Elem,_Traits,_Alloc>::copy': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'
– mtijn
15/10/2014 a las 12:57
-
@PaulWilliams que se afirma en la última parte de la respuesta.
– luizfls
24 de agosto de 2019 a las 22:38
-
La terminación nula debe aparecer justo después del final de la copia, no al final del búfer copiado. Si el búfer de destino ya tenía contenido, tendrá basura en la cadena de salida.
– Alberto
16 de septiembre de 2020 a las 11:52
-
La forma generalizada de terminar el búfer de chat es “` const size_t LEN = 5; prueba de carbonización[LEN]; size_t len = str.copy(prueba, LEN-1); prueba[len] = ‘\0’; “`
– Zeppe
6 de noviembre de 2021 a las 17:01
ataúd de jerry
Ante todo, strncpy
es casi seguro no Lo que quieras. strncpy
fue diseñado para un propósito bastante específico. Está en la biblioteca estándar casi exclusivamente porque ya existe, no porque sea útil en general.
Probablemente la forma más sencilla de hacer lo que quieres es con algo como:
sprintf(buffer, "%.4s", your_string.c_str());
A diferencia de strncpy
esto garantiza que el resultado terminará en NUL, pero no completa datos adicionales en el destino si la fuente es más corta que la especificada (aunque esto último no es un problema importante cuando la longitud del destino es 5).
-
+1 para respuesta única. Pero, ¿no es esto una gran cantidad de gastos generales innecesarios en relación con
strncpy(buffer, str.c_str(), 4); buffer[4] = '\0';
?– robot académico
22 mayo 2010 a las 19:38
-
@academicRobot: ¿Lo ha probado o ha notado la diferencia? 🙂 prefiero el
sprintf
solución, es un poco más sencillo. Solo cuando falta el rendimiento, perfilaría, tal vez encuentre que esto es un problema, pruébelo constrncpy
y tal vez encuentre que funciona mejor.– GManNickG
22 de mayo de 2010 a las 19:46
-
Prefiero la versión segura,
snprintf
que le permite especificar el tamaño del búfer de destino.– jweyrich
22 de mayo de 2010 a las 19:48
-
@academicRobot: En general, si
strncpy
es más rápido o más lento dependerá de los tamaños relativos de la cadena de origen y el búfer de destino. Ya questrncpy
hace mucho trabajo desperdiciado en caso de un búfer grande, en general en caso de mal usostrncpy
no es sólo Más lentopero catastrópicamente más lento, órdenes de magnitud más lento. Lo único que salva el día en este ejemplo es un búfer de destino increíblemente pequeño (solo 5 caracteres).– AnT apoya a Rusia
22 mayo 2010 a las 20:36
-
@NicolBolas: Esto es anterior a C ++ 11, por lo que
snprintf
no era parte de C++ en ese momento. Aun así, especificar la precisión como se hace aquí limita la cantidad de datos que se pueden escribir en el búfer, lo que evita que se desborde el búfer (a menos que especifique un tamaño mayor que el búfer, y si lo hace,snprintf
tampoco evitará una saturación del búfer.– Jerry Ataúd
9 de marzo de 2013 a las 5:01
AnT apoya a Rusia
Usar función enlace roto y material no encontrado en el sitio de destino si su implementación proporciona uno (la función no está en la biblioteca C estándar), sin embargo, es ampliamente aceptado como un nombre estándar de facto para una función de copia de longitud limitada “segura” para cadenas terminadas en cero.strlcpy
Si su implementación no proporciona strlcpy
función, implemente uno usted mismo. Por ejemplo, algo como esto podría funcionar para usted
char *my_strlcpy(char *dst, const char *src, size_t n)
{
assert(dst != NULL && src != NULL);
if (n > 0)
{
char *pd;
const char *ps;
for (--n, pd = dst, ps = src; n > 0 && *ps != '\0'; --n, ++pd, ++ps)
*pd = *ps;
*pd = '\0';
}
return dst;
}
(En realidad, el de facto aceptado strlcpy
devoluciones size_t
por lo que es posible que prefiera implementar la especificación aceptada en lugar de lo que hice anteriormente).
Cuidado con las respuestas que recomiendan usar strncpy
para ese propósito. strncpy
no es una función segura de copia de cadenas de longitud limitada y no se supone que se use para ese propósito. Mientras puedas forzar strncpy
para “trabajar” para ese propósito, todavía es similar a clavar tornillos para madera con un martillo.
-
La limitación con esto es que en algunos casos deberías detectar que hubo un desbordamiento de búfer. Sería más interesante devolver el tamaño de copia en lugar de dst que ya se conoce. En ese caso, uno puede manejar el error cuando copy_size > n o saber cuánto del búfer se usa.
– Alberto
16 de septiembre de 2020 a las 11:57
académicoRobot
Actualizar: Pensé en tratar de unir algunas de las respuestas, respuestas que me han convencido de que mi propia respuesta instintiva original fue pobre.
En primer lugar, como señaló AndreyT en los comentarios a esta pregunta, los métodos de truncamiento (snprintf, strlcpy y strncpy) a menudo no son una buena solución. A menudo es mejor verificar el tamaño de la cadena string.size()
contra la longitud del búfer y devolver/lanzar un error o cambiar el tamaño del búfer.
Si el truncamiento está bien en su situación, en mi humilde opinión, strlcpy es la mejor solución, ya que es el método más rápido y con menos gastos generales que garantiza una terminación nula. Desafortunadamente, no está en muchas/todas las distribuciones estándar y, por lo tanto, no es portátil. Si está haciendo muchos de estos, tal vez valga la pena proporcionar su propia implementación, AndreyT dio un ejemplo. Se ejecuta en O(longitud del resultado). Además, la especificación de referencia devuelve la cantidad de bytes copiados, lo que puede ayudar a detectar si la fuente se truncó.
Otras buenas soluciones son correr y snprintf. Son estándar, por lo que son portátiles y proporcionan un resultado terminado en nulo seguro. Tienen más gastos generales que strlcpy (analizando el especificador de cadena de formato y la lista de argumentos variables), pero a menos que esté haciendo muchos de estos, probablemente no notará la diferencia. También se ejecuta en O(longitud del resultado). snprintf siempre es seguro y ese sprintf puede desbordarse si obtiene el especificador de formato incorrecto (como han notado otros, la cadena de formato debe ser "%.<N>s"
no "%<N>s"
). Estos métodos también devuelven el número de bytes copiados.
Una solución de caso especial es fuerte. Se ejecuta en O(longitud del búfer), porque si llega al final del src, pone a cero el resto del búfer. Solo es útil si necesita poner a cero la cola del búfer o está seguro de que las longitudes de las cadenas de origen y destino son las mismas. También tenga en cuenta que no es seguro ya que no necesariamente anula la terminación de la cadena. Si la fuente está truncada, no se agregará nulo, por lo tanto, llame en secuencia con una asignación nula para garantizar la terminación nula: strncpy(buffer, str.c_str(), BUFFER_LAST); buffer[BUFFER_LAST] = '\0';
Algunas buenas versiones de libc proporcionan un reemplazo no estándar pero excelente para strcpy(3)
/strncpy(3)
– strlcpy(3)
.
Si el tuyo no lo tiene, el código fuente está disponible gratuitamente aquí desde el OpenBSD repositorio.
tkanzakic
void stringChange(string var){
char strArray[100];
strcpy(strArray, var.c_str());
}
Supongo que esto debería funcionar. copiará la cadena de formulario en una matriz de caracteres.
cuerpo oscuro
creo que snprintf() es mucho más seguro y más simple
snprintf ( buffer, 100, "The half of %d is %d", 60, 60/2 );
el carácter nulo se agrega y finaliza automáticamente 🙂
std::string, no conozco ningún otro tipo de cadenas.
– neuromante
22 de mayo de 2010 a las 19:14
Hay cadenas de caracteres, un puñado de cadenas de bibliotecas más o menos conocidas y un número incalculable de implementaciones locales.
– Peter – Reincorporar a Mónica
13 de julio de 2020 a las 1:53