PUNTEROS

La potencia de C radica en gran medida, en el poder que da el  lenguaje al programador para modificar el contenido de la memoria a voluntad.

Mediante punteros podemos leer/escribir en cualquier parte de la memoria.

Un puntero es una variable que contiene una dirección de memoria. Para declarar un puntero antecedemos el * al nombre de la variable.

        char *pChar; //Declara un puntero al tipo char
        int *pVal;      //Declara un puntero al tipo int


Aclaración:
He utilizado la notación de C++ para los comentarios en línea. Estos son soportados en los compiladores de última generación de C.

Los comentarios de cada puntero indican, en cada caso, que declara un puntero al tipo char, el primero, e int el segundo. 
¿Por qué un puntero al tipo y no un puntero del tipo ..?
La respuesta es que el compilador utiliza el tipo para calcular la cantidad de memoria que tiene que referenciar. Un char no ocupa los mismos bytes que un int (por ejemplo).

Al operador asterisco, *, se le llama operador de indirección. Se utiliza para declarar punteros y para acceder al contenido de la dirección apuntada.
Tenemos otro operador, &, llamado operador de dirección, este operador devuelve la dirección de memoria de su operando.

Al declarar un puntero, antes de asignarle un valor, contiene un valor desconocido (para el programador) Por convenio debe asignarse un valor nulo a un puntero que no esté apuntando a ningún sitio.

El siguiente ejemplo imprime el valor de una variable apuntada por un puntero.


Esta es la salida del programa en mi equipo.


Los punteros se utilizan también para pasar parámetros por referencia a una función.

El siguiente ejemplo pasa las variables valor1 y valor2 por referencia por lo que la función _hace_algo() modifica el valor de ambas variables.



La salida de este programa sería:

Valor1 contiene: 235
Valor2 contiene: 39459

Este vídeo explicativo de punteros se lo debemos a Christian León




Punteros a estructuras.
Podemos declarar uno, o varios punteros y apuntarlos a una estructura (recordemos que una estructura es un conjunto de datos de diferente tipo agrupados bajo un mismo nombre). Normalmente accedemos a los campos de una estructura mediante el operador punto.

                    struct my_struct{
                              int edad;
                              char nombre[20];
                    } _mySTR;

                  _mySTR.edad = 27;  //se accede a los campos de la estructura mediante el operador punto.

Ahora declaramos un puntero a my_struct y lo apuntamos al objeto _mySTR para acceder a sus campos

                   struct my_struct *ptr;

                   ptr = _mySTR;

Para acceder a los campos desde el puntero NO utilizamos el operador punto si no el operador flecha
->

                    ptr->edad = 35; //Se utiliza el operador flecha -> para acceder a los campos de la 
                    printf("Como te llamas: ");   //estructura
                    scanf("%s",&ptr->nombre);


Aritmética de punteros.
Sólo se pueden hacer dos operaciones aritméticas con los punteros, sumar y restar.

Al incrementar un puntero, este apuntará a la siguiente posición de memoria según el tipo base.
Al decrementar un puntero, este apuntará a la anterior posición de memoria según el tipo base.

/* aritmética de punteros */
#include <stdio.h>

int main(void)
{
char arrayChar[4]={'H','o','l','a'};

char *pChar;
int i;

pChar = arrayChar; // Se inicializa el puntero a la primera posición del array

for(i=0; i< 4; i++)
{
printf("%c", *(pChar + i)); //Se incrementa el puntero en cada iteración del bucle
}
printf("\n");
   pChar = arrayChar; //Se inicializa el puntero a la primera posición del array
   pChar += 3; //Se ajusta la posición apuntada incrementado en 3 el puntero

for(i= 0;i < 4; i++)
{
printf("%c",*(pChar - i)); //Se decrementa el puntero en cada iteración del bucle
}
printf("\n");

return 0;
}

Este ejemplo declara un puntero al tipo char y lo apunta al array arrayChar. Primero muestra el contenido en orden ascendiente y después en orden descendiente

Hola
aloH

Un puntero puede apuntar a un puntero, a esto se le denomina indirección multiple o puntero a puntero.
Para declarar un puntero a otro puntero se ponen dos * de la siguiente manera:

int **ppInt;

De esta forma indicamos al compilador que ppInt es un puntero a un puntero int