viernes, 26 de noviembre de 2010

Punteros (puntos extra)

Punteros

Las variables de C ocupan determinadas posiciones de memoria y las variables de tipo puntero están pensadas para contener estas direcciones de memoria. Veamos cómo se declara un puntero:

int * p;

La variable p se dice que es de tipo "puntero a int".

De igual manera podemos definir un puntero a cualquier otro tipo de dato como, por ejemplo, double:

double * punt;

Un puntero a int puede contener la dirección de memoria donde se aloja una variable de tipo int. Un puntero a char puede contener la dirección de memoria donde se sitúa una variable de tipo char.

Sin embargo, no podemos asignar direcciones directamente a los punteros. Incluso si supiéramos que la variable numero de tipo int ocupa la dirección 904 de memoria, no podríamos hacer la siguiente asignación:

p = 904; /* no es correcto */

Para asignar a p la dirección que ocupa numero tenemos que utilizar el operador &, el mismo que se utiliza en scanf, y no es necesario saber el valor concreto de la posición de memoria:

int numero;
p = №

Se dice que p apunta a numero.

Una vez que tenemos un puntero apuntando a una variable, podemos acceder al contenido de la variable a través del puntero. Por ejemplo, las dos instrucciones siguientes son equivalentes y ambas asignan a numero el valor 3:

numero = 3;
*p = 3;

Dicho de otra forma, la expresión *p es sinónimo de numero.

Dentro de poco veremos que este mecanismo nos permitirá acceder a variables locales de una función desde otras funciones, que es la principal utilidad de los punteros.

Punteros en java
Hay un par de ideas sobre java muy extendidas: java no tiene punteros y en java todo se pasa por referencia.

La realidad, es que java se entiende mucho mejor si lo pensamos exactamente al revés. En java sólo hay punteros (con excepción de los tipos primitivos) y en java todo se pasa por valor (por copia).

Por ejemplo, en C++ hacemos esto

MiClase a;

y ya está todo correcto. La variable a está perfectamente inicializada. Si en java hacemos eso, tenemos una variable a sin inicializar. Es necesario hacerle un new, exactamente igual que un puntero en C++

MiClase a = new MiClase(); // Esto en Java
MiClase *a = new MiClase(); // Esto en C++

// o este otro tipo de inicialización extrañamente parecida ...

MiClase a = null; // en java
MiClase *a=NULL; // en C++

La única diferencia es la notación con el asterisco. Si pensamos que en java TODO son punteros, no es necesario poner el asterisco para distinguir lo que es puntero de lo que no lo es, por lo que símplemente lo han quitado.

Ahora imaginemos un método que recibe una clase y que le hacemos una llamada

// en java...
void medodo (MiClase a)
{
a = new MiClase();
}
...
MiClase b = null;
metodo (b);

Bueno, pues cuando salimos del método b sigue valiendo null, "apuntando a null". Eso quiere decir que a y b son variables disintas, es decir, se ha pasado la variable b por valor al método.

¿Cómo podemos crear una nueva instancia y devolverla?. En java no queda más remedio que hacerlo en el return, es imposible hacerlo a través de parámetros. Sin embargo, en C++ tenemos más posibilidades. Podemos usar un puntero al puntero, es decir, hacer esto

void metodo (MiClase **a)
{
*a = new MiClase();
}
...
MiClase *b=NULL;
metodo (&b);

o bien, incluso usar referencias de verdad

// El & en la declaración es lo que hace que realmente sea una referencia.
void metodo (MiClase * &a)
{
a=new MiClase();
}
...
MiClase *b=NULL;
metodo (b);
// Aqui b apunta al MiClase creado dentro del método.

Punteros en C++

Haciéndolo así, el puntero b de fuera del método y el puntero a del parámetro son exactamente la misma variable. Ojo, no quiero decir que sean dos punteros distintos que apunten al mismo lado, sino que son realmente el mismo puntero. Cuando hacemos que a apunte a otro sitio, b también apuntará al mismo sitio. Esto es lo que yo entiendo realmente por referencia.

El tratamiento de punteros en C++ utiliza su propio vocabulario con el que es aconsejable familiarizarse desde el principio. En general decimos coloquialmente que un puntero "apunta" o "señala" a un objeto determinado cuando su valor (del puntero) es la dirección del objeto (dirección de memoria donde comienza su almacenamiento). El objeto señalado por el puntero se denomina referente. Por esta razón también se dice que el puntero "referencia" al objeto. El operador que permite obtener la dirección de un objeto (para asignarlo a un puntero) se denomina operador de "referencia" y la operación de obtener el referente a partir del puntero se denomina "deferenciar".

Ejemplo :
#include <iostream.h>

void Invertir(char *s) {
  char *t= s;

  while (*t)
    t++;
                                // Pongo t al final de la cadena. En el caracter '\0'
  t--;                         // Me pongo en el anterior

  while(s < t) {                // Hasta que lleguemos al medio
    char Temp= *s;
    *s++= *t;
    *t--= Temp;                 // Intercambiar
  }
}

void main() {
  char *s= "SOLOS NABOS ES AVE Y NADA";

  Invertir(s);
  cout << s;
}
 
aqui les deje la informacion sobre punteros en 3 lenguajes diferentes
aunque son lenguajes tal ves no muy avansados , creo que les dara una idea
de como utilizar los punteros.
cualquier duda por favor diganmela 

3 comentarios:

  1. hey jurgen , namas te recomiendo que cambies tu plantilla porque con ese fondo no se ven mucho las letras :s,

    ResponderEliminar
  2. jaja , nunca te tengo feliz con mis plantillas , dejame ver que puedo hacer

    gracias por el consejo

    ResponderEliminar
  3. A mí tampoco me haces feliz con tus plantillas. +3 en segundas

    ResponderEliminar