lunes, 22 de noviembre de 2010

.: Punteros: Parte I :.

:: Punteros: Procesos Básicos ::



Materia. Lab de Leng de Progr
Hora. V1 (Jueves)

Hola de nuevos compañeros; en las próximas entradas estaremos recordando cosas del semestre pasado.
Primeramente comenzare por hablar de los punteros.
Definición.
Antes de explicar en forma práctica cómo funcionan los punteros vamos a ver la definición.
Definimos un puntero o apuntador como una variable que únicamente hace referencia a una región de memoria. Podemos verlo también como una variable cuyo valor es una dirección de memoria a la cual está señalando.
Generalmente los punteros se usan al momento de que nosotros creamos nuestras propias estructuras de datos, se usan en pilas, colas, listas, grafos, árboles, etc.
En los “Arrays” también son utilizados, pero de una manera más implícita. De hecho yo diría que más que apuntadores que nosotros declaramos, son sólo índices van junto con loa “arrays” al declararlos para poder estar accesando a cada elemento del arreglo, pero eso es otra historia.
Caso Práctico
Sé que el siguiente programa no es ninguna estructura de datos, pero el objetivo de esta entrada es demostrar cómo funcionan los apuntadores o punteros.
Declaro que me estaré basando en un programa creado en cierta clase de Estructura de Datos a la cual me “cole” el semestre pasado.
Primeramente, nosotros declaramos las siguientes variables enteras:
int x = 3, y = 7, z[5] = {2,4,6,8,10};
Pero además, nosotros declarmos nuestro puntero P de tipo entero. Menciono que los punteros se declaran como cualquier variable, con la diferencia de que se le antepone un asterisco (*).
int *P;
Si mandamos a imprimir nuestras variables enteras, tendremos el siguiente resultado (línea 1):
Como pueden observar no es gran ciencia, sólo se imprimen las variables antes declaradas.
Ahora, veremos las siguientes instrucciones:
P = &x; ----->> Aquí definimos que el puntero tendrá el valor de
                la dirección de memoria que tiene “x”
y = *P;  ----->> Ahora decimos que “y” tendrá el valor que posee
                 nuestro apuntador.
*P = 1;  ----->> En esta parte decimos que “P” tendrá el valor de
                 “1”.
Al imprimir resultados tendremos (ver línea dos):
Como pueden ver, sólo se le asignó el valor de la dirección de memoria a la que señalaba el apuntador a la variable y, no es que el puntero se haya movido a la variable y.
Como P sigue posicionado en la dirección de x, al momento de alterar el valor del apuntador, lo que se altero fue el valor de la dirección de memoria, que es en sí el valor de x.
Nuevamente tenemos los siguientes cambios:
P = &z[2]; ----->> Aquí ya cambiamos la dirección de memoria del
                   puntero, pues ya los colocamos sobre la
                   dirección del elemento “2” del arreglo “z”.
y = *P; ----->> Le asignamos a “y”  el valor de la dirección
                actual del puntero.
*P = 15 --->> Alteramos el valor de la dirección de memoria del
              puntero.
Veamos cómo se verá esto (línea 3):
Recuerden que P se encuentra sobre z[2]. Al asignar a y el valor de P, se le asigna el valor del segundo elemento del arreglo, y al alterar el valor del puntero, alteramos el valor del elemento 2 de nuestro arreglo.
Veamos ahora que pasa con lo siguiente:
x = *P + 5; ----->> A “x” se le asigna el valor de la dirección
                    del memoria añadiendo “5”
*P = *P - 5; ----->> La dirección de memoria al que se señala
                     actualmente se le resta el valor de “5”.
Estas operaciones serían así (línea 4):

Recordemos que P aún está sobre z[2]; por lo tanto, al asignar a x el valor actual de P + 5 es lo mismo que asignarle 15 + 5 = 20, como lo pueden apreciar. Pero observen que el valor del puntero no se esta alterando.
Cuando llega a P – 5, aquí si estamos alterando el valor de P y por consiguiente el valor de la dirección de memoria que viene siendo la variable z[2] = 15 -5 = 10.
Pasemos a las siguientes operaciones:
++*P; ----->> Incrementamos en una unidad el valor de la
              dirección actual de nuestro apuntador
 *P += 1; ----->> Nuevamente incrementamos el valor de nuestro
                  puntero en una unidad.
De modo que tendremos el siguiente resultado (línea 5):
Hagamos recordatorio que P aún está en la dirección de memoria de z[2] = 10; por lo que al aumentar dos veces en una unidad el valor del puntero, es lo mismo que tener 10 + 1 + 1 = 12, como pueden verlo.
Nuevamente, haciendo los siguientes cambios:
x = *(P + 1) ----->> Movemos el apuntador una posición hacía
                     adelante.
y = *P; ----->> Asignamos el valor actual del puntero a la
                variable “y”.
Al imprimir tendremos (línea 6):
No se confundan, escribir “x = *P + 1” es sólo sumar “1” al valor del puntero, pero en sí, colocar “P + 1”, estamos incrementando en una unidad la dirección de memoria, NO SU VALOR; es decir, la estamos moviendo una posición hacía adelante para asignarle ese valor a x.
Pero OJO, no hemos indicado que P se posicione en la dirección de memoria de z[3]. Para eso tendríamos que poner P = &z[3], lo cual no hemos hecho. Aún el puntero está sobre z[2] = 12.
Si se dan cuenta, el & hace la función como de asignación de dirección de memoria para que los punteros se sitúen en ella.
En fin, pasemos a lo siguiente (línea 7):
P = P + 1; ----->> Volvemos a mover una posición hacía adelante
                   la dirección de memoria de “P”
y = *P; ----->> Asignamos el valor de “P” a la variable “y”.
Y los resultados son…
Haciendo énfasis nuevamente, P sigue situado en la posición z[2] = 12. Nuevamente movimos una posición la dirección del puntero en una unidad; es decir, movimos el puntero a z[3] = 8 con el único propósito de asignarle ese valor a la variable y. INSISTO, P NO está guardando la dirección de memoria de z[3].
Continuamos:
P = P + 4; ----->> Movemos “P” cuatro posiciones en el arreglo
                   hacia
adelante
 y = *P; ----->> Asignamos el valor de la posición ahora señalada
                 a la variable
“y
”.
Mostramos en pantalla (línea 8):
Va de nuevo: EL PUNTERO SIGUE SOBRE Z[2] = 12. Otra vez movimos cuatro posiciones hacía adelante en el arreglo para asignar el valor señalado a y.
Como podemos ver y = 152 (?).
¿Pero qué paso? ¿De dónde “$%&!!#/%$” salió ese 152?
Fácil. P estaba situado en la posición 2 de nuestro arreglo de tamaño 5. Al movernos cuatro posiciones, debimos llegar a la posición 6 del arreglo, la cual no existe.
¿Pero entonces de dónde obtuvo P ese 152? Podemos decir que es sólo un valor “basura” que estaba volando por ahí, o un valor extraviado sin ubicación fija. O podemos verlo como un valor imaginario creado por generación espontánea por parte de nuestro sistema operativo. O quizás quiere surgir SKYNET de nuestra computadora y genero este valor extraño de dudosa procedencia. (De acuerdo, ya me aloque. Veo muchas películas de repente de acuerdo. Tomen en cuenta que estoy un poco cansado).
Por si ya se dieron cuenta, estoy ejecutando este código en Windows 7, así que tal vez quieran echarle la culpa a Windows, ¿quién sabe? Si no estoy en Linux es porque perdí el grub y no puedo accesar a UBUNTU.
Pero en fin, hasta para mí es una incógnita los orígenes  reales de este valor. Si alguien tiene una fuente más cuerda de éste origen, por favor compártala.
Prosiguiendo con el código, veamos por último lo siguiente (línea 9):
P = &x; ----->> Ahora cambiamos la posición de “P”. Nuevamente
                colocamos el puntero en la dirección de memoria
                de “x”
P = P + 1; ----->> Movemos una posición en la dirección de
                   memoria a “P”.
x = *P; ------>> Asignamos el valor ahora señalado a “x”.
En pantalla tendremos (línea 9):
¿Ahora qué sucedió? Bueno, tengo dos hipótesis para esto.
Primero notemos que ahora que P se sitúo sobre la dirección de memoria de x, tenemos que P se movió de posición en una unidad para asignar el valor señalado a x.
Yo veo dos posibilidades:
1.       De nuevo se salió a un sitio que no existe como nuestro caso pasado en el arreglo colocando un valor “basura” a x que curiosamente es el mismo que tenía en un principio.
2.       Como x no es un arreglo, ni ninguna estructura de datos, en realidad el puntero no se movió a ninguna parte y por eso asigno el mismo valor que tenía x a la dirección de memoria donde se encontraba.
La verdad es que en este punto, el tema se me convirtió en un misterio para mí mismo.
Espero que les haya servido esta información. A continuación les dejo el código de este programa más abajo.
Cualquier comentario es bienvenido (y vaya que siento que deje abierto para varios comentarios o eso creo).
Saludos a todos.

1 comentario: