LABORATORIO DE PROGRAMACIÓN TEMA I II

Anuncio
E.T.S. de Ingeniería Informática (Ing. Informática)
Dpto de Lenguajes y C. de la Computación
II.1. El tipo Puntero
El tipo puntero permite manipular direcciones de memoria. En este curso se utilizará
UNIVERSIDAD DE MALAGA
para trabajar con la memoria dinámica, prescindiendo de cualquier otro uso que permita el
lenguaje.
DPTO. DE LENGUAJES Y C. DE LA COMPUTACION
E.T.S. DE INGENIERIA INFORMATICA
INGENIERIA INFORMATICA
LABORATORIO DE PROGRAMACIÓN
(CURSO 2006-2007)
TEMA II
La memoria dinámica es una zona de memoria que se consume y libera en función de
las necesidades que se presenten durante la ejecución del programa. Puesto que a priori no es
posible saber cuanta memoria dinámica se necesitará, y donde se encuentra localizada, es
necesario disponer de algún mecanismo para ello. El tipo puntero representa direcciones de
memoria, con lo que permite hacer referencia a determinadas zonas de memoria. En concreto,
nosotros lo utilizaremos para hacer referencia a la memoria que se ha ido solicitando
dinámicamente.
Aunque el lenguaje permite definir directamente variables de tipo puntero,
GESTIÓN DINÁMICA DE MEMORIA
II.1. El tipo Puntero.
II.2. Operaciones con punteros.
II.3. Operaciones básicas sobre listas enlazadas
II.4. Arrays de memoria dinámica.
II.5. Punteros como parámetros a subprogramas.
Bibliografía: [SAVI00], [JOYA00]
recomendamos hacer uso de los punteros a través de la definición de un tipo explÍcito. Para
ello se seguirá el siguiente formato:
typedef tipo_vble_dinámica* tipo_puntero;
Por ejemplo
typedef int* Punt_Entero;
Ahora se podrán definir variables que sean puntero a números enteros.
Punt_Entero vble_punt1;
El tipo puntero es realmente útil cuando se usa para hacer referencia a tipos
estructurados. Por ejemplo
typedef struct Persona* PuntPersona;
struct Persona {
string nombre;
string tfno;
int edad;
};
De esta forma, según veremos más adelante, será posible construir estructuras de
datos dinámicas tales como listas enlazadas.
En determinadas situaciones nos interesa utilizar punteros que no apuntan a ninguna
variable dinámica. Para ello usaremos el puntero NULL
Laboratorio de Programación
_______________________________________
Tema II Gestión Dinámica de Memoria
1
E.T.S. de Ingeniería Informática (Ing. Informática)
Dpto de Lenguajes y C. de la Computación
E.T.S. de Ingeniería Informática (Ing. Informática)
Dpto de Lenguajes y C. de la Computación
II.3. Operaciones básicas sobre listas enlazadas
II.2. Operaciones con punteros
El tipo puntero admite las siguientes operaciones:
Petición de memoria. Se solicita memoria para una entidad y se obtiene el puntero a
la memoria obtenida. Para ello, se usa el operador new, seguido del tipo de la entidad a crear.
Ejemplo:
PuntPersona pers = new Persona;
Liberación de memoria. Se devuelve memoria que previamente fue pedida mediante
new y que sabemos que a partir de ahora no volverá a ser útil. Para ello se usa el operador
delete seguido del puntero que apunta a la entidad que deseamos liberar.
El tipo puntero puede ser utilizado para construir listas enlazadas dinámicas. Aunque
la sintaxis del lenguaje C++ admite múltiples variantes para efectuar la definición de una lista
enlazada, recomendamos utilizar el siguiente estilo de declaración:
typedef struct nodo* PuntNodo;
struct nodo {
tipoCampo1 campo_1;
...
...
tipoCampoN campo_n;
Puntnodo sig;
};
Como se puede observar, primero hemos definido un tipo PunteroNodo que cuyos
valores apuntan a registros (struct) de tipo nodo. A continuación se define el tipo registro
Ejemplo:
apuntado, que entre otros, contiene un campo para enlazar con el siguiente nodo de la lista.
delete pers;
Desreferenciación. Acceso a la entidad apuntada por un puntero. Para ello, se utiliza
el operador *, aunque hay algunas abreviaturas para situaciones frecuentes.
Ejemplos.
Para poder trabajar con listas es necesario disponer de la posibilidad de localizar el
último nodo de la lista. Ello se hará detectando un puntero especial NULL, cuyo valor no
apunta a ninguna entidad real de la memoria dinámica.
Las operaciones de manipulación de listas siguen los mismos criterios estudiados en la
asignatura Metodología de la Programación.
*vble_punt1 = 2;
// almacena un 2 en la entidad de tipo entero
// apuntada desde vble_punt1.
int num = *vble_punt1;
// obtiene la entidad apuntada por vble_punt1
// (un 2) y lo almacena en la vble num
II.4. Arrays de memoria dinámica
(*pers).edad++;
// suma 1 al campo edad de la estructura
// apuntada por pers
El tipo puntero puede ser utilizado para definir arrays dinámicos. Éstos son arrays
cuyo tamaño se especifica en tiempo de ejecución, en el momento de efectuar una petición de
(*pers).nombre = “Juan”;
memoria para el mismo.
Debido a que es frecuente el uso de puntero para acceder a entidades de tipo registro,
el acceso a los campos de un registro apuntado se puede especificar además mediante el
operador ->
pers->edad++;
// suma 1 al campo edad de la estructura
// apuntada por pers
pers->nombre = “Juan”;
Asignación. Se puede almacenar el valor de un puntero en una variable de tipo
puntero.
Para definir un array dinamico de tipo base T_Base se utiliza la misma sintaxis que
para definir un puntero a un elemento de tipo T_Base.
typedef struct Persona* ArrayDinamicoPersonas;
Será en el momento de la petición de memoria dinámica cuando se indique que se está
pidiendo memoria para un array dinámico. Para ello, bastará con especificar el número de
elementos del array entre corchetes.
const int TAM = 20;
ArrayDinamicoPersonas Pers = new Persona[TAM];
// TAM puede ser constante o vble
Comparaciones de igualdad y desigualdad. Para comprobar si dos punteros están
apuntando a la misma entidad (son la misma dirección) o no.
Una vez efectuada la petición de memoria para un array dinámico podremos trabajar
con él como con cualquier otro array, usando la sintaxis típica de éstos.
Pers[i].edad++;
Laboratorio de Programación
_______________________________________
Tema II Gestión Dinámica de Memoria
2
Laboratorio de Programación
// suma uno a la edad de la persona “i” del array “Pers”
_______________________________________
Tema II Gestión Dinámica de Memoria
3
E.T.S. de Ingeniería Informática (Ing. Informática)
Dpto de Lenguajes y C. de la Computación
Para liberar la memoria utilizada por un array dinámico se insertan corchetes entre
delete y el nombre del array.
delete [] Pers;
Notas:
E.T.S. de Ingeniería Informática (Ing. Informática)
Dpto de Lenguajes y C. de la Computación
II.5. Punteros como parámetros a subprogramas
El paso de valores de tipo puntero a subprogramas no se diferencia del paso de valores
de cualquier otro tipo como por ejemplo int. Así pues, si el parámetro es de entrada
usaremos paso por valor y si es de salida o de entrada/salida, usaremos paso por referencia.
Al acceder a una posición del arrray dinámico no se comprueba que el valor del índice
se refiera a una posición válida del array.
Al liberar un array dinámico no se comprueba que la nemoria del mismo fuera
solicitada correctamente.
Sin embargo, sabemos que usamos punteros para apuntar a variables dinámicas.
Dichas variablas apuntadas no se ven afectadas por el mecanismo de paso por valor / paso por
referencia. Como consecuencia, aunque pasemos un puntero por valor, la variable dinámica
apuntada por éste no se copia. Si desreferenciamos un puntero en un subprograma,
accedemos a la misma variable dinámica que si desreferenciamos el parámetro
Arrays dinámicos como parámetros a subprogramas.
Se realizará utilizando un array abierto en el parámetro formal correspondiente.
Además, para poder trabajar con el array dentro del subprograma, deberá incluirse un
parámetro que informe del número de elementos del array que está siendo pasado como
parámetro.
Ejemplo:
correspondiente en la llamada, y por tanto, si modificamos la variable dinámica dentro del
subprograma, dicha modificación permanece al finalizar el subprograma, tanto si el
parámetro puntero fue pasado por valor como si fue pasado por referencia.
Las funciones pueden devolver valores de tipo puntero. De nuevo, debemos tener en
cuenta que únicamente se devuelve el puntero, sin que ello afecte a la variable dinámica
apuntada por éste.
typedef int* AD_Enteros;
Ejemplos:
void leer(int n, int numeros[])
{
cout << ”Introduce “ << n << “ elementos” << endl;
for (int i = 0; i < n ; i++) {
cin >> numeros[i];
}
}
float media(int n, const int numeros[])
{
float suma = 0.0;
for (int i = 0; i < n; i++) {
suma += numeros[i];
}
return suma / float(n);
}
/*
* Dada una lista que puede contener elementos repetidos
* elimina los duplicados que aparezcan en la misma.
*/
void purgar_lista(T_Lista& lista)
/*
* Devuelve una lista nueva que contenga aquellos elementos
* de “l” mayores que “num”
*/
T_Lista copiar_lista(T_Lista l, int num)
int main()
{
int n_elem:
AD_Enteros numeros;
cout << “Introduce el número de elementos”;
cin >> n_elem;
numeros = new int[n_elem];
leer(n_elem, numeros);
cout << “Media: ” << media(n_elem, numeros) << endl;
delete [] numeros;
return 0;
}
Laboratorio de Programación
_______________________________________
Tema II Gestión Dinámica de Memoria
4
Laboratorio de Programación
_______________________________________
Tema II Gestión Dinámica de Memoria
5
Descargar