Punteros genéricos
Es posible declarar punteros sin especificar a qué tipo de objeto apuntan:
void *<identificador>; |
Usaremos estos punteros en situaciones donde podemos referirnos a distintos tipos de objetos, ya que podemos hacer que apunten a objetos de cualquier tipo.
Por supuesto, para eso tendremos que hacer un casting con punteros, sintaxis:
(<tipo> *)<variable puntero> |
Por ejemplo:
#include <iostream>
using namespace std;
int main() {
char cadena[10] = "Hola";
char *c;
int *n;
void *v;
c = cadena; // c apunta a cadena
n = (int *)cadena; // n también apunta a cadena
v = (void *)cadena; // v también
cout << "carácter: " << *c << endl;
cout << "entero: " << *n << endl;
cout << "float: " << *(float *)v << endl;
return 0;
} |
El resultado será:
carácter: H
entero: 1634496328
float: 2.72591e+20 |
Vemos que tanto cadena como los punteros n, c y v apuntan a la misma dirección, pero cada puntero tratará la información que encuentre allí de modo diferente, para c es un carácter y para n un entero.
Para v no tiene tipo definido, pero podemos hacer casting con el tipo que queramos, en este ejemplo con float.
Punteros a estructuras
Los punteros también pueden apuntar a estructuras. En este caso, para referirse a cada elemento de la estructura se usa el operador (->), en lugar del (.).
Ejemplo:
#include <iostream>
using namespace std;
struct stEstructura {
int a, b;
} estructura, *e;
int main() {
estructura.a = 10;
estructura.b = 32;
e = &estructura;
cout << "puntero" << endl;
cout << e->a << endl;
cout << e->b << endl;
cout << "objeto" << endl;
cout << estructura.a << endl;
cout << estructura.b << endl;
return 0;
} |
Ejemplos
Veamos algunos ejemplos de cómo trabajan los punteros.
Primero un ejemplo que ilustra la diferencia entre un array y un puntero:
#include <iostream>
using namespace std;
int main() {
char cadena1[] = "Cadena 1";
char *cadena2 = "Cadena 2";
cout << cadena1 << endl;
cout << cadena2 << endl;
//cadena1++; // Ilegal, cadena1 es constante
cadena2++; // Legal, cadena2 es un puntero
cout << cadena1 << endl;
cout << cadena2 << endl;
cout << cadena1[1] << endl;
cout << cadena2[0] << endl;
cout << cadena1 + 2 << endl;
cout << cadena2 + 1 << endl;
cout << *(cadena1 + 2) << endl;
cout << *(cadena2 + 1) << endl;
return 0;
} |
Aparentemente, y en la mayoría de los casos, cadena1 y cadena2 son equivalentes, sin embargo hay operaciones que están prohibidas con los arrays, ya que son punteros constantes.
Otro ejemplo:
#include <iostream>
using namespace std;
int main() {
char Mes[][11] = { "Enero", "Febrero", "Marzo", "Abril",
"Mayo", "Junio", "Julio", "Agosto",
"Septiembre", "Octubre", "Noviembre", "Diciembre"};
char *Mes2[] = { "Enero", "Febrero", "Marzo", "Abril",
"Mayo", "Junio", "Julio", "Agosto",
"Septiembre", "Octubre", "Noviembre", "Diciembre"};
cout << "Tamaño de Mes: " << sizeof(Mes) << endl;
cout << "Tamaño de Mes2: " << sizeof(Mes2) << endl;
cout << "Tamaño de cadenas de Mes2: "
<< &Mes2[11][10]-Mes2[0] << endl;
cout << "Tamaño de Mes2 + cadenas : "
<< sizeof(Mes2)+&Mes2[11][10]-Mes2[0] << endl;
return 0;
} |
En este ejemplo declaramos un array Mes de dos dimensiones que almacena 12 cadenas de 11 caracteres, 11 es el tamaño necesario para almacenar el mes más largo (en caracteres): "Septiembre".
Después declaramos Mes2 que es un array de punteros a char, para almacenar la misma información. La ventaja de este segundo método es que no necesitamos contar la longitud de las cadenas para calcular el espacio que necesitamos, cada puntero de Mes2 es una cadena de la longitud adecuada para almacenar el nombre de cada mes.
Parece que el segundo sistema es más económico en cuanto al uso de memoria, pero hay que tener en cuenta que además de las cadenas también en necesario almacenar los doce punteros.
El espacio necesario para almacenar los punteros lo dará la segunda línea de la salida. Y el espacio necesario para las cadenas lo dará la tercera línea.
Si las diferencias de longitud entre las cadenas fueran mayores, el segundo sistema sería más eficiente en cuanto al uso de la memoria.
Ir al Principio
Comentarios