Curso de C++ (Página 13c)

pagina013b Principal pagina013d

CAPITULO 13c Tipos de variables IV: Punteros 1

Punteros genéricos.

Es posible declarar punteros sin tipo concreto:

void *<identificador>;

Estos punteros pueden apuntar a objetos de cualquier tipo.

Por supuesto, también se puede emplear el "casting" con punteros, sintaxis:

(<tipo> *)<variable puntero>

Por ejemplo:

#include <iostream.h>
 
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.

Nota: el tipo de línea del tercer "cout" es lo que suele asustar a los no iniciados en C y C++, y se parece mucho a lo que se conoce como código ofuscado. Parece como si en C casi cualquier expresión pudiese compilar.

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.h>
 
struct stEstructura {
   int a, b; 
} estructura, *e;
 
int main() { 
   estructura.a = 10;
   estructura.b = 32;
   e = &estructura;
 
   cout << "variable" << endl;
   cout << e->a << endl;
   cout << e->b << endl;
   cout << "puntero" << 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.h>
 
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; 
  }

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.h>
 
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 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 se almacenan 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.


pagina013b Principal pagina013d