jueves, mayo 15, 2008

La supernova más jóven en la Vía Láctea

Ayer la NASA anunció a lo grande un objeto en nuestra galaxia que habían encontrado y que dicen llevar 50 años buscando. Se trata de una supernova, la más jóven encontrada hasta la fecha. La supernova fue encontrada por el radiotelescópio Chandra y explotó hace apenas 140 años.



Una supernova es un tipo muy peculiar de extrella, de enormes dimensiones, que acaba haciendo explosión en uno de los acontecimientos más espectaculares que ocurren en el vasto universo.

La luz y calor que producen estrellas como nuestro Sol, viene producida por la fusión en sus nucleos de elementos ligeros, como hidrógeno o helio que se combinan para producir otros más pesados, como nitrógeno o carbono. Estas reacciones de producen debido a la presión que producen las capas exteriores de la estrella sobre las interiores, debido a la gravedad que las atrae hacia el centro. Cuando a una estrella como nuestro Sol se le va acabando el combistible, le cuesta cada vez más combinar los elementos pesados y se va encogiendo hasta formar una enana blanca.


Pero si la estrella tiene un tamaño superior, como 40 veces el de nuestro sol o más, en el proceso de compresión para convertirse en enana blanca colapsará y creará una enorme explosión que arroje casi toda su materia en una onda expansiva de una energía equivalente a 1.000 millones de soles, que viaja a gran velocidad y que puede permanecer incandescente durande meses, arrasando todo lo que encuentran a su camino. Esta explosión puede llegar a brillar más que toda la galaxia que la contiene.

Si una supernova explotase demasiado cerca de nuestro sistema, la radiación emitida acabaría con toda la vida en la Tierra y puede que incluso con el propio planeta. Por suerte, nos encontramos en una de las ramas externas de la Vía Láctea, donde este tipo de acontecimientos son menos frecuentes que cerca del centro. Tampoco encontramos estrellas lo suficientemente grandes en nuestro entorno como para ser claras candidatas a supernova.

Aún así en la historia se han registrado hasta seis supernovas visibles a simple vista. La más espectacular fue en 1604, que pudo verse incluso de día durante más de tres semanas.

Pero a pesar de su carácter destructor, las supernovas son fundamentales para el desarrollo de la vida como la de nuestro planeta en el universo. Las supernovas riegas de materiales pesados el espacio, materiales que habitualmente sólo podríamos encontrar en el mismo centro de las estrellas. Estos materiales pesados, como el hierro, el aluminio, el carbono, etc. se reagrupan después de la explosión para formar nuevos sistemas y planetas. De hecho ¡nuestro sistema solar proviene de la explosión de una o más supernovas!

viernes, marzo 21, 2008

El robot BigDog


Cuando se habla de robots en tecnología, los expertos siempre se mantienen bastante excepticos, y no sin motivo. Las espectaciones de futuro siempre han sido muy altas y los resultados pobres. Aunque podemos hablar de maravillas como el robot Spirit que ahora mismo rueda a sus anchas fotografiando la superficie de Marte, no deja de ser un trasto teledirigido muy lejos de los robots que se supone que iban a trabajar por nosotros.

Uno de los principales problemas a la hora de diseñar un robot, es la estabilidad. Hacer que el robot pueda desplazarse por cualquier superfie sin perder el equilibrio. Para esto hay dos soluciones. La primera y más sencilla es ponerle ruedas. Las ruedas dan una gran estabilidad pero están muy limitadas en cuanto a superficie. Un robot con ruedas no podrá subir escalone o sobrepasar obtáculos y fisuras en el suelo. La otra alternativa es utilizar patas. Un robot con cuatro patas tecnicamente podría recorrer cualquier camino que puede hacer una cabra montesa. Pero usar patas es complicado. La estabilidad es muchísimo menor que con las ruedas y la complejidad de programar el sistema enorme. Hasta hoy no había visto un robot con patas que resultase convincente.

Pero hoy el leído en Xataka que la empresa norteamericana Boston Dynamics ha mostrado su última creación: el BigDog, que podría traducirse como PerroGrande.

Es sorprendente lo que este robot puede llegar a hacer, tiene una agilidad y reflejos que hace pensar que se trata de un ser vivo. Pero bueno, lo mejor es que lo veais por vosotros mismos en el video.

martes, noviembre 13, 2007

Marte ya tiene bandera

Ya ha sido aprobada la bandera oficial de Marte por la Sociedad de Marte y la Socidad Planetaria.


Los colores de la bandera son rojo, verde y azul, que representan la sucesión de colores que podría tener marte durante una hipotética terraformación, es decir, los colores que iría tomando el planeta en un proceso que lo convirtiera en habitable para el ser humano; tal y como se describe en la Trilogía Marciana de ciencia ficción de Kim Stanley Robinson. La bandera fue propuesta por primera vez en 1999 por un grupo de ingenieros de la NASA.

¿Se sentirán orgullosos los marcianos de ondear su nueva bandera, o tendrán ya la suya propia?

martes, noviembre 06, 2007

La Edad de la Tierra


Hacía mucho tiempo que no escribía en el blog, más por falta de tiempo que por falta de motivación, pero por fin he conseguido sacar un rato y traeros una nueva historia que contar.

Y precisamente de tiempo va hoy el asunto. Siguiendo la serie comenzada en el artículo anterior, que consiste en que conozcamos un poco más acerca del planeta en que vivimos, y más concretamente cómo hemos llegado a conocerlo, hoy vamos a hablar de uno de los retos más difíciles de conseguir en la historia de la ciencia: la Edad de la Tierra.

La Biblia



Los primeros intentos serios de calcular la edad de la Tierra fueron realizados estudiando los textos bíblicos, y tasaron la edad de la Tierra en unos 6.000 años, teniendo en cuenta que en dichos textos se citan todas las generaciones (unas 20) desde Adán a Abraham, y se calculan unas 55 desde Abraham a Jesús. De esta forma habrían pasado unos 4.000 años desde la creación hasta el nacimiento de Jesús.

Sabemos a día de hoy que este dato es completamente incorrecto, y que la Edad de la Tierra es muchísimo mayor, por no hablar de la edad del Universo. El error en este caso no estaba en el análisis de los textos, que pudo ser más o menos riguroso y cuidado, sino en tomar los textos bíblicos de una forma completamente literal. Aun así, esta creencia fue mantenida durante mucho tiempo, hasta aproximadamente del siglo XVIII, cuando el nacimiento de la geología comenzó a dar las primeras pistas de la edad que hoy en día tomamos como acertada.

Comienzos de la Geología




El interés comenzó intentando buscar una explicación a los numerosos fósiles de moluscos y otros animales marinos que aparecían en las cumbres montañosas. ¿Cómo habían llegado hasta allí? Para explicarlo surgieron dos teorías. Por un lado estaba la teoría neptunista que defendía que había ciclos de inundaciones que llegaban a cubrir la Tierra por completo, sumergiendo las montañas completamente. El problema de esta teoría es que no podía explicar de dónde venía el agua y dónde iba a parar cuando se retiraba. La otra teoría era la plutonista, cuyos argumentos eran que la Tierra estaba sujeta a potentes fuerzas interiores que producían los volcanes y los terremotos, pero no daban a explicar como habrían llegado los fósiles hasta ahí arriba.

Fue a la llegada del escocés James Hutton cuando se empezaron a dar pasos en la dirección correcta. Para empezar Hutton advirtió algo en lo que nadie se había percatado nunca, o que no le habían dado mayor importancia: la erosión. Se dio cuenta de que la tierra en las faldas de las montañas era mucho más suelta debido a que estaba formada por partículas que los ríos arrastraban desde las cimas y que si el proceso continuaba en el tiempo, la Tierra se volvería muy lisa, así que tenía que haber un proceso generador de nuevos accidentes geográficos.

Tras la muerte de Hutton en 1797, el interés en la geología comenzó a crecer de manera descontrolada llegando a ser la rama científica con más adeptos en el siglo XIX, en incluso un fenómeno social en las áreas intelectuales en general. Entre las múltiples teorías para describir el fenómeno generador del relieve, destacó principalmente Charles Lyell, considerado el padre de la geología moderna. Lyell planteaba un desarrollo uniforme de la geografía, tan lineal que observando los acontecimientos actuales se podría explicar el pasado geológico. Su obra tuvo tal éxito que prácticamente desbancó el resto de teorías. Darwin, por poner un ejemplo, fue un gran seguidor de Lyell.

Tras Lyell hubo una avalancha de clasificaciones de la historia terrestre en épocas o periodos, tales como el Jurásico o Pleistoceno. Hubo tal disparidad y cantidad de clasificaciones que incluso hoy no hay una única clasificación concertada. Pero a pesar de tanta clasificación y subdivisión, nadie podía decir con certeza la duración de cada periodo, y mucho menos la edad de la Tierra. Para eso tuvieron que pasar aún muchos años.



¿Cómo calcular la edad real?



En este momento te pediría que dejases de leer un momento, dejases correr tu imaginación e intentases pensar algún medio para calcular la edad de la Tierra pues, aunque no hayan conseguido su objetivo, en la historia no han faltado propuestas ocurrentes.

Una de ellas, a manos de Edmond Halley, consistiría en dividir la cantidad de sal total que hay en el mar entre lo que se añade cada año, y de esta forma calcular cuanto tiempo llevan existiendo los mares; pero por desgracia no se sabía cuanta sal hay en el mar ni cuanta se añade anualmente, por lo que no había forma de realizar el cálculo.

Otro intento vino del francés Georges-Louis Leclerc que, sabiendo que la Tierra disipaba calor, realizó un experimento calentando unas esferas al rojo y calculando la tasa de pérdida de calor. De esta forma estimó una edad de entre 75.000 y 168.000 años, lo cual era aún muy bajo pero revolucionario para la época.

En pleno siglo XIX, Charles Darwin en su libro "El origen de las especies" estimó la edad de la Tierra en unos 306 millones de años en base a sus cálculos, pero no tenía forma de demostrarlo.

En 1897, Willian Thomson, que fue una gran físico del siglo XIX y padre de la escala de temperaturas absolutas que lleva su nombre (barón de Kelvin), afirmó que la Tierra no podría tener más de 24 millones de años, debido a que una estrella como el Sol agotaría su combustible en un tiempo menor a ese; pero la mayoría de los fósiles parecían contradecirle.

La confusión y el desatino en dar con una edad creíble duró al menos hasta 1904, año en el que el neozelandés Ernest Rutherford presentó su trabajo. Rutherford no dio con una edad muy aproximada, pero sí con el medio a través el cual se ha seguido investigando desde entonces. Rutherford se encontraba estudiando la radioactividad recién descubierta por Pierre y Marie Curie y en concreto la desintegración del uranio. Observó que todas las muestras de material radioactivo tardaban siempre el mismo tiempo en descomponerse hasta la mitad. De esta forma, calculando la radiación que tenía actualmente un material y la rapidez con la que se estaba desintegrando, se podía determinar su edad. Así que calculó la edad del mineral del que procedían sus muestras de uranio, y pudo estimar que tenía una edad de 700 millones de años.

La actualidad



Aún han tenido que pasar muchos años, y a partir del estudio de la radiación se han ido encontrando minerales cada vez más antiguos. De una forma un tanto irónica, la edad actual, 4.550 millones de años, calculada con un error menor del 1%, no ha resultado del estudio de la Tierra, sino de meteoritos cercanos que, lejos de la superficie terrestre, se han mantenido a salvo de la erosión.

martes, mayo 15, 2007

Eratóstenes y la circunferencia terrestre

Hoy vamos a ver el primer experimento de una serie de tres que comentaré en sucesivos días y que fueron bastante decisivos en la historia de la ciencia. Los tres tienen un elemento en común: la Tierra. En estos experimentos la Tierra participa como un elemento más, y precisamente el objetivo de estos tres experimentos es medir alguna característica de la tierra: su circunferencia, su rotación y su densidad.



El radio de la Tierra


Es increíble que, mientras en Europa en el sigo XV aún se discutía si la Tierra era redonda o plana, muchos siglos antes, en el siglo III a.C. los griegos no sólo sabían que la Tierra era redonda, sino que habían sido capaces de medir su tamaño.

Los griegos sabían que la tierra era redonda por diversas evidencias: la sombra que proyectaba la Tierra sobre la Luna en los eclipses lunares era siempre circular; o cuando un barco se alejaba en el horizonte, lo último en desaparecer siempre eran las velas.

Uno de estos griegos, el matemático y astrónomo Eratóstenes fue el que llevo a cabo el experimento para medir el la circunferencia de la tierra, utilizando unos medios, como veremos de lo más sencillos.

Durante el tiempo en el que Eratóstenes realizó el experimento, vivía en la ciudad de Alejandría, que se encontraba a unos 5.000 estadios al norte de la ciudad de Siena (1 estadio = 167,7 metros). La ciudad de Siena era conocida porque el día del solsticio de verano, el 21 de Junio, a las 12 del mediodía, los rayos del Sol caían completamente perpendiculares. En ese momento los habitantes de Siena podían ver el Sol exactamente sobre sus cabezas, y los edificios, columnas, postes, etc. no producían sombra alguna. En realidad esto ocurre porque Siena se encuentra situada en el trópico de Cancer.

Eratóstenes, sabiendo esto, utilizó esta peculiaridad para calcular la circunferencia de la Tierra. Situado en Alejandría, a las 12 del mediodía del solsticio de verano, colocó un palo vertical (se cree que un reloj de sol) y midió la longitud sombra que producía. Usando algo de trigonometría básica pudo hallar el ángulo que formaba la sobra con el palo, que resultó ser de 1/50 de circunferencia (unos 7º12'). De esta forma, y como veremos a continuación con ayuda de la figura 1, supo que la distancia entre Alejandría y Siena era 1/50 de la circunferencia total de la Tierra, por lo que la Tierra tendría que tener de cincunferencia 50 veces la distancia de 5.000 estadios que separaba ambas ciudades, esto es, 250.000 estadios. Eratótenes decidió añadir la cantidad de 2.000 estadios para hacerla divisible entre 60 y facilitar cálculos posteriores.


En la figura 1 se muestra esquemáticamente una parte de la Tierra. La letra S representa la ciudad de Siena, en el trópico de cáncer. La letra A, al norte, representa la ciudad de Alejandría, donde se encontraba Eratóstenes. La letra C es el centro de la Tierra. Como se puede observar, los rayos solares, representados mediante flechas, caen perpendicularmente sobre la ciudad de Siena, pero con un cierto ángulo sobre Alejandría. Este ángulo produce que el poste situado en A proyecte una sobra sobre el punto P. El ángulo que se forma entre los rayos y el poste colocado en A es exactamente el mismo que el formado por A, C y S.

El valor calculado por Eratóstenes era de 41.950 km, un valor bastante aproximado a los 40.120 km medidos en la actualidad. Pero lo grandioso del experimento es la sencillez de su ejecución, compuesta por un simple palo, su sombra, y por supuesto la Tierra y el Sol.

Enlaces de interés


Biografía de Eratóstenes
Demostración interactiva en Flash (y otro ejemplo)

martes, mayo 01, 2007

Un planeta primo de la Tierra


Últimamente se ha hablado mucho en los medios acerca del planeta econtrado en el sistema Gliese 581 con características muy similares a las de la Tierra: rocoso, con un 50% más de radio, 2,2 veces más gravedad y temperaturas entre 0 y 40ºC. Además las posibilidades de que este planeta albergue agua en estado líquido son muy altas, debido a que el agua es un elemento muy común en el universo.

¿Se encontrarán más planetas similares en el futuro?

Hasta hace una década no sabíamos si el hecho de existir planetas orbitando a las estrellas era algo que ocurría con frecuencia o era prácticamente un milagro, ya que nunca había sido detectado un planeta exosolar. Los primeros planetas encontrados eran gigantes gaseosos similares a Júpiter, o incluso más grandes. Las técnicas empleadas aún debían ser refinadas y no eran capaces de detectar planetas más pequeños.

Sin embargo ahora se están empezando a encontrar planetas rocosos. La técnica aun puede mejorar más aún ya que se encuentran en sistemas muy específicos: aquellos con estrellas muy pequeñas, enanas rojas, como es el caso de la estrella Gliese 581, donde se ha encontrado el reciente planeta. Al ser la estrella más pequeña y con menos brillo es más fácil detectar los planetas que orbitan alrededor de ella.

En mi opinión se encontrarán muchos más planetas y con cada vez mayor frecuencia. Estoy seguro de que también se encontrarán planetas similares y más cercanos, aunque 20 años luz en escalas estelares es relativamente cerca; la estrella más cercana, Alfa Centauri, se encuentra a 4,36 años luz de nosotros.

¿Podría existir vida en este planeta?

Todo depende de si contiene agua o no. Como comenté antes, el agua es un elemento muy común en el universo, encontrada en la mayoría de los meteoritos que llegan a la tierra desde los bordes del sistema solar, pero depende en gran medida del proceso de formación del planeta el que haya retenido agua o se haya escapado al espacio en forma de vapor.

Tradicionalmente se ha pensado siempre que la vida es algo frágil y difícil de sostener, pero los últimos estudios apuntan a todo lo contrario: allá donde pueda surgir la vida, surgirá la vida. Por supuesto todo es especulación, pero no sin fundamento. Después de encontrar vida es los sitios más extremos del planeta, como debajo de los casquetes polares o en el interior de fallas sísmicas submarinas en erupción a miles de metros de profundidad, dejamos de pensar que la vida necesita un habitat equilibrado y ajustado con precisión.

¿Y qué hay de la vida inteligente?

Desde luego, no tiene sentido intentar de responder a esta pregunta sobre un planeta del que ni siquiera conocemos su composición aproximada. Como mucho podemos especular sobre la posibilidad de que en planetas de este tipo exista vida inteligente.

Si, como yo mismo pienso, el firmamento está plagado de planetas de estas características, la posibilidad de vida inteligente también aumenta, pero no podemos saber si con eso es suficiente. El número de estos planetas viene representado como ne en la ecuación de Drake, de la que espero escribir algún día.

¿Se podría viajar a ese planeta en un futuro cercano?

Con la tecnología actual desde luego que no merecería la pena enviar una sonda tan lejos; ya no hablemos de seres humanos. La sonda espacial New Horizons, que es la más rápida construida hasta la fecha, es capaz de viajar a 50.000 km/h. Salió de viaje en Enero del 2006 y se espera que llegue a Plutón en el 2015. Esta sonda tardaría en llegar hasta la constelación Gliese 581 más de 21.500 años.

No obstante los investigadores más optimistas esperan que en un futuro no muy lejano, con nuevas tecnologías de propulsión espacial, podría alcanzarse la cuarta o quinta parte de la velocidad de la luz. A estas velocidades se podría llegar al planeta en menos de 100 años, pero aquí en la Tierra tendríamos que esperar 20 años más hasta que el mensaje anunciando la llegada retornase hasta nuestro planeta.

No dudo que mientras esperamos esa tecnología, encontremos más planetas en estrellas más cercanas.

¿Qué supone este descubrimiento para la ciencia?

Sin duda sospechabamos que llegaría el día en que se encontrasen planetas similares a la Tierra en el espacio exterior, y por fin ese día ha llegado. Lo más importante de este descubrimiento es que si algún día decidiésemos salir de nuestro sistema solar, tendremos un sitio al que apuntar, y no salir en una dirección al azar dando palos de ciego.

Fotografía: Representación del nuevo planeta recién descubierto (1) y la estrella Gliese 581 (2). [ESO]

miércoles, marzo 21, 2007

Web 2.0

Últimamente se habla mucho de este término, pero... ¿Qué es exactamente? Tenía pensado soltar una parrafada como de costumbre, pero creo que es mejor que veais este video que sintetiza el concepto mucho mejor, y de una forma muy elegante. A mí me puso la carne de gallina.

Web 2.0 ... The Machine is Us/ing Us

viernes, enero 19, 2007

Tutorial sobre punteros


Hola de nuevo a todos. A petición de un amiguete, hoy os voy a dejar un sencillo tutorial sobre punteros. Para ello hay que tener unos conocimiento básicos, muy básicos, de programación. Por lo que aquellos que no los tengan deberán hacer un esfuerzo extra, o esperar al siguiente artículo, que espero que sea en no mucho tiempo.

El texto se puede tomar para prácticamente cualquier lenguaje de programación que soporte punteros, pero los ejemplos los mostraré haciendo uso del Lenguaje C.

Primero hablaremos de cómo un ordenador maneja los datos. Para un ordenador, datos pueden ser una letra, un número, una fotografía, una película o la discografía de nuestro grupo favorito en MP3.

La Memoria RAM


Los datos se pueden almacenar en muchos soportes: en CD, DVD, disco duro, disquete, una unidad USB, etc. pero cuando trabaja sobre ellos siempre necesita almacenarlos en la memoria RAM.

La memoria RAM se divide en páginas y/o segmentos, y estos a su vez en palabras, que se componen de bytes, que son un conjunto de 8 bits (un bit es un 0 o un 1). Para esta introducción a los punteros nos centraremos en las palabras, que es la unidad base de memoria del ordenador. El tamaño de la palabra se mide en bytes o bits, y para complicación nuestra varía según el modelo de ordenador, aunque lo normal es encontrar ordenadores que trabajan sobre palabras de 32 bits (4 bytes) o 64 bits (8 bytes). En cualquier caso no nos pararemos a complicarnos con esto. Para nosotros una palabra es una palabra y punto.

Cada palabra es como un pequeño casillero donde se pueden meter datos. ¿Cuantos datos se pueden meter en una palabra? Pues no muchos la verdad, ya que es la unidad base con la que trabaja el ordenador. En una palabra generalmente cabe un número o un carácter ortográficos. De esta forma una frase como "Hola que tal?" necesitará 13 casillas, una por cada carácter, incluyendo los espacios en blanco. Un número grande o con decimales podría ocupar más de una casilla, y una película o una canción ocupan muchas, muchas, muchas casillas.

Variables


En un lenguaje de programación, se suele asignar un nombre y un tipo a una casilla o conjunto de ellas, para luego en el propio lenguaje poder utilizar los datos de esa casilla en operaciones o sustituirlos por otros sin perder a la casilla de vista en ningún momento. A esto se le denomina una variable, y se puede definir así:

char letra = 'A';


La palabra char indica el tipo de contenido de la variable (tipo carácter) y la palabra letra el nombre que le asignamos a la variable para poder hacerle referencia más tarde. Además, en la misma línea le asignamos un contenido inicial, la letra A, pero podríamos a haber creado una variable sin asignarle ningún contenido inicial (en la práctica no es recomendable). De esta forma tenemos una casilla con el nombre letra y de contenido la letra A. Una representación gráfica se puede ver en la Figura 1.

Nuestra etiqueta letra que tenemos pegada a la casilla no se puede mover a otra casilla, pero sí se puede asignar un nuevo contenido con una sentencia de asignación, tan simple como:

letra = 'B';

Con el signo = estamos asignando un nuevo contenido a la casilla etiquetada por letra: la letra B. ¿Donde va a parar la letra A que teníamos anteriormente? Podemos decir que se pierde para siempre, o que va la cielo de las letras A. Si tenemos el siguiente código, ¿qué tendremos en la variable otra_letra almacenado al final?

char otra_letra = 'X';
otra_letra = 'Y';
otra_letra = 'Z';


La repuesta es la letra Z, ya que es lo último que hemos "introducido" en la caja y lo que por tanto nos queda al final.

Las variables, además de almacenar datos, se pueden utilizar en operaciones. En el siguiente ejemplo tenemos dos casillas con números enteros (tipo int) y almacenamos la suma en un tercero.

int a = 5;
int b = 2;
int c = a + b;


¿Que contendrá la variable c después de este trozo de código? La respuesta es que contendrá el número 7, que es la suma 5 + 2.

Punteros


Todo esto parece realmente sencillo ¿verdad? Bien, ahora vamos a pasar a los punteros, con los que mucha gente se atraganta, pero como veremos no tienen ningún misterio si se entiende bien el concepto.

Supongamos que las casillas, antes de que ningún programador decida etiquetarlas están numeradas según su posición en la memoria. Como están todas en fila esto resulta bastante sencillo. La primera tiene la dirección 0, la segunda la dirección 1, la tercera la dirección 2 y así sucesivamente. El sistema de asignación de etiquetas a las casillas es muy parecido al funcionamiento de una consigna. Nosotros le solicitamos al ordenador una casilla en la que poder meter nuestros datos; entonces el ordenador busca una casilla libre y nos entrega una ficha con el número de casilla, es decir, su dirección en la memoria. El lenguaje de programación nos permite asociar esta dirección a un nombre de variable, un alias, pero esto es sólo para facilitarnos la tarea de programación, en realidad, el ordenador sólo entiende de direcciones numéricas. Nosotros ahora podemos consultar en cualquier momento el contenido de nuestra casilla, o cambiar su contenido, ya que tenemos la reserva y la ficha con la dirección de la casilla.

Continuando con nuestro ejemplo de la consigna, imaginemos el siguiente ejemplo:

Nuestro jefe mensualmente nos deja la nómina en una casilla en la que nosotros podemos recogerla. El empleado de la consigna (el ordenador) cada vez le da una dirección de casilla distinta, según las que haya libres y ocupadas y no tenemos forma de predecir cual va a ser. Nosotros sólo podemos hablar con nuestro jefe una vez al año, por lo que no tenemos forma de saber en qué casilla está nuestra nómina cada mes. ¿Cómo se puede solucionar esto? De una forma bastante simple. La dirección de la casilla que contiene nuestra nómina es un dato, un número, y como tal puede ser almacenado en una casilla. Así que lo que acordamos con nuestro jefe es que yo tengo una casilla reservada que es siempre la misma y en la que él, mensualmente, puede dejar la dirección de la casilla donde está la nómina. De esta forma yo no tengo más que ir a mi casilla, recoger la ficha y entregársela al encargado para recoger mi nómina.

En esto mismo consiste el funcionamiento de los punteros. Un puntero es una casilla especial que en vez de contener datos directamente, contiene una dirección de alguna casilla que contiene datos. En la Figura 2 tenemos un ejemplo de un puntero (casilla azul) que contiene la dirección de una casilla tipo carácter que contiene la letra A. un puntero se declara de la siguiente forma:

char* direccion_letra;

El asterisco se emplea para especificar que la variable es un puntero, y en este caso la palabra char nos indica que la casilla apuntada contiene un carácter. Es muy importante no confundir. Un puntero sólo contiene la dirección y ocupa una casilla. Un puntero a una letra no contiene una letra, sino la dirección de la letra, un puntero a una fotografía contiene la dirección a la primera casilla de la fotografía, ya que una fotografía necesita muchas casillas para almacenarse. Un puntero a una cadena (un conjunto de caracteres, por ejemplo una frase) contiene la dirección de la primera casilla de la cadena, es decir, del primer carácter.



Como podemos ver, aún no hemos asignado ningún contenido a nuestro puntero. Vamos a crear una variable que contenga una letra y asignar a un puntero la dirección de la casilla que contiene la letra. Esto se hace mediante el operador &. El operador & delante de cualquier variable nos devuelve su dirección, en vez de su contenido.

char letra = 'A';
char* puntero_a_letra = &letra;


Ahora tenemos una variable llamada puntero_a_letra que contiene la dirección de la variable letra. Sin intentásemos imprimir por pantalla el contenido de esta variable con printf(), nos imprimiría la dirección de la letra. Si lo que queremos es acceder al dato contenido en la dirección guardada, debemos anteponer el operador * delante del nombre del puntero. El operador * interpreta que la variable que hay a continuación es una dirección y nos devuelve el contenido de esa dirección. Hay que tener cuidado, ya que si lo anteponemos a una variable que no sea un puntero, puede interpretarla como si de una dirección se tratase y obtener resultados inesperados.

¿Puedes averiguar que hace el siguiente código? ¿Qué contendrán letra1 y letra2 al final del código?


char letra1 = 'A';
char letra2 = 'B';
char* puntero = &letra1;
letra1 = 'C';
letra2 = *puntero;


La respuesta es que ambas variables contendrán la letra C. En este caso estamos creando dos variables de tipo carácter y asignamos a la primera el dato 'A' y a la segunda 'B'. Después creamos una variable puntero a carácter (char*) y le introducimos la dirección de la casilla letra1 (recordemos el operador &), más comúnmente dicho "hacer que apunte a letra1". A continuación cambiamos el contenido de letra1 por la letra C. Aunque hayamos cambiado su contenido, la dirección siempre será la misma. Finalmente cogemos el dato al que apunta puntero con el operador * (de lo contrario devolvería el contenido de puntero, es decir la dirección del dato) y lo metemos en letra2, por lo que estamos metiendo en letra2 el contenido de letra1, es decir, la letra C.

Puede que esto os resulte confuso, así que os animo a repasar esta última parte y resolver estos sencillos ejercicios antes de pasar al último apartado.

Ejercicio 1

char letra1 = 'A';
char letra2 = 'B';
char* puntero = &letra1;
letra1 = 'C';
letra2 = *puntero;


¿Contenidos de letra1 y letra2 al final del código?

Respuesta
 Pincha para mostrar


Ejercicio 2

char letra1 = 'A';
char letra2 = 'B';
char* puntero = &letra1;
puntero = &letra2;
letra1 = *puntero;


¿Contenidos de letra1 y letra2 al final del código?

Respuesta
 Pincha para mostrar



Ejercicio 3

char letra1 = 'A';
char letra2 = 'B';
char* puntero1 = &letra1;
char* puntero2 = &letra2;
puntero1 = puntero2;
letra1 = 'C';
letra2 = 'D';
letra1 = *puntero1;


¿Contenidos de letra1 y letra2 al final del código? ¿A quien apuntan los punteros al final?

Respuesta
 Pincha para mostrar


Ejercicio 4
Teniendo el código.

char letra = 'A';
char* puntero = &letra;

Indicar cuales de la siguientes asignaciones son incorrectas y podrían producir errores:

A) letra = *puntero;
B) letra = &letra;
C) letra = &puntero;
D) puntero = *puntero;
E) puntero = *(&puntero);
F) puntero = *letra;
G) *puntero = letra;
H) &puntero = letra;


Respuesta
 Pincha para mostrar


Operaciones con punteros


Ahora que ya hemos comprendido en qué consiste un puntero y como utilizarlo para tareas cotidianas.

Como dije anteriormente, un puntero es una dirección, y una dirección es un número. Por lo tanto podemos realizar operaciones matemáticas de cualquier tipo con ellos, aunque usualmente se utiliza la suma y la resta, y la multiplicación y división en casos muy específicos como el trabajo con matrices cuadradas, que no veremos aquí.

¿Qué significado tiene sumar 1 a un puntero? Como hemos dicho, todas las casillas de la memoria está numeradas consecutivamente. De esta forma, sumar 1 a la dirección contenida en un puntero es lo mismo que obtener la dirección de la siguiente casilla. Decrementar el puntero en uno significaría hacerle retroceder a la casilla anterior.

¿Tiene esto alguna utilidad? Pues sí. Como hemos visto antes, algunos datos necesitan más de una casilla para almacenarse, por lo que lo normal es guardar un puntero con la dirección de la primera casilla y acceder al resto mediante sumas a la dirección de ese puntero.

Veamos un ejemplo. Vamos a declarar una cadena. Una cadena es un conjunto de caracteres consecutivos, cada uno en una casilla de la memoria. En lenguaje C se emplea el carácter especial '\0' (barra invertida seguida de cero) para indicar el final de las cadenas, por lo que en principio no necesitamos saber su longitud; basta con recorrerla hasta encontrar el carácter especial que marca el final. Una cadena en C se declara así:

char* cadena = "Hola";

Como vemos lo que en realidad estamos declarando es un puntero a char. Efectivamente, la variable cadena es, en realidad un puntero al primer carácter de la cadena, es decir, la letra H. Otro detalle a tener en cuenta es que las cadenas se declaran usando comillas dobles, y no simples como con los caracteres. Es muy importante no confundir la cadena "H" con el carácter 'H'. Para empezar, el uso del primero nos devuelve un puntero a esa cadena, mientras que el segundo nos devuelve el dato 'H' de tipo char y no su puntero. En segundo lugar, la cadena "H" está en realidad ¡compuesta por dos caracteres! que son el propio carácter 'H', y el carácter especial que indica la final de la cadena '\0'.

Bien, veamos que podemos hacer con este puntero llamado cadena que hemos creado. Si conocemos de antemano que la longitud de la cadena es 4, sin contar el carácter de final '\0', podríamos almacenar cada una de las letras en variables de carácter con las siguientes líneas:


char* cadena = "Hola";
char letra0 = *cadena;
char letra1 = *(cadena+1);
char letra2 = *(cadena+2);
char letra3 = *(cadena+3);


Nótese el uso de los paréntesis para sumar primero a la dirección y después extraer el dato contenido con el operador *. De no usar los paréntesis, la suma no se realizaría sobre la dirección contenida en cadena, sino sobre cada uno de los datos. Dado que C trabaja con las letras como si de números se tratase, el resultado de sumar 1 a una letra es obtener la siguiente en la tabla de caracteres ASCII, normalmente la siguiente letra del abecedario. El código anterior almacenaría el carácter 'H' en letra0, 'o' en letra1, 'l' en letra2 y 'a' en letra3. Sin embargo el siguiente código,


char* cadena = "Hola";
char letra0 = *cadena;
char letra1 = *cadena+1;
char letra2 = *cadena+2;
char letra3 = *cadena+3;


almacenaría 'H' en letra0 ('H' + 0 = 'H'), 'I' en letra1 ('H' + 1 = 'I'), 'J' en letra2 ('H' + 2 = 'J') y 'K' en letra3 ('H' + 3 = 'K').

También hay que tener cuidado al sumar o restar a punteros ya que se puede acceder a zonas de memoria libres y obtener resultados inesperados, o incluso un error del sistema operativo. Esto ocurriría en el caso anterior, si por ejemplo intentamos hacer:

char letra8 = *(cadena+8);


Arrays


Un array es un vector de algún tipo de datos específicos, esto es, una reserva de un número determinado de casillas a las que accederemos con una única etiqueta. Por ejemplo, si quisiésemos guardar las temperaturas máximas de una población durante los doce meses del año podríamos declarar un array de números enteros (int) de longitud 12:


int temperaturas[12];


Esto nos reserva doce espacios en la memoria consecutivos de tipo entero. Podemos acceder a cada una de estas casillas usando el número entre corchetes, llamado índice del array. Es muy importante recordar que en lenguaje C el índice de los arrays siempre comienza por 0, y no por 1. Veamos como asignar valores a cada uno de los doce meses:


temperaturas[0]=15;
temperaturas[1]=18;
temperaturas[2]=22;
temperaturas[3]=23;
...
temperaturas[11]=12;


De momento esto es todo lo que necesitamos saber sobre los arrays. Lo importante es que, a efectos prácticos, un array es un puntero. es lo mismo acceder al primer elemento del array con temperaturas[0] que con *temperaturas, y como hemos visto que los elementos del array son consecutivos en la memoria, podemos acceder al segundo elemento del array con temperaturas[1] o con *(temperaturas+1). Igualmente podemos utilizar un puntero como si de un array se tratase. Si retomamos el ejemplo de la cadena "Hola" que puse en el apartado anterior:


char* cadena = "Hola";
char letra0 = *cadena;
char letra1 = *(cadena+1);
char letra2 = *(cadena+2);
char letra3 = *(cadena+3);


Otra forma de expresarlo podría haber sido:


char* cadena = "Hola";
char letra0 = cadena[0];
char letra1 = cadena[1];
char letra2 = cadena[2];
char letra3 = cadena[3];



Funciones: Paso por referencia y por valor



Una de las cosas que pueden parecer más descorcentantes cuando aprendemos le lenguaje C es por qué en determinadas llamadas a función es necesario anteponer el operador & a algunos parámetros, por ejemplo en la función scanf(). Como vimos antes, el operador & sirve para utilizar la dirección de memoria de un dato, en vez del dato en sí mismo. ¿Qué diferencia puede haber entre pasar un dato y pasar la dirección del mismo?

Supongamos la siguiente función, que suma dos números enteros y devuelve el resultado:


int sumar(int valor1, int valor2) {
return valor1 + valor2;
}


En esta función los parámetros se reciben por valor, es decir, cuando la llamamos se reservan nuevas casillas y se copian los valores, por lo que cualquier cambio dentro de la función a valor1 o valor2 no tendría ningún efecto en el código llamante. Supongamos que modificamos la función anterior de la siguiente forma:


int sumar_cero(int valor1, int valor2) {
valor1 = 0;
valor2 = 0;
return valor1 + valor2;
}


y la llamamos de la siguiente forma:


int num1 = 5;
int num2 = 3;
int resultado = sumar_cero(num1, num2);


Al finalizar esta ejecución la variable resultado contendrá cero, ya que en el código interno de la función sumar_cero() se convierten ambos sumandos a cero antes de sumarlos y devolver el valor. En cambio las variables num1 y num2 seguirán teniendo sus valores originales 5 y 3, ya que al pasarlas a la función estamos pasando una copia de sus valores, en unas nuevas casillas. Esto se puede ver en la Figura 3.



También podemos definir una función que reciba punteros como parámetros, o lo que es lo mismo, las direcciones de memoria que contienen. ¿Nos sirve de algo pasar una dirección de memoria a un dato, en vez de el dato en si? Cuando pasamos la dirección de memoria de una variable, la función tendrá acceso al contenido de la casilla original, y no sólo a una copia del dato, de forma que podrá realizar cambios en esa casilla, sí repercutirá en el código que llama a la función. A los parámetros que se pasan de esa forma se dice que son pasados por referencia. Podríamos rescribir la función sumar anterior de la siguiente forma:


void sumar(int valor1, int valor2, int *resultado) {
*resultado = valor1 + valor2;
}


En esta ocasión no estamos devolviendo el resultado, sino que lo estamos almacenando en el tercer parámetro de la función. Como la función recibe la dirección original donde se está almacenando el parámetro resultado, sí tiene acceso a modificar el mismo. Así, el siguiente código almacena correctamente el resultado en la variable que enviemos como parámetro:


int valor1 = 5;
int valor2 = 3;
int resultado;
sumar (num1, num2, &resultado);


Como podemos ver, necesitamos utilizar el operador & para pasar la dirección de memoria de la variable, ya que de otro modo estaríamos pasando su valor. Si la variable resultado fuera un puntero esto no sería necesario, ya que su valor en sí mismo es la dirección de un dato:


int valor1 = 5;
int valor2 = 3;
int* resultado;
sumar (num1, num2, resultado);


Rizando en rizo


Todo lo visto hasta ahora han sido unos conceptos básicos sobre punteros. En realidad permiten hacer cosas mucho más complejas, pero podremos afrontarlas sin problemas si tenemos siempre muy presente que las casillas tipo puntero son iguales que todas las demás, con la diferencia de que el dato que almacenan es una dirección. Así mismo podríamos definir un puntero que apunte a casillas de tipo puntero que apunten a casillas que contienen caracteres:


char** puntero;


Esto es la base para la construcción de matrices bidimiensionales o tridimiensionales, o los arrays de cadenas. Un array es un puntero, y una cadena también los es por lo tanto un array de cadenas es un puntero al primer elemento de una lista de punteros al primer carácter de una cadena.

También es bastante común el uso de punteros a void. Un puntero a void es un puntero genérico capaz de apuntar a cualquier casilla, independientemente del tipo que tenga. Se declara de la siguiente forma:


void* puntero;


Bueno, y eso es todo. Si tenéis alguna duda o corrección podéis dejarlo en los comentarios y estaré encantado de ayudaros en lo que pueda.