strncpy que conduce a un error de segmentación

10 minutos de lectura

Solo estoy jugando con strncpy.

Mi programa se ve así

typedef struct
{
    char from_str[10];
}test;

main ()
{

    test     s1;
    memset(&s1,0,sizeof(test));
    char       src[10]="himansh";
    char       dest[10];

    memset(dest,0,10);
    src[3]='\0';

    printf("src is %s and strlen is %d \n",
            src,strlen(src));

    fflush(stdout);

    strncpy(s1.from_str,src,100);

    printf("s1.from_str is %s , src is %s \n",
            s1.from_str,src);
    return 1;

}

Aquí, antes de hacer strncpy, he agregado un carácter “\ 0” en la cadena “src”, la longitud de la cadena “src” se convierte en 3, la matriz de destino tiene un tamaño de 10. Pero en strncpy he puesto el número de bytes para copiar como 100 .

Esto significa que mi cadena de origen está terminada en NULL. Ahora, strncpy, como cualquier función de cadena, debería intentar copiar solo 3 bytes, incluso si la cantidad de bytes que proporciono es más de 3 (en este caso, 100). Hace eso, pero también tengo una falla de segmentación.

Mi resultado se muestra a continuación

src is him and strlen is 3
s1.from_str is him , src is him
Segmentation fault (core dumped)

¿Por qué está ocurriendo esta falla de segmentación aquí?

Puede alguien ayudarme aquí.

  • Lo que crees que debería intentar hacer y lo que hace son dos cosas completamente diferentes.

    -Brian Roach

    28 de diciembre de 2012 a las 6:20

strncpy que conduce a un error de segmentacion
QuiénesCraig

Podría indicarle páginas de manual, sitios web, etc., pero en última instancia, lo que importa es el estándar C en sí. Como parte de la biblioteca de tiempo de ejecución estándar, el uso y el comportamiento se definen en C99-§7.23.2.4 como:

#include <string.h>
char *strncpy(char * restrict s1,
      const char * restrict s2,
      size_t n);

Descripción
los strncpy La función copia no más de n caracteres (los caracteres que siguen a un carácter nulo no se copian) de la matriz a la que apunta s2 a la matriz a la que apunta s1. Si la copia tiene lugar entre objetos que se superponen, el comportamiento no está definido. Si la matriz a la que apunta s2 es una cadena más corta que n caracteres, se agregan caracteres nulos a la copia en la matriz a la que apunta s1, hasta que se hayan escrito n caracteres en total.

Devoluciones
los strncpy La función devuelve el valor de s1.

Hay significativo información implícita aquí, siendo la más importante: strncpy() voluntad NO termine su cadena de destino con un carácter nulo si la longitud de la cadena de origen (sin incluir su terminador de carácter nulo) cumple o supera la longitud del búfer de destino especificada).

Además, aunque está claramente especificado en el estándar (ver arriba), me sigue confundiendo cuántos ingenieros NO saben que strncpy() rellenos de cola el búfer de cadena de destino con caracteres nulos hasta la longitud especificada n se alcanza cuando la longitud de la cadena de origen es menos que el tamaño del búfer de destino. Esto lleva a la siguiente conclusión ineludible:

los strncpy() La API SIEMPRE escribirá n caracteres a la dirección a la que hace referencia el búfer de destino.

En su caso, debido a que el búfer de destino tiene solo 10 caracteres de ancho, está escribiendo 90 caracteres adicionales más allá del final definido de la memoria de escritura y, por lo tanto, entrando en la tierra de comportamiento indefinido.

En este punto, debe preguntarse “¿De qué sirve?” Ahí es un caso de uso posiblemente fundamental. Te permite copiar hasta n caracteres al búfer de destino con la previsibilidad de saber que no se sobrepasará n caracteres Período. Sin embargo, en última instancia, desea una cadena terminada en nulo, por lo que los el uso correcto es este:

char dst[ N ]; 
strncpy(dst, src, N-1);
dst[N-1] = 0;

donde N es la longitud dura de la dst búfer en caracteres y es mayor o igual que 1. Tenga en cuenta que dst podría ser un puntero de memoria asignado dinámicamente:

char *dst = malloc( N * sizeof(char) ); 
strncpy(dst, src, N-1);
dst[N-1] = 0;

Con lo anterior, usted siempre tener una cadena terminada en cero en dst. Si la cadena de origen longitud es menor que la longitud del búfer de destino especificada, strncpy() completará el resto del búfer con caracteres nulos hasta que un total de caracteres de origen copiados + caracteres nulos llenos de cola sea igual n, y la declaración final es redundante. Si la longitud de la cadena de origen es igual o mayor que la longitud del búfer de destino, strncpy() dejará de copiar una vez N-1 se alcanzan los caracteres y la declaración final establece un carácter nulo al final del búfer. Esto da como resultado una cadena de prefijo “recortada” de la fuente original, pero lo más importante es que garantiza que NO excederá los límites de su búfer de destino con una llamada API de cadena posterior que busca un terminador.

La utilidad de la técnica anterior es siempre discutible. Soy un chico de C++, así que std::string salva a mi yo feliz de toda esta locura. Pero la realidad es esta: A veces te importa si src no se copia en su totalidad para dst; a veces no lo haces. la utilidad es muy dependiente situacionalmente. Para presentar datos de cadena en una interfaz de usuario, esto (probablemente) no importará. Para copiar una cadena que se usará para datos críticos, una subcadena de prefijo parcial no será aceptable. Cuando la policía emita una orden de arresto para “Joseph Johnson Jr.”, habrá algunas explicaciones que hacer cuando su padre (“Joseph Johnson”) sea llevado a la cárcel porque el búfer de nombres del software de emisión de órdenes solo tenía 15 caracteres. .

Dicho todo esto, su falla de segmentación se reduce a esta declaración:

strncpy(s1.from_str,src, 100); // length parameter is wrong.

Recuerde la declaración en negrita anterior: strncpy() SIEMPRE escribiré n caracteres a la dirección a la que hace referencia el búfer de destino”.. Esto significa que el código anterior siempre escriba 100 caracteres en el búfer de destino, que en su caso tiene solo 10 caracteres de ancho, por lo tanto, un comportamiento indefinido y probable ker-boom.

Rectifique esto haciendo lo siguiente si el búfer de destino es una matriz de caracteres de longitud fija:

strncpy(s1.from_str,src, sizeof(s1.from_str)/sizeof(s1.from_str[0])-1);
s1.from_str[ sizeof(s1.from_str)/sizeof(s1.from_str[0])-1 ] = 0;

Consulte el uso anterior para saber cómo hacer esto para cadenas dinámicas de longitud `N caracteres.

  • Gracias @WhozCraig… muy detallado y descriptivo… Solo estaba jugando con strncpy, sé cómo usar strncpy de manera segura. Solo quería saber si la cadena ‘src’ termina en NULL, entonces cuántos caracteres se copian en la cadena ‘dest’ si ‘n’ es más grande que el tamaño de la cadena ‘src’ y el tamaño de la cadena ‘dest’ es lo suficientemente grande para contener Cadena ‘src’ pero más pequeña que ‘n’. La descripción de la página MAN de strncpy no fue lo suficientemente clara para mí.

    – Himanshu Gupta

    28 de diciembre de 2012 a las 10:58

  • strncpy es para archivar en campos de tamaño fijo previsiblemente. Está no una “función de manejo de cadenas”.

    – vonbrand

    20 de enero de 2013 a las 18:20

strncpy que conduce a un error de segmentacion
Abhijit

Desde http://www.cplusplus.com/reference/cstring/strncpy/

char * strncpy (char * destino, const char * fuente, size_t num);

Copiar caracteres de la cadena Copia los primeros números de caracteres del origen al destino. Si se encuentra el final de la cadena C de origen (que se indica mediante un carácter nulo) antes de que se haya copiado el número de caracteres, el destino se rellena con ceros hasta que se haya escrito un total de números de caracteres.

Entonces, aunque la longitud de la cadena de origen es menor que el tamaño del búfer de destino, debido al comportamiento de paso de strncpy, intenta superponer el resto de los caracteres más allá del tamaño del búfer de destino, lo que provoca una falla de segmentación.

En lugar de copiar más allá de los 100 caracteres, el tamaño debe ser igual al tamaño máximo permitido en el búfer de destino, por lo que podría haber escrito

strncpy(s1.from_str,src,sizeof(s1.from_str)/sizeof(s1.from_str[0]) - 1); Actual size -1 to accomodate the null terminator 

o mejor escribir un _countof macro

#define _countof(s) (sizeof(s)/sizeof(s[0]))
................
strncpy(s1.from_str,src,_countof(s1.from_str) - 1);

  • Esta falla de segmento está ocurriendo en una máquina LINUX, pero no está ocurriendo en una máquina UNIX diferente. Porque ?

    – Himanshu Gupta

    28 de diciembre de 2012 a las 6:23

  • @HimanshuGupta: escribir más allá de la memoria asignada es un comportamiento indefinido (UB) y la falla de segmentación es una de las muchas UB incluyendo demonios saliendo de tu nariz

    – Abhijit

    28 de diciembre de 2012 a las 6:25


  • @HimanshuGupta: si la respuesta ayudó, intente votar y aceptar la respuesta

    – Abhijit

    28 de diciembre de 2012 a las 7:45

  • @HimanshuGupta: Lo que sucede debajo del capó es que strncpy también escribe sobre lo que viene después de que el lugar se copió. Lo que podría ser depende de las variables que defina, cómo su compilador distribuye los datos en la memoria, si elimina algunas variables porque sabe que no se usan (si es así, depende de los indicadores de optimización), … y finalmente en exactamente lo que se sobrescribe (¿dirección de retorno?) y cómo se interpretan los bytes escritos allí (si es una dirección de retorno, podría ser una dirección de instrucción ilegal, aterrizar en medio de un do-do profundo o ser inofensivo).

    – vonbrand

    20 de enero de 2013 a las 18:26

Ver: http://www.manpagez.com/man/3/strncpy/

Las funciones stpncpy() y strncpy() copian como máximo n caracteres de s2 a s1. Si s2 tiene menos de n caracteres, el resto de s1 se rellena con caracteres `\0′. De lo contrario, s1 no se termina.

El resto se llena….

Entonces:

strncpy( s1.from_str, src, 10 );

  • pero aquí el tamaño de la cadena src es menor que el de la cadena dest y n es mayor que el tamaño de la cadena src y dest.

    – Himanshu Gupta

    28 de diciembre de 2012 a las 6:18

  • @icepack porque se sobrescriben 90 bytes después de from_str (memoria que posiblemente no le pertenezca). Y luego depende de la configuración/SO del compilador. … que pasa

    – Mario La Cuchara

    28 de diciembre de 2012 a las 6:20

  • Eso es correcto, pero la respuesta no especifica nada de esto, es solo una copia de la referencia.

    – Un nombre de usuario ingenioso

    28 de diciembre de 2012 a las 6:20

  • Solo estoy bromeando. Esto está sucediendo en una máquina LINUX, pero no recibo ninguna falla de segmento en otra máquina UNIX.

    – Himanshu Gupta

    28 de diciembre de 2012 a las 6:26

strncpy(s1.from_str,src,100);

porque estas usando 100 en su función, from_str y src tienen asignados 10 bytes consecutivos, pero está copiando 100 bytes, lo que conduce a seg. culpa.

usar así,

strncpy(s1.from_str,src,10);

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad