Punteros

De Proyectos
Saltar a: navegación, buscar

Caracteristicas

  • Un puntero no es más que una variable estática cuyo contenido es una dirección de memoria
  • Para obtener la dirección de memoria de una variable se usa el operador de dirección"&"
int i;
printf("direccion de memoria de la variable: %d", &i);
  • Para acceder al contenido de una posición de memoria se utiliza el operador de indirección "*"
  • Cuando se define un puntero se hace según un tipo de variable. Ese puntero solo puede apuntar a ese tipo de varaibles
  • Los operadores "& y *" tiene mas prioridad que los operadores binarios (+, -, ...)
  • Se pueden asignar punteros entre ellos:
int a = 8;
int *p = &a;
int *q;
q = p;
  • Una buena práctica es inicializar los punteros a NULL
int *p = NULL;

Operaciones con Vectores

  • Podemos manipular la dirección de memoria del puntero
int *p;
int a[10];

p = a;
printf("%d", *(p+0)); //Primera posicion del vector a ;
printf("%d", *(p+1)); //Segunda posicion del vector a;
  • Hay que dejar claro que cuando se hace
int *p;
int a[10] = {1,2,5,9,5,7,8,2,1,7};

p = a;
printf("%d", *(p+1)); //Si la dirección de memoria de p es 1, con p+1 no pasa a valer 2, vale p+(1*sizeof(int)). Por tanto cuando si p es un puntero a entero (un entero ocupa 4 bytes)
                      //cada vez que desplazamos n numeros a p lo que hacemos es desplazar n posiciones de memoria * lo que ocupa un entero


posiciones
de memoria      1     2     3     4     5     6
             -------------------------------------
   array     |                       |           |
     a       |           1           |        2  |
             |                       |           |
             -------------------------------------
             \----------  ---------/ \-----------
                        \/
         espacio que ocupa un int (4 bytes)

Esto es una explicación gráfica de a lo que me refiero. El puntero p esta a puntando a la posicion de memoria 1, pero un int ocupa 4 bytes (es decir que se necesitan 4 casillas para poder almacenar un int).
Cuando hago la operación *(p+1), p pasa a valer 5, que es donde empieza el siguiente int del array a.
  • Lo mismo se puede hacer restando


  • El operador "[ ]" también se puede usar en punteros, por tanto esto es equivalente:
int a[10];
int *p;

p = a;
*(p+2);
p[2];
  • Cuando se utilizan numeros negativos con el operador [ ] se comporta de manera diferente que con arrays:
int a[10];
int *p;
p = &a[5];

//Si escribo esto estoy intentando acceder a un lugar no valido
a[-2];

//En cambio en punteros, escribir esto
p[-2]

//Equivale a

*(p-2) // Y como p apunta al elemento 6 del array a, ahora pasa a apuntar al elemento 4

Punteros y Vectores

Todos los vectores son en realidad punteros

 int a[10];
 int *p;

 p = a; //Ahora p puede acceder a las "casillas de a". Se escribe así porque la variable a es un puntero y estamos asignando la dirección de memoria a la que apunta a a p

 //Estos dos printfs son equivalentes
 printf("%d", a[0]);
 printf("%d", *p);

 //Estos dos printfs son equivalentes
 printf("%d", a[1]);
 printf("%d", *(p+1)); //Sumamos 1 a la dirección de memoria haciendo que p apunte al siguiente elemento del vector

 //En este ejemplo vemos que para imprimir un caracter y asignarle un valor lo hacemos normalmente:
 char *c;
 char b = 'H';
 c = &b;
 printf("%c", *c); //Cuando se imprime se pone el * para imprimir el dato que hay en la casilla a la cual apunta c.

 //Aqui vemos que en una cadena de caracteres las operaciones de imprimir y asignar un valor son diferentes a como se hacen con el caracter y son similares a como se hacen con vectores de cadenas.
 //Esto es por lo dicho anteriormente, los vectores de cadena son punteros.
 //Estos dos ejemplos son equivalentes, los dos imprimiran Fran
 char *cadena;
 cadena = "Fran";
 printf("%s", cadena);

 char cadena2[]="Fran";
 printg("%s", cadena2);

 //Printfs equivalentes. Estos dos imprimiran F
 char cadena[]="Fran";
 printf("%c", cadena[0]);
 printf("%c", *cadena);

Explicación:

     Ejemplo1                        Ejemplo2
char cadena2[]="Fran";    ==    char *cadena = "Fran";
printf("%s", cadena2);    ==    printf("%s", cadena);

Con estos dos ejemplos vemos que cuando se hace la declaracion de una cadena de caracteres y luego se imprime es igual que como se hace con un puntero.
Cuando se imprime un puntero que apunta a un vector lo que se imprime es la primera posicion del vector. Para poder ir recorriendo el vector se le va sumando +1 al contenido de la memoria, asi si va desplazando entre las casillas.
Por tanto cuando ponemos en el printf la cadena lo que hacemos es pasarle al printf la dirección de memoria y con el operador %s indicamos que es un vector de caracteres y que tiene que ir recorriendolo todo.

Sabiendo esto y sabiendo de operaciones de punteros podemos hacer las equivalencias:

char cadena="Fran";
printf("%c", cadena[0])    ==    printf("%c", *cadena);   //Primera posicion del vector
printf("%c", cadena[1])    ==    printf("%c", *(cadena+1); //Segunda posicion del vector

Punteros Genéricos

  • Son los punteros que no especifican a que tipo de variable apuntan, por tanto pueden apuntar a distintos tipos de objetos
  • Para poder manipular punteros genericos se necesita hacer casting
int a=10;
int c= 'H';
void *p; //Asi se declaran

p = &a;
printf("%d\n", *(int *)p); //El valor impreso sera 10
               \-------/
                   |___ Esto se llama casting

p = &c;
printf("%c", *(char *)p)); //El valor impreso sera H