Objetos dinámicos
El uso principal y más potente de los punteros es el manejo de la memoria dinámica.
La memoria se clasifica en muchas categorías, por ahora nos centraremos en algunas de ellas. Cuando se ejecuta un programa, el sistema operativo reserva una zona de memoria para el código o instrucciones del programa y otra para los objetos que se usan durante la ejecución. A menudo estas zonas son la misma, y componen lo que se denomina memoria local. También hay otras zonas de memoria, como la pila, que se usa, entre otras cosas, para intercambiar datos entre las funciones. El resto, la memoria que no se usa por ningún programa es lo que se conoce como heap o montón.
Nuestro programa puede hacer uso de esa memoria durante la ejecución, de modo que la cantidad de espacio de memoria usado por el programa no está limitada por el diseño ni por las declaraciones de objetos realizadas en el código fuente. Por eso se denomina a este tipo, memoria dinámica, ya que tanto la cantidad de memoria como su uso se deciden durante la ejecución, y en general, cambia a lo largo del tiempo, de forma dinámica. Para ello, normalmente se usará memoria del montón, y no se llama así porque sea de peor calidad, sino porque suele haber un buen montón de memoria de este tipo.
C++ dispone de dos operadores para manejar (reservar y liberar) la memoria dinámica, son new y delete. En C estas acciones se realizan mediante funciones de la biblioteca estándar stdio.
Hay una regla de oro cuando se usa memoria dinámica: toda la memoria que se reserve durante el programa hay que liberarla antes de salir del programa. No seguir esta regla es una actitud muy irresponsable, y en la mayor parte de los casos tiene consecuencias desastrosas. No os fiéis de lo que diga el compilador, de que estas variables se liberan solas al terminar el programa, no siempre es verdad.
Veremos con mayor profundidad los operadores new y delete en el siguiente capítulo, por ahora veremos un ejemplo:
#include <iostream>
using namespace std;
int main() {
int *a;
char *b;
float *c;
struct stPunto {
float x,y;
} *d;
a = new int;
b = new char;
c = new float;
d = new stPunto;
*a = 10;
*b = 'a';
*c = 10.32;
d->x = 12; d->y = 15;
cout << "a = " << *a << endl;
cout << "b = " << *b << endl;
cout << "c = " << *c << endl;
cout << "d = (" << d->x << ", "
<< d->y << ")" << endl;
delete a;
delete b;
delete c;
delete d;
return 0;
} |
Y mucho cuidado: si pierdes un puntero a una variable reservada dinámicamente, no podrás liberarla.
Ejemplo:
int main()
{
int *a;
a = new int; // variable dinámica
*a = 10;
a = new int; // nueva variable dinámica,
// se pierde el puntero a la anterior
*a = 20;
delete a; // sólo liberamos la última reservada
return 0;
} |
En este ejemplo vemos cómo es imposible liberar la primera reserva de memoria dinámica. Lo correcto, si no la necesitábamos habría sido liberarla antes de reservar un nuevo bloque usando el mismo puntero, y si la necesitamos, habría que guardar su dirección, por ejemplo usando otro puntero.
Problemas
1-Escribir un programa con una función que calcule la longitud de una cadena de caracteres. El nombre de la función será LongitudCadena, debe devolver un int, y como parámetro de entrada debe tener un puntero a char.
En esta función no se pueden usar enteros para recorrer el array, usar sólo punteros y aplicar aritmética de punteros.
En main probar con distintos tipos de cadenas: arrays y punteros.
2-Escribir un programa con una función que busque un carácter determinado en una cadena. El nombre de la función será BuscaCaracter, debe devolver un int con la posición en que fue encontrado el carácter, si no se encontró volverá con -1. Los parámetros de entrada serán una cadena y un carácter. En la función main probar con distintas cadenas y caracteres.
3-Implementar en una función el siguiente algoritmo para ordenar un array de enteros.
La idea es recorrer simultáneamente el array desde el principio y desde el final, comparando los elementos. Si los valores comparados no están en el orden adecuado, se intercambian y se vuelve a empezar el bucle. Si están bien ordenados, se compara el siguiente par.
El proceso termina cuando los punteros se cruzan, ya que eso indica que hemos comparado la primera mitad con la segunda y todos los elementos estaban en el orden correcto.
Usar una función con tres parámetros:
void Ordenar(int* vector, int nElementos, bool ascendente);
De nuevo, no se deben usar enteros, sólo punteros y aritmética de punteros.
Ir al Principio
Comentarios