Diferencia entre memcpy y memmove
Resuelto
leoliom
Mensajes publicados
187
Estado
Miembro
-
leoliom Mensajes publicados 187 Estado Miembro -
leoliom Mensajes publicados 187 Estado Miembro -
Hola, he leído muchos documentos, he visto muchos ejemplos pero es imposible entender las cosas de superposición y otras. Quiero entender de tal manera que pueda prever lo que el programa me mostrará
Configuración: iPad / Chrome 98.0.4758.97
Configuración: iPad / Chrome 98.0.4758.97
Enlaces relacionados:
- [C] Extraer parte entera y parte decimal
- Lenguaje C: %d, %ls y %x
- La différence entre ' et " est que ' représente une apostrophe ou une citation simple, tandis que " est l'entité HTML pour les guillemets doubles.
- generador de consonantes y vocales al azar
- Diagonal principal y diagonal secundaria de una matriz
9 respuestas
jeannets
Mensajes publicados
28379
Fecha de registro
Estado
Colaborador
Última intervención
Ambassadeur
6 600
Hola,
Memcpy es una copia de memoria en otra dirección, sin destruir el original
https://man7.org/linux/man-pages/man3/memcpy.3.html
Mientras que Memmove es un desplazamiento de memoria, a diferencia de Memcpy, borra la fuente..
https://www.man7.org/linux/man-pages/man3/memmove.3.html
Los atributos definen la fuente, el destino y el tamaño de los valores desplazados o copiados...
Por supuesto, para que todo esté sincronizado, hay que conocer la lección y los valores en movimiento. Hacer ejemplos en papel cuadriculado..
Memcpy es una copia de memoria en otra dirección, sin destruir el original
https://man7.org/linux/man-pages/man3/memcpy.3.html
Mientras que Memmove es un desplazamiento de memoria, a diferencia de Memcpy, borra la fuente..
https://www.man7.org/linux/man-pages/man3/memmove.3.html
Los atributos definen la fuente, el destino y el tamaño de los valores desplazados o copiados...
Por supuesto, para que todo esté sincronizado, hay que conocer la lección y los valores en movimiento. Hacer ejemplos en papel cuadriculado..
He leído también este sitio, pero no entendí. Como ustedes dicen, la única forma de entender es a través de un esquema, pero yo no sé, me cuesta un poco.
Quizás un pequeño ejemplo me ayude a comprender mejor.
Quizás un pequeño ejemplo me ayude a comprender mejor.
Las 2 funciones solo se distinguen en el caso de que haya superposición. Es cuando hay celdas que están a la vez en la fuente a copiar y en el destino.
Ejemplo, quieres copiar las 4 primeras celdas de la siguiente tabla en las 4 últimas:
Si utilizas
Si utilizas
Así que si no hay superposición, las funciones son equivalentes (pero
Ejemplo, quieres copiar las 4 primeras celdas de la siguiente tabla en las 4 últimas:
+---+---+---+---+---+---+---+
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
+---+---+---+---+---+---+---+
Si utilizas
memmove()obtendrás el siguiente resultado (las 4 últimas reciben correctamente lo que había en las 4 primeras)
+---+---+---+---+---+---+---+
| 1 | 2 | 3 | 1 | 2 | 3 | 4 |
+---+---+---+---+---+---+---+
Si utilizas
memcpy(), esta función es un poco "tonta", va rápido pero no "piensa" mucho. ¡Puede darte el siguiente resultado:
+---+---+---+---+---+---+---+Es una suposición, intenta entender lo que se perdió y trata de escribir un código que lo haga, o intenta escribir tú mismo una función
| 1 | 2 | 3 | 1 | 2 | 3 | 1 |
+---+---+---+---+---+---+---+
memcpy()y observa por qué el final no es correcto.
Así que si no hay superposición, las funciones son equivalentes (pero
memcpy()es más rápida), si hay superposición la función
memcpy()puede tener un resultado incorrecto.
According to your example:
Is it correct?
I didn't understand the sentence It's when some elements are both in the source to copy and in the destination.
For example in your example, for which number is there an overlap?
int tab[10] = {1, 2, 3, 4, 5, 6, 7}; int tab2[10]; strncpy(tab2,tab1,4); memmove(tab + 3, tab2, strlen(tab)) memcpy(tab + 3, tab2, strlen(tab)) Is it correct?
I didn't understand the sentence It's when some elements are both in the source to copy and in the destination.
For example in your example, for which number is there an overlap?
No has entendido, de hecho. Solo hay un único array y se hacen copias dentro del array. Si hay dos arrays, entonces
Y
Mi ejemplo es:
memcpy()y
memmove()son indistinguibles.
Y
strncpy()y
strlen()son funciones que se aplican a cadenas de caracteres. Aquí son arrays de enteros, no tienen nada que ver y estas funciones hacen locuras en tu código.
Mi ejemplo es:
int tab[7] = {1, 2, 3, 4, 5, 6, 7}; memmove( &tab[3], &tab[0], 4*sizeof(int) ); // copiar tab[0]tab[1]tab[2]tab[3] en tab[3]tab[4]tab[5]tab[6]. for ( int i = 0 ; i < 7 ; ++i ) printf( "%d ", tab[i] );
Creo que está bien, he comprendido la sutileza entre los dos, me tomó mucho tiempo antes de entender
Gracias
Gracias
Bonjour,
Para entender el funcionamiento de
Ejemplo :
Si tomo otra implementación en Internet :
No entiendo, su implementación en C me parecía correcta. ¿Qué está mal? ¿Qué le falta a estas funciones para que hagan el mismo trabajo que
Para entender el funcionamiento de
memcpyy
memmove, he revisado su implementación en C, pero curiosamente no siempre hacen lo mismo. Para
memmove, funciona, pero no para
memcpy.
Ejemplo :
#include <stdio.h> #include <string.h> void * Memcpy(void* dst, const void* src, unsigned int cnt) { char *pszDest = (char *)dst; const char *pszSource =( const char*)src; if((pszDest!= NULL) && (pszSource!= NULL)) { while(cnt) //hasta cnt { //Copiar byte por byte *(pszDest++)= *(pszSource++); --cnt; } } return dst; } int main(void){ char chaine[7] = "aabbcc"; Memcpy(chaine + 2, chaine, 4); printf("%s\n", chaine); return 0; } -
Memcpy
devuelveaaaaaa
; -
memcpy
devuelveaaaabb
.
Si tomo otra implementación en Internet :
#include <string.h> #include <stdio.h> void myMemCpy(void *dest, void *src, size_t n){ // Convertir las direcciones de src y dest a (char *) char *csrc = (char *)src; char *cdest = (char *)dest; // Copiar el contenido de src[] a dest[] for (int i = 0; i < n; i++) cdest[i] = csrc[i]; } int main(void){ char str1[7] = "aabbcc"; myMemMove(str1 + 2, str1, 4); printf("New string: %s\n", str1); return 0; } -
mymencpy
devuelveaaaaaa
; -
memcpy
devuelveaaaabb
.
No entiendo, su implementación en C me parecía correcta. ¿Qué está mal? ¿Qué le falta a estas funciones para que hagan el mismo trabajo que
memcpy?
Hola,
¿Qué hacen
De manera general, basta con mirar lo que dicen
¿Qué pasa si los bloques se superponen?
Ahora, veamos con más detalle qué sucede si el bloque fuente y el bloque destino se superponen. Aquí, hay que ser cuidadoso, ya que puedes temer efectos secundarios (típicamente si escribes en el área que estás a punto de leer):
¿Por qué existe una función
Hay varias razones, y antes de comenzar es importante entender cómo se almacena una cadena de características en memoria. El problema de fondo es que una cadena de caracteres puede ser arbitrariamente larga (a diferencia de un
La elección que se ha hecho es marcar la cadena con un carácter terminal
Si volvemos a
Como
Regreso a tu código
En tu caso, dado que manipulas cadenas, no es suficiente copiar las letras para que funcione bien, hay que asegurarse de que la cadena que vas a copiar o que vas a mostrar tenga su carácter terminal
Buena suerte
¿Qué hacen
memmovey
memcpy?
De manera general, basta con mirar lo que dicen
man memmovey
man memcpy(que puedes buscar en Google o en un terminal si estás en Linux)
-
memcpy
copia un bloque de memoria de una dirección a otra dirección. El bloque de destino debe estar preasignado en memoria para recibir el bloque fuente, de lo contrario, generalmente obtendrás un error de segmentación. La copia se realiza típicamente byte a byte (y para recordar, un carácter ASCII (char
) ocupa un byte, por lo que esta función es muy similar astrcpy
y, por lo tanto, se encuentra en<string.h>
): leemos el byte fuente actual, lo copiamos en el byte de destino correspondiente y repetimos la operación hasta haber tratado todo el bloque. - Oficialmente,
memmove
mueve un bloque de memoria de una dirección a otra dirección. El bloque de destino debe estar preasignado en memoria para recibir el bloque fuente, de lo contrario, generalmente obtendrás un error de segmentación. No hay ninguna garantía sobre lo que quedará en el bloque de origen, pero la mayoría de las implementaciones simplemente lo dejan tal como está para mejorar el rendimiento (y para estas implementaciones,memmove
hace exactamente lo mismo quememcpy
cuando los bloques fuente y destino no se superponen). En estas situaciones, usamos másmemmove
por la legibilidad del programa. Sin embargo, el bloque fuente ya no debe ser leído porque dependiendo de la implementación, puede haber sido reinicializado.
¿Qué pasa si los bloques se superponen?
Ahora, veamos con más detalle qué sucede si el bloque fuente y el bloque destino se superponen. Aquí, hay que ser cuidadoso, ya que puedes temer efectos secundarios (típicamente si escribes en el área que estás a punto de leer):
- Según esta página,
memmove
utiliza un búfer intermedio para protegerse de estos efectos secundarios. - Según esta página, este no es el caso de
memcpy
, por lo que hay que tener cuidado con lo que se hace.
¿Por qué existe una función
strcpyy
memcpy?
Hay varias razones, y antes de comenzar es importante entender cómo se almacena una cadena de características en memoria. El problema de fondo es que una cadena de caracteres puede ser arbitrariamente larga (a diferencia de un
uint32_tque por definición ocupa exactamente 32 bits o 4 bytes). ¿Cómo hacer un seguimiento del tamaño?
La elección que se ha hecho es marcar la cadena con un carácter terminal
'\0'(que corresponde al
uint8_t
0. Todas las funciones
str*(
strcpy,
strlen, ...) y
printfse apoyan en este carácter terminal para saber cuándo detenerse. Esto significa que la cadena
"abc"ocupa 4 bytes
{'a', 'b', 'c', '\0'} y no 3 como podría pensarse. Esto significa que no se debe olvidar este famoso carácter terminal cada vez que se manipulan cadenas. Sin él, las funciones str*seguirán buscando (por suerte) un byte que valga 0 y que a menudo está fuera de un área de memoria asignada, lo que provoca un error de segmentación.
Si volvemos a
memcpy, nos damos cuenta de que podemos reproducir
strcpysiempre y cuando conozcamos la longitud de la cadena a copiar (sin olvidar su
'\0'terminal).
Como
memcpyestá diseñada para manipular un bloque de memoria arbitrario -de ahí el tipo
const void *para el bloque fuente (solo lectura) y el tipo
void *para el bloque destino (lectura y escritura)- (en particular, algo que no es una cadena y por lo tanto, algo que no necesariamente está terminado por
'\0'), se debe indicar cuántos bytes copiar. Ese es el papel de su tercer parámetro.
Regreso a tu código
En tu caso, dado que manipulas cadenas, no es suficiente copiar las letras para que funcione bien, hay que asegurarse de que la cadena que vas a copiar o que vas a mostrar tenga su carácter terminal
'\0'. Eso es algo que garantiza
strcpy, pero no lo hace
memcpy.
Buena suerte
Ah, entonces las implementaciones de estas funciones no son buenas porque no se tiene en cuenta el carácter terminal de fin de cadena
¿Debo modificar el código para que añada este carácter al final de la copia para que funcione?
¿Debo modificar el código para que añada este carácter al final de la copia para que funcione?
>>> Ah, entonces las implementaciones de estas funciones no son buenas porque no se tiene en cuenta el carácter terminal de fin de cadena.
No. ¿Has visto en alguna parte que memcpy() debía poner un terminador de cadena?
>> ¿Debo modificar el código para que añada al final de la copia este carácter para que funcione?
No.
La función memcpy(), la función mymemcpy() y la función Memcpy() son las 3 conformes.
La norma dice:
- si no hay solapamiento, la función debe copiar (puedes verificar que las 3 funciones efectúan bien la copia).
- si hay solapamiento, el resultado es totalmente impredecible (así que el resultado es completamente aleatorio, ¡no tiene sentido comparar los resultados en este caso!)
Es totalmente posible que la función memcpy() sea diferente a sí misma si cambias el contexto.
No. ¿Has visto en alguna parte que memcpy() debía poner un terminador de cadena?
>> ¿Debo modificar el código para que añada al final de la copia este carácter para que funcione?
No.
La función memcpy(), la función mymemcpy() y la función Memcpy() son las 3 conformes.
La norma dice:
- si no hay solapamiento, la función debe copiar (puedes verificar que las 3 funciones efectúan bien la copia).
- si hay solapamiento, el resultado es totalmente impredecible (así que el resultado es completamente aleatorio, ¡no tiene sentido comparar los resultados en este caso!)
Es totalmente posible que la función memcpy() sea diferente a sí misma si cambias el contexto.
char str1[7] = "aabbcc"; char str2[7] = "aabbcc"; memcpy(str1 + 2, str1, 4); printf("Nueva cadena: %s\n", str1); memcpy(str2 + 2, str2, 4); printf("Nueva cadena: %s\n", str2);Este código puede devolver 2 resultados diferentes con aparentemente los mismos datos de entrada, o tener un resultado diferente en la versión de depuración y en la versión de liberación , inténtalo. Es inútil querer reproducir lo que ves en el caso en que la función tiene un resultado indefinido!
Para completar lo que dice Dalfab:
- las funciones
str*
suponen que el bloque de memoria a copiar es de tamaño arbitrario pero puede considerarse como una cadena de caracteres terminada por'\0'
; - las funciones
mem*
no suponen un carácter de parada (lo que permite copiar cualquier secuencia de bytes, pero necesita un tamaño para saber cuándo detenerse ; - en todos los casos, estas funciones solo deben leer y escribir en áreas de memoria asignadas por el programa, de lo contrario se desencadenará un error de segmentación.