Universidad Técnica Federico Santa María EX UMBRA IN Departamento de Informática Prof. Hubert Hoffmann N. SOLEM MANEJO DINÁMICO DE MEMORIA Se distinguen dos tipos de variables: estáticas y dinámicas. A las variables estáticas se le asigna el espacio que necesitan en la memoria antes de la ejecución de una función o programa. El espacio que ocupa una variable dinámica es asignado y liberado según las necesidades mientras se ejecuta la función o el programa. El espacio en la memoria que ocupa una variable estática es referenciado, es decir a este espacio hay acceso a través de un nombre declarado por el programador y en el caso de una variable dinámica es referenciado por medio de un puntero. Los punteros son un tipo de datos especial que se distingue de los demás tipos de datos ya que permite almacenar referencias a la memoria. Estas referencias o direcciones se denominan en los diferentes lenguajes de programación generalmente punteros (pointer). El tipo de datos puntero permite el manejo dinámico de memoria: A través de una variable se puede reservar el espacio en la memoria que se necesite. Una cantidad de memoria no predefinida se puede manejar en forma simple: se pueden añadir, insertar y eliminar elementos. Una variable p del tipo puntero tiene como valor una referencia (puntero, dirección) a un objeto del llamado tipo referenciado. Este objeto referenciado será creado en el tiempo de ejecución en C++ por el operador new. Este objeto referenciado no es declarado, pero la variable del tipo puntero si lo es: El puntero es una variable estática, mientras el objeto referenciado es un elemento dinámico (Figura 1). p Objeto Referenciado Figura 1: Puntero - Pointer El objeto referenciado no es directamente identificado por el nombre de una variable, sino a través del nombre de una variable del tipo “puntero-a-tipo”. El operador new es un operador unario que permite asignar espacio de memoria para una instancia de un tipo de datos específico en tiempo de ejecución. El operador requiere como argumento el nombre del tipo de datos y retorna un puntero al espacio asignado. Se declara en C++ int *p, n=5, k; En este caso, p es una variable “puntero al tipo int”. Se puede almacenar la dirección de la variable n en p escribiendo p = &n; En este ejemplo, *p denota un objeto del tipo int en la memoria, *p es el mismo espacio que ocupa la variable n en la memoria. Después de ejecutar la asignación p=&n;, el objeto al cual apunta p resulta ser la variable n del tipo int. Después de almacenar la dirección de n en p, es posible tratar *p como otra expresión para n. Si se continúa con k = *p; entonces el valor de k será 5, igual si se hubiese escrito 420304994.doc 1 13-11-15 Universidad Técnica Federico Santa María EX UMBRA IN Departamento de Informática Prof. Hubert Hoffmann N. SOLEM k = n;. El proceso para obtener el valor 5 utilizando p se denomina dereferenciación o indirección y el operador unario * en *p es el operador de dereferenciación o indirección. Hay que distinguir cuidadosamente entre p y *p. La variable p es del tipo “puntero-a-int” y por eso se pueden asignar a ella direcciones, mientras que a *p se puede asignar valores enteros ya que es una expresión del tipo int. *p no se debe utilizar antes de haber asignado un valor a p. En este caso la variable p es indefinida. Con la siguiente función se demuestra este error: int main() { char *p, ch; *p = ‘A’; return 0; // ERROR } Este error se puede corregir agregando p = &ch; antes de la asignación *p = ‘A’; Ahora se asigna ‘A’ a la variable ch, es decir a *p. Un puntero puede apuntar también a ninguna celda de la memoria. En este caso, tiene el valor NULL. Esto significa que un puntero puede apuntar a una celda de la memoria, tener el valor NULL (no apuntar a ninguna celda) o ser indefinido (generalmente un error). Para alocar espacio en la memoria dinámicamente, es decir en el tiempo de ejecución, se utiliza el operador new. En C se utiliza la función malloc (p = (int *) malloc(1)). int *p; p = new int; En este caso se alocó espacio en la memoria para un solo valor del tipo int. Ejemplo: Puntero a una estructura (struct) struct oficina { int numero; int tamaño; int fono; }; oficina o1, o2, *op1, *op2; Acceso a los campos es: o1.numero=56; o2.fono=123456; (*op1).numero=56; (*op1).fono=o2.fono; Se escribe también: op1->fono=o2.fono; Otras estructuras son: struct oficina1 { int numero; 420304994.doc 2 13-11-15 Universidad Técnica Federico Santa María EX UMBRA IN Departamento de Informática Prof. Hubert Hoffmann N. SOLEM int tamano; int fono; persona *profesor; }; struct oficina2 { int numero, tamano, fono; oficina2 *siguiente; }; El espacio reservado en la memoria a través de new se puede liberar a través de delete. Ejemplo: int *p = new int; delete p; Pero no se puede hacer lo siguiente: int a = 5; int *p = &a; delete p; 420304994.doc // p no apunta a algo reservado a través de new 3 13-11-15