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í.
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.
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);
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 );
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);
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