Funciones para copiar vectores en C: memcpy y memmove

Ana Martínez Aguilar
3 min readMay 10, 2023

--

Para copiar bloques de memoria en el lenguaje C, disponemos de diferentes funciones de librería. En este artículo vamos a hablar de memcpy y memmove, ambas de la librería string.h. Aunque las dos funciones tienen el mismo propósito, existen algunas diferencias entre ellas en términos de cómo manejan la memoria y los datos.

memcpy

La función memcpy copia un bloque de memoria de una ubicación a otra. Si los bloques de memoria se superponen, el comportamiento es indefinido. Por esta razón, es más seguro utilizar memmove, que explicamos más adelante. Sin embargo, memmove es más costosa por lo que dependiendo de las circunstancias preferiremos usar una u otra.

Este es un ejemplo de cómo usar memcpy.

#include <string.h>
#include <stdio.h>

int main(void)
{
char src[] = "hola";
char dst[5] = "";
printf("%s\n", memcpy(dst, src, 4)); // hola
printf("%s\n", dst); // hola
return (0);
}

Aquí tienes una posible implementación de la función memcpy. Como puedes ver, previamente convertimos los punteros dst y src a punteros de caracteres unsigned para poder manipularlos byte por byte (un dato de tipo char equivale a un byte en la mayoría de sistemas). Después utilizamos un bucle para recorrer los datos de la dirección de origen y los copiamos en la dirección de destino. Al final, devolvemos un puntero a la dirección de inicio del destino.

void    *ft_memcpy(void *dst, const void *src, size_t n)
{
size_t i;
unsigned char *cdst;
const unsigned char *csrc;


if (!dst && !src)
return (0);
i = 0;
cdst = (unsigned char *) dst;
csrc = (const unsigned char *) src;
while (i < n)
{
cdst[i] = csrc[i];
i++;
}
return (dst);
}

memmove

La función memmove copia un bloque de memoria de una ubicación a otra, incluso si los bloques de memoria se superponen. Esta es la principal diferencia con memcpy, pues memmove sí maneja de forma segura el caso en el que el buffer origen y el buffer destino se superpongan.

¿Cuándo hay solapamiento? Este se produce cuando el buffer de origen es menor que el buffer de destino, esto es, cuando se encuentra en una posición de memoria anterior. Imaginemos que tenemos un array de caracteres. La cadena de caracteres “hola mundo” será la que deseemos copiar, es decir, nuestro destino origen.

Veamos el ejemplo en el que la posición de la memoria de source es menor que la memoria de destino. Por ejemplo, comenzaríamos a copiar en la posición de memoria 2.

Si seguimos copiando de esta manera, puede producirse el solapamiento. Para que se entienda, podemos imaginar que ocurriría lo se ve en la fotografía. Cuando queremos copiar la siguiente letra, nos encontramos con la que acabamos de copiar.

Para evitar esta pérdida de información, una solución es copiar comenzando por el final en lugar de por el principio, como puedes ver en el siguiente fragmento de código:

  i = len;
while (i > 0)
{
i--;
dst[i] = src[i];
}

Así es como quedaría la implementación completa de memmove. En la función auxiliar make_copy, si src es menor que dst, copiamos un bloque de memoria en otro en sentido inverso. Si no es el caso, copiamos de la misma manera en que lo hacemos en memcpy.

#include <stddef.h>

void make_copy(unsigned char *dst, const unsigned char *src, size_t len)
{
size_t i;

if (src < dst)
{
i = len;
while (i > 0)
{
i--;
dst[i] = src[i];
}
}
else
{
i = 0;
while (i < len)
{
dst[i] = src[i];
i++;
}
}
}

void *ft_memmove(void *dst, const void *src, size_t len)
{
unsigned char *cdst;
const unsigned char *csrc;

if (!src && !dst)
return (0);
cdst = (unsigned char *) dst;
csrc = (const unsigned char *) src;
make_copy(cdst, csrc, len);
return (dst);
}

--

--