martes, 5 de marzo de 2013

Una nota sobre los punteros

Volviendo a practicar con C, y nos volvemos a encontrar las míticas criaturas llamadas "punteros" del lenguaje C, esas siniestras y crueles seres que confunden y aterran al programador nuevo.

Entonces ¿por que están implementadas?, ¿Para que sirven?, bueno en realidad los Punteros, es algo sencillo, los estúpidos y ridículos usos que les dan  es lo que espanta a la gente.

¿Que son?, cuando tienes un arreglo, digamos array[i], tenemos  el arreglo "array" y su indicie, llamado 'i' por la misma razón, si el valor de i es 0 entonces obtenemos el valor en array[0], si el indice es 1, entonces obtenemos el valor en array[1].

Si 'i' es el indice, y el indice es la dirección en donde esta la información del arreglo, entonces el Arreglo como tal, es un conjunto de direcciones, pero localizadas en la memoria de la maquina, y los indices de un arreglo, nos dicen en que parte de la maquina esta.

Esto permite a C pensar en tu computadora como si fuera un enorme arreglo de bytes, un montón de espacio en memoria para ser acomodados.

A todo esto, ¿Que son?, bueno un puntero, es un "apuntador" a esa direccion en memoria, los punteros no almacenan nada, solo "apuntan" a donde esta, imaginemos que tu arreglo es un librero,  y quieres el libro que esta en libros[3][2], vas a esa dirección y lo tomas, un puntero seria como la ficha bibliográfica  te dice en donde esta, en que parte esta, sin embargo NO ES el libro, solo te dice donde esta.

Recuerda este proceso que pasa cuando asignas un puntero:

-Tu computadora crea un bloque de memoria en si misma, que representa al arreglo
-"Apuntamos" el inicio de ese bloque de memoria
-Se usa el "indice", que en este caso es Array[i], para obtener el elemento en una parte del bloque de memoria
-el puntero esta "apuntando" al inicio del bloque de memoria, si queremos obtener el mismo dato tenemos que hacer puntero+i, osea mueve el puntero i posiciones.

C sabe a donde apunta el puntero, sabe que tipo de datos es a lo que apunta, el tamaño de esos datos y como obtenerte esos datos. Pero al igual que los arreglos, los punteros pueden ser "modificados", sin embargo el puntero NO ES  otro arreglo, es el mismo arreglo, así que si modificas un puntero, terminaras modificando el arreglo original, aquí es donde la gente tiene problemas.

Imagina que tienes el arreglo:

 char *Caminantes[] = {"Jace","Chandra","Garruck","Ajani", "Liliana"}

, creamos un puntero

char *puntero_caminates = Caminantes;

agregamos un caminante
Caminantes.add("Karn") //No es la sintaxis correcta, pero me entienden

nuestro arreglo queda como

Caminantes ={"Jace","Chandra","Garruck","Ajani", "Liliana","Karn"}

que pasa si hacemos

puntero_caminates.add("Tezzert");

Tezzert es agregado,PERO al arreglo de caminantes, no en puntero, por que no es un arreglo

asi que tenemos

Caminantes ={"Jace","Chandra","Garruck","Ajani", "Liliana","Karn", "Tezzeret"}

Los punteros tienen varios usos prácticos:

-Le pides al sistema operativo trabajar con el bloque de memoria creado, incluso funciona con struct y strings
-Pasar grandes bloques de memoria a funciones con punteros para no tener que pasar todo.

Digamos que tienes que pasar un bloque de 200 megas, si quieres "pasarlo" de manera normal, tendrías que crear una variable para almacenarla, así que la computadora reservaría otros 200 megas, el del arreglo normal y el del arreglo nuevo, y si es una estructura que tienes que estar pasando entre funciones es muy desgastante en memoria. Con un puntero sin embargo solo pasas el "AHI ESTA" y no creas nada adicional.

-Tomar la dirección de una función para hacer llamadas dinámicas

Los punteros te van a mostrar como esta ese bloque de memoria en ese momento, así que si fue afectado por algún otra forma puedes obtener ese bloque con un puntero,

-ACompleto analizis de un bloque de memoria para convertir los bytes de un puerto de red en estructura de datos o convertirlo a archivo


Para cualquier otro uso, se deberían usar arreglos, antes los punteros se usaban con mucha frecuencia por que el compilador no optimizaba los arreglos de forma efectiva, así que tener 1 o 2 arreglos nuevos alentaba mucho tu programa, ahora ya no es el caso.

Syntaxis de los puntero

Como nota adicional:

type *ptr
"un puntero "type" llamado  ptr"
*ptr
"El valor de lo que sea que ptr apunta"
*(ptr + i)
"el valor de lo que sea que ptr apunta + i"
&thing
"la direccion de thing"
type *ptr = &thing
"un puntero type llamado ptr inicializado a la direccion de thing"
ptr++
"incrementar donde ptr apunta"

viernes, 1 de marzo de 2013

Estructura de datos fundamentales

Del libro "Algoritmo y estructura de datos" de Wirth Nicklaus

Introducción

La computadora digital moderna fue inventada e ideada como dispositivo que debe facilitar y acelerar operaciones de calculo complicadas y que consumen mucho tiempo.En la mayoría de las aplicaciones su capacidad de almacenar y acceder a grandes cantidades de información se ha vuelto su principal característica  Su capacidad de contar o computar, ese ha vuelto irrelevante.

En la mayoría de los casos, esta información representa una abstracción de una parte de la realidad. La información que se ocupa es un conjunto de datos del problema real. Por lo tanto, los datos representan una abstracción de la realidad en el sentido que ciertas propiedades y características de los objetos reales son ignorados por que son irrelevantes para el problema. Una abstracción es por tanto una simplificación de hechos.

Al resolver un problema con o sin una computadora se necesita elegir una abstracción de la realidad. Esta acción debe ser guiada por el problema a resolver. Luego una elección de esta información  que normalmente por las herramientas usadas para resolver el problema, en este caso los recursos que proporciona la computadora.

Generalmente se sabe que las computadoras utilizan la numeración binaria. Que es inadecuada para los seres humanos, pero es ideal para las computadoras ya que se puede representar el 0 y 1 por la ausencia o presencia de corriente eléctrica, carga eléctrica, o campos magnéticos.

Un lenguaje de programación representa a una computadora abstracta capaz de interpretar los términos que se utilizan en este lenguaje. Así  los programadores que utiliza este lenguaje de nivel superior queda liberado de cuestiones referentes a la representación numérica para la computadora de una instrucción en especifico.

La ventaja de usar un lenguaje de programación es que incluye un conjunto conveniente de abstracciones básicas comunes a muchos problemas de procesamiento de datos. Es mas fácil diseñar un programa basado en el razonamiento con nociones bien conocidas de números  conjuntos, secuencias y repeticiones que en bits, unidades de almacenamiento y saltos.

Cuanto mas próximas estén a una cierta computadora las abstracciones, mas fácil sera hacer una elección de la representación para el ingeniero o implantador del lenguaje y mayor sera la probabilidad de que una sola elección sea adecuada para todas las aplicaciones imaginables.

Sin embargo, también hay que considerar el hecho de que si una abstracción base de un lenguaje es muy especifica, otros programadores podrán usarla de una forma errónea.