2009-10-21 9 views
5

Estoy tratando de entender las diferencias/desventajas de strcpy y strncpy. Puede alguien por favor ayuda:strcpy cuando el buffer de dest es más pequeño que el buffer de src

void main() 
{ 
char src[] = "this is a long string"; 
char dest[5]; 

strcpy(dest,src) ; 
printf("%s \n", dest); 
printf("%s \n", src); 

} 

La salida es:

this is a long string 
a long string 

PREGUNTA: No entiendo, ¿cómo consiguió modificar la picadura fuente. De acuerdo con la explicación, strcpy debe mantener la copia hasta que se encuentra con un '\ 0', por lo que hace, pero ¿cómo es que "cadena src' Se modificó.

Por favor explique.

+0

Esto se conoce como buffer Overun. – lsalamon

+0

Este problema de desbordamiento de búfer ilustra por qué debe elegir usar strncopy sobre strcpy. –

+0

No pude reproducir su código. Obtengo 'tring' en la matriz de dest. – Spidey

Respuesta

11

La respuesta fácil es que tiene (con esa llamada strcpy()) hecho algo fuera de las especificaciones del sistema, y ​​por lo tanto sufre de un comportamiento indefinido.

La respuesta más difícil consiste en examinar el diseño de la memoria concreta en su sistema, y ​​cómo strcpy() funciona internamente.Probablemente es algo como esto:

 N+28 "g0PP" 
    N+24 "trin" 
    N+20 "ng s" 
    N+16 "a lo" 
    N+12 " is " 
src N+08 "this" 
    N+04 "DPPP" 
dest N+00 "DDDD" 

Las letras representan D bytes en dest, las letras P son bytes de relleno, los 0 personajes son caracteres ASCII NUL utilizados como terminadores de cadena.

Ahora strcpy (dest, src) va a cambiar el contenido de la memoria un poco (suponiendo que maneja correctamente las áreas de memoria que se solapan):

 N+28 "g0PP" 
    N+24 "trin" 
    N+20 "g0 s" 
    N+16 "trin" 
    N+12 "ng s" 
src N+08 "a lo" 
    N+04 " is " 
dest N+00 "this" 

es decir, mientras dest ahora "contiene" la cadena completa "esta es una cadena larga" (si cuenta la memoria desbordada), src ahora contiene una cadena terminada en NUL completamente diferente "una cadena larga".

7

Este es un desbordamiento de memoria, e indefinido . el comportamiento

en su caso, parece que el compilador ha colocado dest y src secuencialmente en la memoria. Cuando se copia desde src a dest, continúa copiando allá del final de dest y sobrescribe parte de src.

+0

Puede ser más descriptivo. Permítanos considerar que mi dest y src son secuenciales en la memoria. Por lo tanto, deben comenzar desde la ubicación 1000 (por ejemplo) .. Entonces dest toma 1000-1004 (5 bytes) y src toma 22 bytes (21 caracteres + terminación nula). Así que hemos utilizado un total de 27 bytes 1000 hasta 1026. Si lo que he mencionado (en términos de memoria) es correcto, ¿puede explicar en detalle cómo se sobrescribió el src? – user193891

+2

Y src y dst parecen estar alineados con múltiplos de 4 caracteres, por lo que con un destino de 5 caracteres de longitud, el nuevo src mutilado iniciará 8 caracteres en el src original (que ahora es dest). – ndim

+0

¿Puedes explicar el mapa de memoria para que sea más fácil de entender? solo suponga que toda la memoria asignada comienza desde la ubicación 1000 ... ¿puede explicar los espacios ocupados por dest y src antes y después de strcpy? – user193891

1

con gran simpatía, la cuerda son vecinos exactos. Entonces, en su caso, puede tener esta imagen

dst | | | | | src | | | | | |

por lo que comienza a escribir y sucede que los campos de src se sobrescriben.

Howerver seguramente no podrá confiar en él. Todo puede pasar, lo que tienes es un comportamiento indefinido. Entonces, puede suceder algo más en otra computadora en otro momento y/u otras opciones.

Saludos Friedrich

0

que sugieren una lectura rápida de:

http://en.wikipedia.org/wiki/Strncpy#strncpy

que muestra las diferencias. Esencialmente, strncpy le permite especificar una cantidad de bytes para copiar, lo que significa que la cadena resultante no necesariamente termina en nulo.

Ahora, cuando usa strcpy para copiar una cadena sobre otra, no comprueba el área resultante de la memoria para ver si es lo suficientemente grande, no sostiene su mano en ese sentido. Comprueba el carácter nulo en la cadena src.

Por supuesto, dst en este ejemplo tiene solo 5 bytes. ¿Así que lo que ocurre? Sigue escribiendo, hasta el final de dest y más allá de él en la memoria. Y en este caso, la siguiente parte de la memoria en la pila es su cadena src. Entonces, aunque su código no está copiándolo intencionalmente, el diseño de los bytes en la memoria junto con la escritura pasada la finalización de dst ha causado esto.

Espero que ayude!

1

Su código provocó un desbordamiento del búfer, copiando para destilar más caracteres de los que puede contener. Los caracteres adicionales se escribieron en otro lugar de la pila, en su caso, a donde apuntaba src.

Necesita usar la función strncpy().

0

O yo estoy malentendido su pregunta, o le esté malentendido strcpy:

PREGUNTA: No entiendo, ¿cómo consiguió modificar la picadura fuente. Según explicación, strcpy debe mantener copiado hasta que se encuentra con un '\ 0', por lo lo hace, pero ¿cómo es que "cadena src' Se modificado.

Me suena como que está esperando strcpy para dejar de copiar en dest cuando llega al final de dest, basado en ver un caracter \0. Esto no es lo que hace. Strcpy copia en el destino hasta que llega al final de la cadena fuente, delimitada por un caracter \0. Supone que asignó suficiente memoria para la copia. Antes de la copia, el búfer de destino podría contener cualquier cosa, incluidos todos los valores nulos.

strncpy resuelve esto haciendo que digas en realidad cuán grande es el búfer en el que estás copiando, por lo que puedes evitar casos en los que se copia más de lo que cabe.

1

Como nota adicional, tenga en cuenta que la función strncpy no es la función correcta para usar cuando necesite realizar copias con protección de desbordamiento del búfer. Esta función no está diseñada para ese propósito y nunca ha sido diseñada para ese propósito. strncpy es una función que se creó hace mucho tiempo para realizar algunas copias de cadenas muy específicas de la aplicación dentro de un sistema de archivos muy específico en alguna versión anterior de UNIX. Desafortunadamente, los autores de la biblioteca lograron "aislar" el nombre que suena genérico strncpy para usar para un propósito muy específico. Fue preservado para fines de compatibilidad con versiones anteriores. Y ahora, tenemos una o dos generaciones de programadores que hacen suposiciones sobre el propósito de strncpy basándose únicamente en su nombre y, por lo tanto, lo usan incorrectamente. En realidad, strncpy tiene muy poco o ningún uso significativo en absoluto.

La biblioteca estándar C (al menos su versión C89/90) no ofrece ninguna función de copia de cadenas con protección de desbordamiento de búfer. Para realizar dicha copia protegida, debe usar alguna función específica de la plataforma, como strlcpy, strcpy_s o escribir una usted mismo.

P.S. Este thread en StackOverflow contiene una buena discusión sobre el propósito real strncpy fue desarrollado para. Vea esto post específicamente para la explicación precisa de su función en el sistema de archivos UNIX. También, vea here para un buen artículo sobre cómo llegó a ser strncpy.

Una vez más, strncpy es una función para copiar un tipo de cuerda completamente diferente: cadena de longitud fija. Ni siquiera está destinado a ser utilizado con cadenas tradicionales terminadas en nulo estilo C.

+0

Encuentro strncpy útil decir si tengo un búfer y estoy leyendo líneas de un archivo de texto que sé que será

+0

@James Morris: No veo exactamente lo que estás tratando de lograr usando 'strncpy' allí. ¿Qué función de 'strncpy' es importante para ti en este caso? – AnT

+0

Esta respuesta de esa manera no es correcta. Strncpy seguramente no sobrepasa un buffer si tiene a) tiene el espacio adecuado para el "String" b) lo hace bien con la longitud. Para eso, probablemente todos utilicen mejor el siguiente código (pseudo-C, parcialmente tomado de Code Complete II) char buf [MAX_LEN + 1]; strncpy (buf, src, MAX_LEN); En ese caso, strncpy es más seguro que strcpy. Pero tiene razón, no hay una función en el estándar C que proteja el exceso de "buffer". Así es como se implementó C, velocidad, velocidad, velocidad – Friedrich

Cuestiones relacionadas