Publicado el 3 de Mayo del 2019
679 visualizaciones desde el 3 de Mayo del 2019
773,0 KB
40 paginas
Creado hace 8a (19/01/2016)
TEMA 0
Gestión de
Memoria Dinámica
ESTRUCTURAS DE DATOS
1
Objetivos
Tema preliminar para entender el uso de la herramienta
básica en la gestión de memoria dinámica: punteros
Objetivos:
◦ Conocer el concepto de “puntero”
◦ Entender la gestión dinámica de memoria
◦ Manejar estructuras estáticas y dinámicas en memoria a través de
punteros
◦ Crear y destruir estructuras dinámicas en memoria
2
Definición del problema
Las estructuras estáticas (por ejemplo, array) no pueden
cambiar su tamaño durante la ejecución del programa
Cambiar la disposición de los elementos dentro de la
estructura estática es, a veces, costoso.
Ejemplos:
◦ No se puede redimensionar un array.
◦ Colocar el último elemento al comienzo del array.
Además, hay otros factores importantes a tener en cuenta
sobre el uso de la memoria en los procesos.
3
Definición del problema
El espacio de memoria en un sistema está descompuesto
de forma general en 4 bloques con tamaños diversos
◦ Segmento de código: asignación automática
◦ Variables globales: asignación automática
◦ Stack o pila de memoria: asignación automática
◦ Heap o montículo de memoria: asignación manual
Stack
Heap
Global
Código
Imagen extraída de: www.sw-at.com
4
Definición del problema
◦ La memoria local a los subprogramas se gestiona en la pila de
memoria
◦ Cada proceso de un programa tiene su propia pila de memoria, por
lo que en general la pila tiene un tamaño muy limitado
◦ La memoria dinámica se gestiona en un bloque muy grande de
memoria (heap/montículo)
global
PROGRAM Memoria;
VAR
precio: real;
FUNCTION CalculoIVA(p: real): real;
BEGIN
CalculoIVA := p*0.21;
END;
BEGIN
precio := 200.25;
writeln(‘El IVA es: ’, CalculoIVA(precio));
END;
local
Stack
Heap
Global
Código
5
Imagen extraída de: www.sw-at.com
Definición del problema
Para algunos problemas de programación no se conoce en
tiempo de diseño cuánta memoria necesitaremos ni cómo
se va a organizar
Solución: definir y organizar esa memoria en tiempo de
ejecución
◦ Para ello, se utilizan estructuras de memoria dinámica
La gestión de memoria dinámica se realiza a través de
variables capaces de guardar direcciones de memoria:
punteros
6
¿Qué es eso de...?
Memoria dinámica: memoria en la que se puede reservar
espacio en tiempo de ejecución
◦ El heap es el bloque del espacio direccionable de memoria dedicado
para la memoria dinámica
Estructuras de datos dinámicas: colección de elementos
(denominados nodos) que se crean o destruyen en tiempo
de ejecución.
Variables Dinámicas: Posiciones de memoria reservadas en
tiempo de ejecución
7
Punteros
Una variable puntero se puede declarar como tipo anónimo, o como
tipo definido por el usuario
VAR
pointer: ^integer;
TYPE
TPointer = ^integer;
VAR
pointer: TPointer;
Variable puntero de tipo
anónimo identificada por
pointer
Tipo TPointer definido
por el usuario para crear
variables puntero a entero
Variable declarada del
tipo anterior
8
Punteros
Un tipo puntero se puede usar para declarar variables de ese tipo
◦ Igual que un tipo Entero se usa para declarar variables de tipo entero (que
guarda valores de ese tipo)
TYPE
TPrecio = integer;
VAR
precioPan: TPrecio;
BEGIN
precioPan := 85;
writeln(precioPan);
END.
TYPE
TPunteroEntero = ^integer;
VAR
pEntero: TPunteroEntero;
◦ Una variable puntero almacena una dirección de memoria donde guardar un
valor del “tipo base” del puntero (releer hasta estar bien seguro de
entenderlo)
9
Punteros
Simulación en memoria
TYPE
TPrecio = integer;
TPunteroEntero = ^integer;
VAR
precioPan: TPrecio;
pEntero: TPunteroEntero;
BEGIN
precioPan := 85;
writeln(precioPan);
END.
precioPan
85
Dirección $3$12
identificada
como
precioPan
Valor (85) que
guarda
precioPan
pEntero
???
10
Operaciones con punteros
Operador @ (Referencia)
◦ Obtención de la dirección de memoria de una variable
VAR
pEntero: ^integer;
precioPan: integer;
BEGIN
precioPan := 85;
pEntero := @precioPan;
...
Operador ^ (Desreferencia)
◦ Acceso al valor de la variable apuntada desde el puntero
...
pEntero^ := 100;
writeln(precioPan); {imprime 100}
pEntero^ y
precioPan son
sinónimos
11
Punteros
Simulación en memoria
TYPE
TPrecio = integer;
TPunteroEntero = ^integer;
VAR
precioPan: TPrecio;
pEntero: TPunteroEntero;
BEGIN
precioPan := 85;
pEntero := @precioPan;
writeln(precioPan);
END.
precioPan
85
Dirección $3$12
identificada
como
precioPan
Valor (85) que
guarda
precioPan
pEntero
$3$12
Si pEntero contiene el valor $3$12, y esa es la dirección de memoria de
la variable precioPan, se dice que pEntero apunta a precioPan
12
Punteros
Simulación en memoria
TYPE
TPrecio = integer;
TPunteroEntero = ^integer;
VAR
precioPan: TPrecio;
pEntero: TPunteroEntero;
BEGIN
precioPan := 85;
pEntero := @precioPan;
pEntero^ := 100;
writeln(precioPan);
END.
precioPan
85
100
Dirección $3$12
identificada
como
precioPan
Valor (85) que
guarda
precioPan
Desde pEntero se
altera el valor de
precioPan (100)
pEntero
$3$12
Si pEntero contiene el valor $3$12, y esa es la dirección de memoria de
la variable precioPan, se dice que pEntero apunta a precioPan
13
Operador @: Ejemplo (1/3)
TYPE
tIniciales = string[3];
tRegistro = RECORD
iniciales: tIniciales;
identificacion: Integer;
END;
tPtrRegistro= ^tRegistro;
VAR
pRegistro: tPtrRegistro;
registro: tRegistro;
BEGIN
...
Reservamos en tiempo de
compilación un bloque de memoria
para un registro y otro para un
puntero (ESTÁTICOS!!)
registro
registro.iniciales:=‘ASM’;
registro.identificacion:=23455;
pRegistro
...
pRegistro := @ registro;
...
END.
14
Operador @: Ejemplo (2/3)
TYPE
tIniciales = string[3];
tRegistro = RECORD
iniciales: tIniciales;
identificacion: Integer;
END;
tPtrRegistro= ^tRegistro;
VAR
pRegistro: tPtrRegistro;
registro: tRegistro;
BEGIN
...
registro.iniciales:=‘ASM’;
registro.identificacion:=23455;
pRegistro
...
pRegistro := @ registro;
...
END.
Inicializamos el registro de la manera
habitual
registro
Char[3]
'A'
'S'
'M'
23455
15
Operador @: Ejemplo (y 3/3)
TYPE
tIniciales = string[3];
tRegistro = RECORD
iniciales: tIniciales;
identificacion: Integer;
END;
tPtrRegistro= ^tRegistro;
VAR
pRegistro: tPtrRegistro;
registro: tRegistro;
BEGIN
...
registro.iniciales:=‘ASM’;
registro.identificacion:=23455;
pRegistro
...
pRegistro := @registro;
...
END.
Apuntamos con el puntero el bloque
de memoria del registro. Tenemos
accesible la información del registro
a través del puntero.
registro
Char[3]
'A'
'S'
'M'
23455
16
Operador ^: Ejemplo (1/3)
TYPE
tIniciales = string[3];
tRegistro = RECORD
iniciales: tIniciales;
identificacion: Integer;
END;
tPtrRegistro= ^tRegistro;
VAR
pRegistro: tPtrRegistro;
reg: tRegistro;
BEGIN
...
pRegistro:=@reg;
…
pRegistro^.iniciales:=‘JJP’;
pRegistro^.identificacion:=23456;
...
END.
Reservamos en tiempo de
compilación un bloque de memoria
para un registro y otro para un
puntero (ESTÁTICOS!!)
reg
pRegistro
17
Operador ^: Ejemplo (2/3)
TYPE
tIniciales = string[3];
tRegistro = RECORD
iniciales: tIniciales;
identificacion: Integer;
END;
tPtrRegistro= ^tRegistro;
VAR
pRegistro: tPtrRegistro;
reg: tRegistro;
BEGIN
...
pRegistro:=@reg;
…
pRegistro^.iniciales:=‘JJP’;
pRegistro^.identificacion:=23456;
...
END.
Apuntamos con el puntero el bloque
de memoria del registro.
pRegistro
reg
18
Operador ^: Ejemplo (y 3/3)
TYPE
tIniciales = string[3];
tRegistro = RECORD
iniciales: tIniciales;
identificacion: Integer;
END;
tPtrRegistro= ^tRegistro;
VAR
pRegistro: tPtrRegistro;
reg: tRegistro;
BEGIN
...
pRegistro:=@reg;
…
pRegistro^.iniciales:=‘JJP’;
pRegistro^.identificacion:=23456;
...
END.
Accedemos al campo “iniciales” e
“identificacion”del dato de tipo
tRegistro y asignamos valores
(NO asignamos valores al puntero,
sino al dato al que apunta)
reg
pRegistro
Char[3]
'J'
'J'
'P'
23456
19
Operaciones con Punteros
Operaciones permitidas:
◦ Asignación (:=)
◦ Comparación (= y <>)
Para realizar estas operaciones los operandos han de ser
punteros a variables del mismo tipo o NIL.
Los punteros no se pueden leer ni escribir directamente.
20
Operaciones: ejemplos (1)
TYPE
ptrACaracter = ^char;
VAR
p1,p2: ptrACaracter;
c1,c2: char;
BEGIN
c1:='a';
c2:='h';
p1:=@c1;
p2:=@c2;
...
END.
En esta situación:
p1 = p2 --> FALSE
p1 <> p2 --> TRUE
p1^ = p2^ --> FALSE
p1
p2
c1
'a'
c2
'h'
21
Operaciones: ejemplos (2)
TYPE
ptrACaracter = ^char;
VAR
p1,p2: ptrACaracter;
c1,c2: char;
BEGIN
c1:='a';
c2:='h';
p1:=@c1;
p2:=@c2;
p1:=p2;
...
END.
Asignación de punteros.
En esta situación:
p1 = p2 --> TRUE
p1 <> p2 --> FALSE
p1^ = p2^ --> TRUE
p1
p2
c1
'a'
c2
'h'
22
Operaciones: ejemplos (3)
TYPE
ptrACaracter = ^char;
VAR
p1,p2: ptrACaracter;
c1,c2: char;
BEGIN
c1:='a';
c2:='h';
p1:=@c1;
p2:=@c2;
p1^:=p2^;
...
END.
Asignación de valores
En esta situación:
p1 = p2 --> FALSE
p1 <> p2 --> TRUE
p1^ = p
Comentarios de: TEMA 0: Gestión de Memoria Dinámica (0)
No hay comentarios