miércoles, 18 de julio de 2012

Distancia de edición

adminitrador: Saludos User123
user123: Saludos
adminitrador: disculpe por las molestias, pero lamento informaros que nuestra base de datos ha sido comprometida y por lo que parece, por una persona de nuestro equipo.
user123: Lo lamento, pero y  ¿por qué me estás diciendo eso? no tengo nada que ver con lo que ha sucedido.
adminitrador: estamos llevando una investigación a fondo, y como se podrá . . .

¡Espera un momento! ¿Quién diablos es ese? ¡administrador sin s!

Bueno, sin duda ese era alguien un poco más astuto de la cuenta, y estoy seguro de que hubo personas que no pudieron percibir ese pequeño detalle mientras leían la parte de arriba.

El robo de identidad es algo muy común en la red y muchas veces es muy fácil de llevar a cabo, veamos como podemos proteger a los usuarios y nuestra web, en lo posible, de este tipo de cosas utilizando la distancia de edición de Levenshtein, o simplemente distancia de Levenshtein:

Antes de comenzar, necesitarás la siguiente gema:
gem install levenshtein
Continuando, según el ejemplo del timador de arriba, para nuestros fines, consideraremos insegura cualquier palabra que necesita dos o menos cambios para convertirse en otra.

Primero probemos un poco con irb:
irb(main):001:0> require 'levenshtein'
=> true
irb(main):002:0> Levenshtein.distance("administrador", "adminitrador")
=> 1
irb(main):003:0> Levenshtein.distance("webmaster", "wepmaster")
=> 1
irb(main):004:0> Levenshtein.distance("administrador", "administradores")
=> 2
irb(main):005:0>
Viendo los resultados, podríamos concluir que si tenemos un usuario de nombre webmaster, sería inseguro aceptar otro usuario de nombre wepmaster, de la misma manera para: administrador y adminitrador; administrador y administradores.

Preparemos ahora otro ejemplo, pero esta vez uno que lea una lista de usuarios y de ellas nos diga si es seguro aceptar el usuario o no.
require 'levenshtein'

RULE= 2

def safe_name?(pool, username, rule=RULE)
     not pool.any? do|name|
          Levenshtein.distance(name, username) <= rule
     end
end

if ARGV.empty?
     $stderr.puts "Uso: ruby #{$0} <usuario>"
     exit
end

# pool = IO.read('lista_usuarios.txt').scan(/\w+/)

pool = %w{ administrador abogado policia admin webmaster
           paypal google yahoo amazon dios jesus gandhi}

if safe_name?(pool, ARGV[0].downcase)
     puts "El nombre de usuario `#{ARGV[0]}' es seguro."
else
     puts "`#{ARGV[0]}' no es un nombre de usuario seguro."
end

~ $ ruby edit_distance.rb googel
`googel' no es un nombre de usuario seguro.

$ ruby edit_distance.rb jesu
`jesu' no es un nombre de usuario seguro.

$ ruby edit_distance.rb gandi 
`gandi' no es un nombre de usuario seguro.
                                        
~ $ ruby edit_distance.rb abogados
`abogados' no es un nombre de usuario seguro.

Conclusión

Últimamente los entornos de trabajo modernos (frameworks) integran mecanismo como este, de modo que la responsabilidad de comprobar este tipo de cosas recae en el sistema y no en el programador, pero nunca está de más estar alerta y consciente de los lugares de entrada y la forma de tapar esos huecos.

Ya con esto haremos que nuestros usuarios estén un metro más lejos de las garras de personas malintencionadas y brindaremos una capa más de seguridad a nuestra aplicación. Para aquellos que utilicen PHP en vez de Ruby, buenas noticias, PHP incluye en su librería estándard la función levenshtein() .

Enlaces Útiles

domingo, 15 de julio de 2012

Esteganografía: El canal alfa

¿Has sentido la necesidad de pasar información a través de un canal público? ¿Has sentido la necesidad de no levantar sospechas? o solo quieres ocultar información, sea cual sea tú fin, en esta entrada encontrarás un programa que te será muy útil así como la descripción de una técnica relativamente práctica que utiliza imágenes para ocultar información.


Ocultando información

Debido a  que a muchas personas no les interesa la teoría detrás de esta técnica, he comenzado por la parte práctica, la cual es de interés común.

Necesitarás:
  •  Ruby
  • El código del programa, descargar AQUÍ
  • Instalar la gema ChunkyPNG
    gem install chunky_png
  • La siguiente imagen para seguir los ejemplos al pie:


Primero veamos las opciones que nos proporciona el programa con la opción --help y de camino veamos también que espacio de almacenamiento tenemos disponible en la imagen.
Bueno, a simple vista se puede ver que el programa nos ofrece muchas opciones útiles para manipular la imagen, y también nos muestra que tenemos apróx. 145 KB de espacio útil dentro de la imagen.

Ahora veamos como se oculta y revela información dentro de la imagen

También podrías — si el texto es muy grande — especificar un fichero completo y ocultarlo dentro con la opción --file, o podrías también si consideras que la información dentro de la imagen es muy grande, volcarla en un fichero, con la opción --output-file. Veamos

¿Cómo funciona?


Antes que nada aclaremos unas cosas, por ejemplo el título de la entrada:

 ¿Qué es la esteganografía?
es la parte de la criptología en la que se estudian y aplican técnicas que permiten el ocultamiento de mensajes u objetos, dentro de otros, llamados portadores, de modo que no se perciba su existencia. Wikipedia
Es preciso aclarar, que la esteganografía y la criptografía van de la mano pero el fin de ambas es diferentes. La esteganografía falla cuando se descubre la presencia de información oculta dentro del portador, aún si esta está cifrada. La criptografía falla cuando el sistema de cifrado falla.

Para mas información visita wikipedia.

El canal alfa

Ya a estas altura de juego ya muchos de ustedes estarán familiarizado con la representación hexadecimales de los colores en la web, por ejemplo dos colores muy comunes y que posiblemente sabes son el blanco #FFFFFF y el negro #000000. Para el que no lo sepa, esas representaciones son números, números que indican la cantidad de ciertos colores preestablecidos, los cuales son: Rojo, Verde y Azul. De ahí su nombre, colores RGB.

Continuando, para representar dichos colores se necesitan 3 bytes, en cierta forma un byte por cada dos dígitos hexadecimales de ahí la decisión por adoptar la representación base dieciséis, es mucho fácil de recordar. Ahora, imagina que preparas una imagen y has seleccionado un color, pero pasa algo, sucede que es un color muy intenso y quieres darle un poco de opacidad — que se vea algo transparente — ¿Cómo lo logras? ¡pues con el canal alfa!

El canal alfa es un cuarto byte A dentro de la representación numérica del color RGB de un píxel y representa la opacidad que este tiene. Cuando se utiliza el canal alfa, el píxel se denomina por el cuarteto RGBA — Un píxel es, por así decirlo, un punto de color dentro de la imagen  — .

— ¿Qué pasaría si decidiera darle total opacidad a un píxel?
— Pues simple, conseguirías un píxel trasparente.
— Un píxel transparente es un píxel invisible ¿no?
— exacto.

De  forma resumida, para ocultar información dentro de una imagen con canal alfa, solo tendríamos que insertar la información en el espacio RGB de un píxel y ocultarla dándole total opacidad con el canal alfa ... solo eso ...

Debilidades

Esta técnica presenta una debilidad y es que cualquier persona podría poner visibles todos los pixeles transparentes de una imagen y ver una evidente anomalía en la imagen. Veamos como se logra esto con el programa de la entrada y la opción --show-alpha:

y el resultado es el siguiente:


Conclusión


Aquí no está, quizás esté en otra parte :P

 Referencias


Este artículo está  basado en otro escrito por Daniel Lerch en su extraordinario blog.

Enlaces de interés

martes, 22 de mayo de 2012

Técnicas de búsqueda: Introducción


Lunes 8:45pm, luego de un largo día de trabajo abres el navegador y buscas la información habitual: como preparo la cena ... ¡Clic! 0.20 s después, con 2.560 millones de resultados en frente de ti, comienza la búsqueda por una comida apropiada ¡Clic! ¡Clic! ¡Clic! y al cabo de unos segundos ya estás listo para ir a preparar la cena.

¡Espera un momento!

¿Tardar menos de un minuto para encontrar la información que se desea dentro de 2 560 000 resultados?

Bueno, el propósito de esta entrada no es explicar la cantidad de ordenadores necesarios para lograr tal rapidez, algoritmos de caché, base de datos ni tampoco hablar del pago de la factura de luz de un buscador como ese. El objetivo de este artículo es mostrar una de las técnicas más básicas pero sin embargo más importante cuando se quiere alcanzar la mayor relevancia posible.

No es necesario conocimientos previos de programación para aprovechar esta entrada, pero ayudaría mucho. Si piensas seguir el artículo al pie, al menos deberás tener instalado una versión de ruby >= 1.9.2 e instalar una gema que programé específicamente para este artículo: 

gem install estem

para más información visita: https://github.com/MaG21/estem

Stemming

Es una técnica que consiste en reducir a la raíz una palabra, dicha palabra puede ser una palabra derivada o estar en su forma conjugada p . ej. supón que tienes dos fragmentos de textos, la palabra clave pescadería y deseas saber cuál podría ser el más relevante de los dos.
primer fragmento
La pescadería es el lugar donde venden pescados atrapados por los pescadores. El pescador es la persona que atrapa el pescado.
segundo fragmento
Por este medio le informamos que cerraremos la pescadería Mar. Por favor perdone los inconvenientes que esto podría causar, nuestra prioridad es abrir la pescadería lo más pronto posible.
Una persona ingenua haría una búsqueda por palabras clave contra esos dos fragmentos, a continuación un modelo en ruby de como se vería una búsqueda por palabras claves común y corriente:
~ $ irb
irb(main):001:0> frag1 = "La pescadería es..."
irb(main):002:0> frag2 = "Por este medio l..."
irb(main):003:0> st = "\033[47m\033[1;31m"
irb(main):004:0> en = "\033[m"
irb(main):005:0> re = /pescadería/
irb(main):006:0? idx = 0
irb(main):007:0> [frag1,frag2].each do|txt|
irb(main):008:1*    ret = txt.gsub(re,"#{st}\\&#{en}")
irb(main):009:1>    puts "Fragmento #{idx+=1}\n#{ret}\n"
irb(main):010:1> end
Fragmento 1
La pescadería es el lugar donde venden pescados atrapados por
los pescadores. El pescador es la persona que atrapa el pescado.

Fragmento 2
Por este medio le informamos que cerraremos la pescadería Mar. Por
favor perdone los inconvenientes que esto podría causar, nuestra
prioridad es abrir la pescadería lo más pronto posible.
Según los resultados, el segundo fragmento es el que más coincidencias posee y  por ende, para este criterio de búsqueda, el más relevante.  Sin duda el segundo fragmento es el menos relevante, pues aunque una persona explícitamente desee la información del segundo fragmento, con esa sola palabra clave sería ilógico entregar un resultado tan alejado del significado de la misma. Si la persona desea obtener lo que busca, simplemente deberá entregar más de una palabra clave  p. ej. el nombre de la pescadería.

Veamos como se vería el resultado de la búsqueda anterior, aplicando otro criterio de búsqueda a partir de raíces gramaticales, dichas raíces si no lo son, son muy parecidas a los lexemas y son el resultado de aplicar la técnica del Stemming a una palabra. Continuando con la sesión de irb anterior, tenemos:
irb(main):011:0> require 'estem'
irb(main):012:0> re = %r{\b#{'pescadería'.es_stem}[a-zA-ZáéíóúüÁÉÍÓÚÜÑñ]++}
irb(main):013:0? idx = 0
irb(main):014:0> [frag1,frag2].each do|txt|
irb(main):015:1*    ret = txt.gsub(re,"#{st}\\&#{en}")
irb(main):016:1>    puts "Fragmento #{idx+=1}\n#{ret}\n"
irb(main):017:1> end
Fragmento 1
La pescadería es el lugar donde venden pescados atrapados por
los pescadores. El pescador es la persona que atrapa el pescado.

Fragmento 2
Por este medio le informamos que cerraremos la pescadería Mar. Por
favor perdone los inconvenientes que esto podría causar, nuestra
prioridad es abrir la pescadería lo más pronto posible.  
A simple vista se puede ver que el primer fragmento es el más relevante, y sin duda lo es. Ahora te podrías estar preguntando ¿Qué pasó? Bueno no mucho en realidad, simplemente se cargo la gema, se aplicó Stemming a la palabra pescadería y se utilizó dicho resultado junto con una expresión regular para agarrar, por así decirlo, las palabras que concuerden.

Palabras vacías

Las palabras vacías o en inglés stop words, son palabras que la mayor parte de las veces no aportan un nivel de relevancia mayor, son palabras que por su propio significado y alta frecuencia estropean las búsquedas p. ej. tu, yo, el, ellos, para, contra, con, de. Para el español opino que es una lista muy numerosa. Si deseas una lista exhaustiva de palabras vacías, por favor visita la siguiente dirección, donde Martin Porter nos ofrece una gran cantidad: http://snowball.tartarus.org/algorithms/spanish/stop.txt

Veamos un ejemplo funcional:
primer fragmento
Por favor, note que algunos baños son únicamente para mujeres.
Le pedimos que sea cuidadoso. Gracias por cooperar.

segundo fragmento
Un animal herbívoro es aquel que se alimenta de las plantas,
árboles, arbustos y hierbas. 

Aplicando todo lo que se ha visto hasta ahora, nos queda un programa de prueba como este:
#!/usr/bin/env ruby
# encoding: UTF-8
# URL: newbieshell.blogspot.com

require 'estem'
require 'getoptlong'


EQU = {'a' => '[aAáÁ]', 'e' => '[eEéÉ]','i' => '[iIíÍ]','o' => '[oOóÓ]','u' => '[uUúÚ]',
       'á' => '[áÁaA]', 'é' => '[éÉeE]','í' => '[íÍiI]','ó' => '[óÓoO]','ú' => '[úÚuU]',
       'ü' => '[üÜuU]', 'Á' => '[áÁaA]','É' => '[éÉeE]','Í' => '[íÍiI]','Ó' => '[óÓoO]',
       'Ú' => '[úÚuU]', 'Ü' => '[üÜuU]','Ñ' => '[ñÑ]','ñ' => '[ñÑ]'}

STOPWORDS = ['por', 'de', 'los', 'que', 'mucho',
             'algunos', 'son', 'el', 'ellos', 'qué']

$stopwords = false

def get_words(string)
     # I am in love with ruby, look:
     ret = if $stopwords
          string.scan(/[a-zA-ZáéíóúüÁÉÍÓÚÜÑñ]+/) -  STOPWORDS
     else
          string.scan(/[a-zA-ZáéíóúüÁÉÍÓÚÜÑñ]+/)
     end

     ret.collect { |w| w.es_stem }
end

def make_es_regexp(string)
     words = get_words(string)

     re_words = words.collect do|w|
          w.each_char.collect do|c|
               'aeiouAEIOUáéíóúüÁÉÍÓÚÜÑñ'.include?(c) ? EQU[c] : c
          end.join()
     end

     Regexp.new("(?<![a-záéíóúüÁÉÍÓÚÜÑñ])(#{re_words.join('|')})[a-záéíóúüÁÉÍÓÚÜÑñ]*", Regexp::IGNORECASE)
end

begin
     opt = GetoptLong.new(['--stop-words', GetoptLong::NO_ARGUMENT])
     opt.quiet = true
 
     $stopwords = true if opt.get
rescue
     $stderr.puts "Opción inválida"
     exit
end

# Estas dos cadenas de caracteres se utilizan para darle color
# a los resultados encontrados. NOTA necesita una terminal ANSI
st = "\033[47m\033[1;31m"
en = "\033[m"

frag1 = <<EOF
Por favor, note que algunos baños son únicamente para mujeres. 
Le pedimos que sea cuidadoso. Gracias por cooperar.
EOF

frag2 = <<EOF
Un animal herbívoro es aquel que se alimenta de las plantas,
árboles, arbustos o hierbas.
EOF

# búsqueda: "por qué algunos animales son herbívoros?"
re = make_es_regexp("por qué algunos animales son herbívoros?")

[frag1,frag2].each do|text|
     puts text.gsub(re,"#{st}\\&#{en}"), "\n\n"
end
Ahora ejecutemos el ejemplo, las palabras de búsqueda para este ejemplo son: por qué algunos animales son herbívoros?
~$ ruby search.rb
Por favor, note que algunos baños son únicamente para mujeres. 
Le pedimos que sea cuidadoso. Gracias por cooperar.

Un animal herbívoro es aquel que se alimenta de las plantas,
árboles, arbustos o hierbas.
El texto más irrelevante que alguien se pueda imaginar para esta búsqueda es el primer fragmento, pero gracias a las palabras vacías toma relevancia falsa.  Ejecutemos el programa y esta vez, quitando las palabras vacías:
~$ ruby search.rb --stop-words
Por favor, note que algunos baños son únicamente para mujeres. 
Le pedimos que sea cuidadoso. Gracias por cooperar.

Un animal herbívoro es aquel que se alimenta de las plantas,
árboles, arbustos o hierbas.
Como se ve, remover las palabras vacías de los términos de búsquedas, tiene sus beneficios, pero también tiene sus desventajas, de las cuales no hemos hablado, la más notable es que no se podrán realizar búsquedas por frase, algo un poco más complejo si se quiere hacer bien.

Conclusión

Si tienes intenciones de adentrarte en el mundo de la extracción de información, existen muchos acercamientos que podrían ser de interés y no se mencionaron, p. ej. un acercamiento estadístico, utilizando el teorema de Bayes; un acercamiento tomando en cuenta el momento de la consulta, si es hora de comida o una hora de trabajo; búsqueda geolocalizadas; búsquedas sentimentales o por supuesto, una combinación de todos esos acercamientos.

Sin duda faltan muchos pequeños detalles por tomar en cuenta, pero con lo mencionado anteriormente, es suficiente para entender un poco acerca de los buscadores, y si se cuenta con los conocimientos necesarios de programación, cualquier persona sería capaz de programar un algoritmo de búsqueda superior a una innumerable cantidad de paginas web allá afuera.

La brevedad es difícil de alcanzar y sin cuidado complica lo que se quiere simplificar en primer lugar.  Ten cuidado con la codificación de los textos que manejas; Se organizado; clasifica la información e Intenta ejecutar todo lo que se presenta aquí.

Referencias

  1.  Spanish Stemming Algorithm, Martin Porter

Enlaces Útiles

  1.  Lista de palabras vacias
  2. https://github.com/MaG21/estem
  3. IMG, Enlace directo a la página del autor de la imagen de la portada.

sábado, 26 de noviembre de 2011

Descomentador De C/C++

Una de las primeras cosas que aprendemos cuando nos iniciamos en cualquier lenguaje de programación es que debemos comentar de manera correcta nuestro código, es más, muchos autores han dedicado una buena parte de sus libros con temas relacionados a los comentarios, cómo redactarlos y dónde ponerlos. Pero ¿Qué pasaría si no quisiéramos comentar nuestro código? Mejor aún ¿Qué pasaría si no quisiéramos comentarios de ninguna índole en nuestros ficheros fuente?; el mundo da vueltas (!).

El programa descomentador que presento en este artículo está basado en las especificaciones de esta página COS 217. Solo funciona con ficheros fuentes de C o C++. Si no se especifica ningún fichero en los argumentos, el programa lee de la entrada estándar e imprime por pantalla.

Recuerda que necesitarás una shell para ejecutar los siguientes mandatos, preferiblemente Bash.

Si no quieres leer todo este artículo y solo quieres quitar los comentarios de un fichero, puedes usar la siguiente orden, después de haber compilado el programa correctamente.
./decomment comentado.c 2>/dev/null > comentado.c
Compilar Programa
Para compilar con gcc ejecuta uno de los siguientes mandatos
#Compilar
$ gcc decomment.c -o decomment

# También puede permitir que gcc optimice el código para mayor rapidez 
$ gcc -O2 decomment.c -o decomment

# Optimizar un poco más (quizás)
$ gcc -O2 -fomit-frame-pointer decomment.c -o decomment
Modo de empleo
# Quita comentarios e imprime por pantalla
$ ./decomment comentado.c

# Guardar resultado en un fichero
$ ./decomment comentado.c > nocomentado.c

Si el descomentador llega al final del fichero fuente y no encuentra un cierre de comentario, imprimirá una línea como esta: Error: línea x: comentario no cerrado. Si estás consiente de que tu fichero fuente quizás esté mal formado, podrías obviar ese aviso y quitar los comentarios de todas maneras, así:

# Quita comentarios, imprime por pantalla y obvia errores
$ ./decomment comentado.c 2>/dev/null

# Si quiere redirigir la salida a un fichero solo debe hacer
$ ./decomment comentado 2>/dev/null > nocomentado.c

# también podría hacerlo así
$ ./decomment < comentado.c 2>/dev/null > nocomentado.c

Si tus intenciones son eliminar todos los comentarios de un árbol completo de ficheros fuentes, tan solo debes de poner el siguiente programa para Bash a trabajar dentro del directorio raíz:
#!/bin/bash
DEC=./decomment # ruta absoluta del programa decoment
OLD_IFS=$IFS
IFS=$'\n'
for line in `find -iname '*.c' -or -iname '*.h' -or -iname '*.cpp'`; do
   $DEC $line 2>/dev/null > tmpfile
   mv tmpfile "$line"
done 
IFS=$OLD_IFS
Si lo que deseas es no dejar rastros de comentarios por ninguna parte, entonces deberías ir a por las copias de seguridad que hacen algunos editores de texto. El siguiente script busca los ficheros C o C++ y sus copias de seguridad. Sin misericordia, por ejemplo, este script es capaz de encontrar  "la copia de seguridad de la copia de seguridad de la ...", así una copia de seguridad que tenga el nombre: programa.cpp.old.back.old.old~ será procesada. Ten mucho cuidado con este script, pues no hay vuelta atrás.
#!/bin/bash
DEC=./decomment # ruta absoluta del programa decoment
REGEX='.*\.([ch]|cpp)(\.?(~|old|back))+?$'
OLD_IFS=$IFS
IFS=$'\n'
for line in `find -regextype posix-extended -iregex $REGEX`; do
   $DEC $line 2>/dev/null > tmpfile
   mv tmpfile "$line"
done
IFS=$OLD_IFS
Portabilidad

Este programa se puede ejecutar (compilar) en cualquier sistema operativo que posea un compilador para lenguage C compatible con ANSI C. De todas maneras listaré los sistemas donde no habrá problemas para compilar y ejecutar el descomentador:
  • GNU/Linux
  • FreeBSD, OpenBSD, NetBSD
  • Mac OS X
  • Windows
AVISO

Recuerde que descomentar ficheros fuentes podría resultar en grandes consecuencias morales y económicas, se desaconseja su uso, úselo cuando sea realmente necesario y bajo su propia responsabilidad, no me hago responsable de lo que pueda pasar o de los archivos que se corrompan usándolo.

Despedida

Si  bien hice todo lo posible por seguir buenas maneras y estilo mientras programaba el descomentador, todo se fue a pique cuando tuve que reducirlo a un fichero para poder distribuirlo con Google Docs; mis más sinceras disculpas.

¿Tienes alguna funcionalidad nueva en mente? ¿Encontraste algún error o tienes alguna inquietud? No dude en hacérmela saber.

Descarga Código Fuente Del Programa

jueves, 18 de agosto de 2011

Las Funciones memcpy() Y memmove()

Cuando terminamos el ciclo básico y dominamos una buena parte de las funciones de entrada y salida, empezamos a sentirnos agobiados por la incapacidad de mover y copiar la información que obtenemos. Quisiéramos o no, nos vemos forzados a estudiar las funciones para la manipulación de caracteres.

La  función strcpy es la que primero hallamos y utilizamos hasta que vemos su peligro, luego es strncpy, mas prometedora que strcpy pero el peligro aun toca la puerta, y al igual que strcpy solo funciona con cadena de caracteres y corrompen los datos al agregar el carácter \0 al final (con strncpy no siempre es cierto).

Buscando hallamos a memcpy() y memmove() e inmediatamente caemos en una encrucijada ¿Cuándo debo usar memmove? De esto se trata este artículo, explicar cuando utilizarlas y porque.
/* Tomado del código fuente de linux */
void *memcpy(void *dest, const void *src, size_t count)
{
 char       *tmp = dest;
 const char *s   = src;

 while(count--)
  *tmp++ = *s++;
 return dest;
}
Debido a la gran cantidad de versiones y optimizaciones realizadas a esta función, copie esta implementación para la cual su comportamiento está definido en todas las arquitecturas (no intentes optimizarla con el compilador). Antes de entrar en lleno, examinemos que dicen las especificaciones de ambas funciones con el Traductor 9000:


Todo parece estar bien, a excepción de esa palabra; superposición. Para entender más un poco sobre la superposición entre dos áreas de memoria, veamos un ejemplo visual sin superposición, pero antes definamos (de manera vaga) lo que superposición significa (para nuestros fines).
Es cuando dos áreas de memorias están correlacionadas y una modificación en una de las partes se ve reflejada a lo largo de las modificaciones siguientes.

Como se puede apreciar en la animación, una modificación en una área de memoria no afecta las modificaciones sucesivas. Veamos ahora otra animación un ejemplo que muestra claramente la superposición.

En la animación anterior, el uso de la función memmove es necesario. A estas alturas te podrías estar empezando a preguntar si  utilizar memmove y nunca memcpy, la respuesta simple es: podría. Los tíos de FreeBSD (quizás otros) meditaron sobre esto y modificaron su API, de manera que cuanto intentes utilizar memcpy o memmove, sin darte cuenta estarás usando bcopy; función muy parecida a memmove.

Despedida

Luego de haber leído este artículo sería lógico si terminas preguntándote ¿Cuál es el propósito de la función memcpy? ¿Introducir posibles errores en nuestra aplicaciones o copiar áreas de memoria? La respuesta es que memcpy algunas veces posee optimizaciones específicas; es más rápida.

Ahora que conocemos la diferencia entre ambas funciones usarémos memmove solo cuando sea necesario; siempre tratemos de utilizar memcpy, la cual en muchos casos posee mayor rendimiento.

Comentarios y Cosas Raras
 ... os he atrapado con las manos en la falda ¡Qué problema! ¿Eh? Terroríficas, precisas y calculadoras (frías), no podemos escapar de ellas; nos tienen dominados ...
Enlaces
  1. Ejemplo sin superposición
  2. Ejemplo con superposición
  3. Ejemplo con memmove