Bueno he aqui mi primer articulo que sera evidentemente corto, aunque el tema es muy grande. En este documento intento dar a entender y comenzar a manejar Punteros en C++.
Primeramente debemos entender que es un Puntero:
Bueno basicamente en C++ se puede almacenar de 2 formas las variables:
1. Estaticamente
2. Dinamicamente
1.- Creacion de Variables Estaticas.
Bueno esta es la forma mas facil de crear una variable, basta que creacemos una linea, para definir una variable:
int variable = 3;
claro que tambien podemos hacerlo de la forma larga:
int variable;
variable = 3;
asi que ya hemos visto 2 formas para definir una variable estatica, pero ahora vayamos un poco mas profundo y pensemos en que es una variable estatica?
Primeramente no debemos confundirla con una constante, ya que no tienen mucho en relacion, como segundo y cayendo en la definicion exacta de una variable estatica, desde mis propias palabras diria que una variable estatica es aquella que al iniciarse la aplicacion se reserva un espacio en la memoria aleatoria o tambien llamada volatil (RAM, cache, etc) y este espacio queda hasta que la aplicacion se cierre, esto seria el concepto en las mas llanas palabras que se me pudieron ocurrir, ahora pasemos a la almacenacion de variables de forma dinamica.
2. Creacion de Variables Dinamicas
Tambien conocidos como punteros, son aquellos que como su nombre lo dice almacenan un espacion en la memoria virtual dinamicamente, o sea mientras no sea creada la variable dentro del programa, el espacio en la memoria volatil esta libre, pasemos a un ejemplo, por supuesto lo haremos como anteriormente hice, o sea de ambas formas, de la forma larga y de la forma corta:
int *puntero = new int;
*puntero = 3;
y ahora de la forma larga:
int *puntero;
puntero = new int;
*puntero = 3;
Ahora hablare sobre los principales aspectos de ambos ejemplos. En el primer ejemplo se ve claramente que hemos creado un puntero llamado puntero (perdon por la analogia), y luego hemos dado a este puntero un valor, y este es el numero 3; ahora en nuestro segundo ejemplo hemos hecho lo mismo, pero ahora uds. creeran que hice un error en el codeo y me falto un asterisco en la 2da linea, pues dejemne decirles que no, tal y como ven el ejemplo, asi es como se lo hace.
3. Liberando espacio en la Memoria
Bueno pero si son variables dinamicas y existen desde que las declaramos, cuando estas terminan de existir?
Pues bien, esto se hace liberando memoria usando la palabra reservada Delete, y esto se hace la la siguiente forma: (Usare un ejemplo completo pero corto y entendible para todos los lectores):
int *ptr = new int;
*ptr = 3;
cout << "El valor apuntado de *ptr es: " << *ptr << endl;
delete ptr;
Bueno aqui hemos reservado memoria para el puntero y al mismo tiempo lo apuntamos a un objeto INT, luego le en el valor de la direccion apuntada por *ptr le puse 3 como valor, lo imprimi en pantalla y por ultimo lo borre.
Si se dan cuenta lo que borramos es la direccion a la que apunta, eso quiere decir que si queremos crear de nuevo alguna direccion a la cual apunte ptr deberiamos hacer algo asi (ejemplo superior + nuevo codigo):
int *ptr = new int;
*ptr = 3;
cout << "El valor apuntado de *ptr es: " << *ptr << endl;
delete ptr;
ptr = new int;
*ptr = 4;
cout << "El NUEVO valor apuntado de *ptr es: " << *ptr << endl;
delete ptr;
Como ven hemos creado el puntero, este estara para siempre en el programa si es que es puntero global, y solo durante la vida de la funcion si es que es local (de la misma manera que existen variables locales y globales, los punteros pueden tener las mismas caracteristicas).
Algo que deben saber, es que para poder poner otro valor a un puntero que ya tiene una direccion a la cual apuntar NO es necesario borrar primero su direccion para luego apuntar a otro valor, lo pueden hacer como con variables normales, de esta forma:
int *ptr = new int;
*ptr = 3;
*ptr = 5;
*ptr = 9;
delete ptr;
Ahora vamos ha hablar sobre punteros globales y locales ya que hice mencion de estos antes, pero como ya fue explicado solo queria dar un punto interesante a saber, para que un puntero sea global basta la declaracion del puntero en si, NO hace falta indicar a donde debe apuntar este nuevo puntero, o sea en 2 ejemplos seria asi (Ambas formas son correctas):
int *ptr1;
int function(){
ptr1 = new int;
*ptr = 3;
delete ptr;
return 0;}
El ejemplo 2 quedaria asi:
int *ptr2 = new int;
int function(){
*ptr2 = 5;
delete ptr2;
return 0;}
Bueno esto no se si pasa en todos los compiladores o si solo en el que yo uso: Dev-C++ (Compania: Bloodshed, es gratuito), tambien Visual C++ Express (Compania: Microsoft, tambien gratuito), lo que sucede es que con punteros no puedo poner un valor a la direccion que estan apuntado cuando esta en la seccion global, o sea me refiero a esto:
int *ptr = new int;
*ptr = 9;
int main(){
return *ptr;}
Aqui obtengo error al momento de compilar, me ha pasado en ambos compilatores, asi que creo que de forma general no esta permitido, o a lo mejor me equivoco, pero bueno para los que usen cualquiera de los compilatores que nombre arriba, no pueden hacer este tipo cosas.
Bueno creo que esto fue una breve introduccion sobre punteros, en estos ejemplos solo hemos usado INT, como comienzo esta bien, aunque FLOAT, DOUBLE (y otros relacionados con numeros) tampoco hay problemas con aquellos, pero con el que es completamente diferente es cuando usamos CHAR, la forma de codeo cambia drasticamente en algunas partes pero todo sera claro y facil cuando pasemos a leer el articulo sobre Punteros a Char que escribire proximamente.
4. Explicacion profundizada de los Punteros.
Bueno para los que ya se complicaron y no entienden, les recomiendo leer de nuevo y si es que asi todavia no se entiende, pues les ofrezco mi ayuda por medio del foro, ya que lo que se viene ahora es un poco mas complicado.
Como diferenciar en un codigo si una variable es un dinamica o estatica? Esto lo notamos al ver una de las cosas mas notorias, y es el simbolo asterisco " * " apegado al lado izquierdo del nombre de la variable, claro que otra forma es al ver que para el puntero debemos crear una reservacion de memoria
int *ptr = new int;
int a;
Pero si tenemos un ejemplo asi:
int *ptr;
int a;
Seria dificil saber cual es cual si no fuera por el simbolo del asterisco ya que aqui no vemos ninguna reservacion de memoria.
Entonces los punteros que es lo que son principalmente?
Bueno los punteros se almacenan en un registro en la RAM, y estos contienen dentro de este informacion, y que tipo de informacion? Poseen la direccion hacia otro registro en la RAM el cual es el que posee el valor. Para evitar la confusion voy a escribir de nuevo el codigo y a explicar cada linea, para esto usare el ejemplo de la forma larga ya que asi se dara a entender mas:
int *ptr; /* Hemos creado un puntero de nombre ptr, este digamos esta en el registro 01h en la RAM, eso es todo */
ptr = new int; /* Hacemos que lo que contenga este registro del puntero (01h) sea otro direccion de la RAM y esta direccion contenga un valor INT (integer = entero) */
*ptr = 3; /* Aqui hemos indicado que es lo que contendra la nueva direccion que hemos referenciado en nuestro puntero.*/
Yo se que es dificil entender todo esto, a mi me costo mucho, pero con el tiempo se entiende a los punteros su funcion y sus utilidades, creanme yo todavia tengo problemas con punteros, pero claro esta que no este tipo de conceptos, lo mio esta entre punteros bidimensionales y clases, pero eso algun dia escribire y entenderan por lo que estoy pasando, aunque cada dia se aprende un poco mas y asi se evita caer en errores, y mas que todo cuando se comienza a entender realmente bien, uno comienza a reir por lo que nota lo sencilla que es...bueno basta por el momento de vivencias y regresemos a nuestro primer encuentro con punteros y su reconocimiento y mas que todo primeros pasos trabajando con estos.
tratare de crear un pequeno diagrama de una RAM, y tratare de explicar todo sobre el puntero que acabamos de inicializar:
|------------------|
| 01h | --> puntero ptr;
|------------------|
| 02h | --> a donde apunta ptr, aqui encontramos el valor 3 que pusimos al puntero;
|------------------|
Bueno estos valores en Hexadecimal, son 2 alocaciones de memoria, no nos importa el tamano en bits que contengan, lo unico que nos importa es la explicacion detallada de lo que son punteros, bueno ahora unas caracteristicas de los punteros, los punteros poseen 3 valores:
1. Su propia direccion en Memoria (ej.: ptr)
2. La direccion en Memoria al que apuntan (ej.: &ptr)
3. El valor que posee esta direccion apuntada por el puntero en la Memoria. (ej.: *ptr)
Se llaman punteros, por el simple hecho de su labor, "Apuntan", pero a donde apuntan? Apuntan a otras direcciones. Vamos a usar de nuevo nuestro ejemplo de la creacion del puntero *ptr y usemos el objeto COUT para poder mostrar los valores que posee nuestro PTR;
int *ptr = new int;
*ptr = 3;
cout << ptr << "\t" << &ptr << "\t" << *ptr << endl;
Bueno y que nos aparecera en cada uno de estos valores de ptr:
En ptr ==> aparecera la direccion de memoria del puntero o sea 01h;
En &ptr ==> aparecera la direccion de memoria a donde apunta el puntero o sea 02h;
En *ptr ==> aparecera el valor de la direccion de memoria a donde apunta el puntero o sea 3;
Creo que con esto ahora sera mas facil entender la forma larga de la declaracion de un puntero al que le queremos poner el valor de 3, repitiendolo y explicandolo sera mas facil ahora:
int *ptr; /* hemos declarado el puntero o sea hasta ahora en nuestra Memoria esta ocupada la direccion 01h;
ptr = new int; /* esto hace que la direccion de memoria del puntero apunte a un nuevo registro de tipo int, en nuestro famoso ejemplo esta direccion sera 02h.*/
*ptr = 3; /* ahora lo que hemos hecho fue poner el valor que contendra este registro de tipo int al que el puntero apunta;
para aumentar nuestro entendimiento sobre ptr, &ptr y *ptr crearemos un ejemplo mas complicado, aqui solo recalco los nuevos puntos:
int *ptr = new int;
int a = 123;
ptr = &a; /* aqui estamos haciendo que el puntero apunte a la direccion de memoria de a*/
cout << *ptr; /* nuestro puntero esta apuntando a la direccion de a, asi que con el asterisco veremos " 123 ".*/
Espero ahora si tengan idea de lo que cada valor del puntero dependiendo de que le precede mostrara o donde se anotara...
Algo que no explique en variables estaticas aunque no es mi obligacion ya que el titulo de este articulo es: Punteros en C++, no hay buen metodo que repasar algunas cosas que a lo mejor para algunos sea muy clara, pero para los que no saben pues les sera util. Las variables estaticas poseen tambien &variable, o sea el Ampersand, si lo usamos con el objeto COUT este nos retornara la direccion de memoria donde esta localizada esta variable estatica.
5. Cosas que se preguntaran ahora...
- Por que complicarse la vida con Punteros, si con variables estaticas no hay mucho problema?
Bueno, si la aplicacion es sencilla y solo queremos hacer una demostracion de punteros con un computador que posee 1GB de RAM, creo que no habra problema usando variables estaticas. Pero ordinariamente deberiamos usar la memoria volatil de la menor forma posible, asi que por ejemplo en vez de contener mil punteros con valor INT, y aunque todavia no lo usemos y nos ocupe espacio, podriamos hacerlo de forma dinamica, asi podriamos borrar y liberar memoria para otras aplicaciones u otras operaciones en las cuales necesitaremos memoria adicional dentro de nuestra aplicacion.
Aunque no es un ejemplo muy claro con objetos INT, en el proximo articulo hablare directamente sobre: "Punteros a CHAR" y ahi revelare lo que en verdad es usar espacio en Memoria RAM de forma moderada usando los punteros y no en vano por tablas estaticas...
El Proximo Articulo me dedicare solo ha hablar de: "Punteros a CHAR" ya que es un poco mas complicado cuando de CHAR se trata con punteros.
Intentare crear un plan para la elaboracion de estos articulos, no podre fechas ya que conmigo es dificil ponerse de acuerdo para fechas de salida de algun articulo o cualquier cosa, ya que ser estudiante es un trabajo duro.
Notas:
- A lo mejor olvide poner cosas que para mi podrian ser muy sencillas o muy complicadas y las olvide, que las pase por alto, no se, cualquier duda, opinion, correcion, critica al articulo es siempre bienvenida.
- El articulo fue escrito 100% por mi, antes de escribirlo no lei nada, para poder crear mis propias definiciones y mas faciles, y puse todo lo que he descubierto y entendido, porque a veces es dificil encontrar cosas bien detalladas para algunas cosas especificas que queremos programar.
- Bueno estoy esperando poder crear el PDF de este articulo, crear los ejemplos, muchos de ellos, todo esto zipearlo y subirlo a lo mejor a box.net o algun otro medio para almacenar este y todos los articulos que tengo provisto escribir.
- Se me olvido intentare poner imagenes igual, no creo que sean ilustraciones Picasso, pero creo que si lo hago claro en Paint sera mas que suficiente para los lectores.
NOTA IMPORTANTE: A lo mejor me vieron que cuando trataba de objetos los escribia con letras mayusculas (por ej.: COUT, INT, FLOAT) lo hice solo para hacerles notar que son palabras reservadas de c++, pero en cambio en los ejemplos y para uds. al momento de codear usen letras minusculas, y por si acaso con las variables acuerdense que en c++ entre letas mayusculas y minusculas hay diferencia al declararlas, porque no es lo mismo *puntero que *PunTeRo
E2A
PD: el texto esta a su libre disposicion, usenla como gusten, y para los que quieran ayudar en la creacion de este libro llamemoslo sobre C++ avisenme para hacerlo mas detallado.
Salu2