¿Que es un Puntero?

A continuación algunas definiciones de Punteros:

Un apuntador o puntero es una variable que contiene la dirección de una variable. — Kernighan&Ritchie, El Lenguaje de Programación C
Los apuntadores son variables que contienen direcciones de memoria como sus valores. Por lo general una variable contiene directamente un valor especifico. Un apuntador, por otra parte, contiene la dirección de una variable que contiene un valor especifico. — Deitel&Deitel, Como programar en C/C++
En ciencias de la computación, un puntero es un objeto del lenguaje de programación, cuyo valor se refiere a (o “apunta a”) otro valor almacenado en otra parte de la memoria del ordenador utilizando su dirección. Un puntero referencia a una ubicación en memoria, y a la obtención del valor almacenado en esa ubicación se la conoce como desreferenciación del puntero. — Colaboradores de Wikipedia, “Puntero (informática)

Entonces, los punteros son variables especiales que guardan direcciones de memoria y que podemos obtener tanto el valor guardado en esa dirección de memoria como la dirección misma. Cuando obtenemos el valor guardado en dicha dirección llamamos a ese proceso desreferenciación.

Declaración de un puntero en C

Para poder usar una variable puntero debemos declararla de la siguiente forma:

#include <stdio.h> 

int main(){

int cedula = 12395448;
int *ptr_cedula = &cedula;

}
Representación gráfica de un puntero.

En este corto ejemplo estamos declarando una variable de tipo entero llamada cedula, acto seguido declaramos una variable puntero llamada ptr_cedula y en el mismo paso asignamos la dirección de memoria de cedula a ptr_cedula.

Como puede verse en la imagen, la información que se guarda dentro de ptr_cedula es la dirección de memoria de la variable cedula

Es importante destacar que en este punto lo siguiente:

  • Nótese que el tipo de variable (int) debe coincidir.
  • Y que para poder usar un puntero es necesario guardar la dirección de memoria de una variable ya existente.

Mas adelante aprenderemos como usar un puntero sin declarar una variable antes.

Operador *

Como hemos visto, para declarar una variable como puntero hay que anteponer el operador * frente al nombre de la variable. Esto le indica al compilador que esta variable va a manejar direcciones de memoria y no valores normales.

int *ptrEntero; 
float *ptrFlotante;
char *ptrCaracter;

En la linea anterior puede verse la declaración de tres variables puntero, cada una con el tipo de valor que le es permitido manejar.

Fuera de la declaración, el operador * se usa para hacer mención o para referirse al contenido que esta guardado en la dirección de memoria que guarda la variable puntero.

Cuando usamos una variable puntero sin el operador * el valor devuelto por la variable sera el de la dirección de memoria.

Usando los datos de la imagen de arriba la siguiente linea de código:

printf("%p", ptr_cedula);

La salida del comando printf seria la siguiente:

0x0000FFFF

Ahora bien, para obtener el contenido guardado en la dirección de memoria que el puntero contiene usamos el operador * para obtenerla.

La siguiente linea de código:

printf("%d", *ptr_cedula);

Da como salida la siguiente:

12395448

Operador &

¿Y como hacemos para guardar obtener en que parte de la memoria esta guardada una variable?

variablePtr = &variableNormal;

Anteponiendo el & frente a cualquier variable obtendremos en que parte de la memoria esta ubicada.

Nótese que la variable puntero no esta acompañada del operador * en esta linea. ¿Por que?

Punteros y parámetros

El paso de parámetros y los punteros están estrechamente relacionados. En C el paso de parámetros puede tener dos formas:

  • Por valor
  • Por referencia

Parámetros por valor

Es la forma normal de pasar una variable a una función. El valor de la variable se copia y se guarda en la variable parámetro.

En el siguiente ejemplo:

int suma(int a, int b){
int total;
total = a + b;
return total;
}
... 
int bolsillo, cuenta; 
int total;
total = suma (bolsillo, cuenta);

Si modificamos a o b dentro de la función los valores de bolsillo y cuenta no se verán afectados.

Parámetros por referencia

Al hacer paso de parámetros por referencia nos valemos de los punteros para afectar valores que de otra forma no podrían ser modificados. Se transmite es la dirección de memoria donde esta ubicada la variable.

int suma(int *a, int *b){ 
int total;
total = *a + *b;
return total;
}
... 
int bolsillo, cuenta; 
int total;
total = suma (&bolsillo, &cuenta);

Si modificamos a o b dentro de la función los valores de bolsillo y cuenta si se verán afectados.

Nota: Los arreglos siempre se pasan por referencia.

Aritmética de punteros

De igual forma que cualquier otra variable, sobre los punteros pueden hacerse operaciones aritméticas. Con los apuntadores se pueden efectuar las siguientes operaciones aritméticas:

  • incremento (++)
  • decremento ( — )
  • sumar un entero (+ , +=)
  • restar un entero (- , -=)
  • restar dos apuntadores

Pero estas operaciones no funcionan de la misma forma que con las variables normales.

En C cada tipo de variable tiene un tamaño especifico en bytes, dicho tamaño varia de arquitectura en arquitectura y de sistema operativo en sistema operativo.

Por tanto si hacemos lo siguiente

int *ptr_entero; 
... 
ptr_entero = &variable_entera; 
ptr_entero+=2;

No estamos sumando 2 a la dirección de memoria, estamos sumando 2 multiplicado por el tamaño del tipo de dato del puntero. Como un entero usualmente mide 2 bytes, el compilador sumara 2 * 2 a la dirección de memoria.

Nota: Es importante tomar en cuenta que los tipos de variable no tienen las mismas longitudes a la hora de hacer programas que serán ejecutados en múltiples plataformas.

Punteros y arreglos

Cuando hacemos uso de arreglos como por ejemplo:

int notas[10];

Inadvertidamente estamos haciendo uso de punteros. La linea anterior le dice al compilador que cree un espacio de memoria para guardar diez variables de tipo entero. Y dicho espacio de memoria también puede ser manipulado haciendo uso de los punteros y su aritmética.

Las siguientes lineas son equivalentes:

int valor4 = notas[3];
int valor4 = *(notas + 3);

Por eso es que para pasar un arreglo como parámetro hacemos lo siguiente:

float promedio (int *arreglo, int cuantos) { 
int contador = 0;
int total = 0;
for(int contador =0; contador < cuantos; contador++){
total=total+arreglo[contador];
}
return (float)(total/cuantos);
}
int notas[3] = {3, 10, 15};
int promedio = promedio(notas, 3);

La variable que recibe el arreglo en la función es declarada como un puntero aunque es usada como un arreglo.

Si queremos recorrer un arreglo usando la aritmética de punteros hacemos:

int arreglo[5] = { 1, 2, 3, 4, 5 }; 
int contador = 0;
for(int contador =0; contador < 5; contador++){
printf("%d\n", *(arreglo + contador));
}

Ejercicios propuestos

  1. Para cada formula de área de las figuras básicas (circulo, triangulo, cuadrado, rectángulo). Genere dos funciones. Una con paso de parámetros por valor y otra con paso de parámetros por referencia.
  2. Codifique un programa que sume 2 a un puntero de tipo entero. Imprima el valor de memoria al que apunta el puntero antes y después de la suma. Realice la misma operación con punteros a otros tipos de datos (char, double, float, long int).
  3. Investigue cual es la relación de los punteros y los arreglos.
  4. Codifique un programa que imprima un vector de flotantes haciendo uso de aritmética de punteros.
Like what you read? Give Kalim Al Razif a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.