Cómo copiar una cadena en una matriz de caracteres en C ++ sin pasar por el búfer

8 minutos de lectura

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?

  • 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

Esto es exactamente lo que std::stringLa 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


Avatar de usuario de Jerry Coffin
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 strncpyesto 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 con strncpyy tal vez encuentre que funciona mejor.

    – GManNickG

    22 de mayo de 2010 a las 19:46


  • Prefiero la versión segura, snprintfque 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 que strncpy hace mucho trabajo desperdiciado en caso de un búfer grande, en general en caso de mal uso strncpy 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 destaca con el avatar de usuario de Rusia
AnT apoya a Rusia

Usar función strlcpyenlace 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.

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_tpor 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

avatar de usuario de academicRobot
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.

avatar de usuario de tkanzakic
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.

Avatar de usuario de Dark Corp
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 🙂

¿Ha sido útil esta solución?