Punteros

11. Variables Dinámicas

Memoria dinámica
En los programas vistos en capítulos anteriores, todas las necesidades de memoria se determinaron antes de la ejecución del programa mediante la definición de las variables de tamaño necesario , pero para el caso de los arreglos, suele ser mas difícil.. a priori s saber cuantos elementos necesitamos cargar?

Así que hay casos en los que las necesidades de memoria de un programa solo se puedan determinar durante el tiempo de ejecución.

Por ejemplo, cuando la memoria necesaria depende de la entrada del usuario. En estos casos, los programas necesitan asignar memoria dinámicamente, para lo cual el lenguaje C ++ integra los operadores new y delete que mencionamos anteriormente.

Solemos escribir

#include <iostream>
using namespace std;
#define N 5 //Constante simbolica

int main(int argc, char *argv[]) {
    float vec[N];
    for(int i=0;i<5;i++)cin>>vec[i];
    for(int i=0;i<5;i++)cout<<vec[i]<<"\t""'";
    return 0;
}
En este caso el tamaño del Arreglo que es N se define con una constante al momento de COMPILAR, pero luego NO SE PUEDE CAMBIAR.

Que sucedería que queremos cambiar el tamaño durante la ejecución? Por ejemplo cargar X temperaturas donde X se determina al momento de ejecutar el programa?

Para hacerlo correctamente  se utiliza el operador new que veremos a continuación, algo que se suele hacer y que está MAL es lo siguiente como un intento de definir la cantidad de memoria en tiempo de ejecución, cosa que NO es cierta, solo se asigan un tamaño mágicamente grande y luego se utiliza seguramente algo menor.

Esto está mal!!!! NO HAY QUE HACER!!
#include <iostream>
#define N 10000 using namespace std; int main(int argc, char *argv[]){ float vec[N]; int cantidad; cin>>cantidad;//MAL!! en tiempo de ejecución!!! for(int i=0;i<cantidad;i++)cin>>vec[i]; for(int i=0;i<cantidad;i++)cout<<vec[i]<<"\t"; return 0; }

Esto está PEOR!!! NO HAY QUE HACER!!

#include <iostream>
using namespace std;

int main(int argc, char *argv[]){
    int cantidad;
    cin>>cantidad;
    float vec[cantidad];//PEOR!! MUY MAL!! // en tiempo de ejecución defino el tamaño, que pasa si no hay lugar?
    for(int i=0;i<cantidad;i++)cin>>vec[i];
    for(int i=0;i<cantidad;i++)cout<<vec[i]<<"\t";   
    return 0;
}

Montón o Heap

Cuando se inicia la ejecución de un programa, el sistema operativo carga el código ejecutable en una zona libre de la memoria reservando además varias zonas para almacenar los datos que necesite durante su ejecución.

Estas zonas de memoria son:


  • El área del código.

  • El área de datos estáticos.

  • La pila de llamadas (call stack , LIFO).

  • El área de datos dinámicos (heap o montón).


De manera gráfica lo podemos ver...

Figura 1

Como se puede observar en la Figura 1 esto es una parte del Mapa de Memoria.

Hay una zona de datos para almacenar las variables globales y las constantes ( Estática) , reservando el espacio justo ya que se conoce en tiempo de compilación.

Otra zona para las llamadas que almacenará los parámetros de las funciones, las variables locales y los valores de retorno de las funciones ó para intercambiar datos entre funciones.(Pïla/Stack/Lifo)

Una zona para la gestión dinámica  Heap o Montón  de la memoria que se solicita durante la ejecución. Por ejemplo en C++ con el operador “new”.  C++ dispone de otro operador para acceder a la memoria dinámica que es "delete".

Una vez que el sistema operativo ha reservado las zonas de memoria y ha cargado el código del ejecutable en la Memoria RAM, el programa está listo para ser ejecutado.
El S.O indicará a la CPU que debe apuntar con el registro del puntero de instrucciones a la primera instrucción del código (el punto de entrada de las aplicaciones, la función main), y que debe apuntar con su puntero de pila a la primera dirección de memoria reservada para la pila (stack). Esto último escapa a los alcances de nuestra materia.

Veamos un ejemplo:
#include <iostream>
using namespace std;

int main(int argc, char *argv[]) {
    float *vec;
    int n;
    cout<<" Ingrese la dimensión del arreglo: ";
    cin>>n;//Tamaño del Arreglo
    vec=new float[n];//Durante la ejecución determino el tamaño del arreglo!!
    for(int i=0;i<5;i++)cin>>*(vec+i);
    for(int i=0;i<5;i++)cout<<*(vec+i)<<"\t"<<"almacenado en: "<<vec+i)<<"\t"<<endl;
    delete []vec;
    return 0;
}