Академический Документы
Профессиональный Документы
Культура Документы
Punteros
Introduccin
Memoria de un ordenador Gestin del Heap Definicin Inicializacin y liberacin de memoria Operaciones bsicas El operador @ Listas con arrays Listas con punteros
Procesamiento de listas
Introduccin
Memoria de un ordenador
Estructuras de datos dinmicas: el tamao no se conoce en tiempo de compilacin sino que ir aumentado o disminuyendo dinmicamente durante la ejecucin del programa Una estructura de datos dinmica es una coleccin de elementos llamados nodos (normalmente de tipo registro) que se enlazan o encadenan juntos El enlace se establece asociando con cada nodo un puntero que apunta al nodo siguiente de la estructura Existen varios tipos de estructuras dinmicas (listas enlazadas, grafos, rboles)
Nodo 1
Tema 10. Punteros
La memoria de un ordenador est dividida en casillas o celdas de igual tamao Para acceder a una casilla determinada hay que sealar su direccin, que identifica unvocamente a cada casilla Tanto en la memoria como en el procesador, la informacin es procesada y transmitida mediante unidades denominadas palabras de memoria La longitud de cada palabra de memoria vara de una mquina a otra, aunque hoy en da el tamao ms habitual es de 16, 32 y 64 bits.
Nodo 2
Nodo 3
3 Tema 10. Punteros 4
Zona de cdigo: es la parte de la memoria donde residen las instrucciones de nuestro programa; suele ocupar las direcciones ms bajas de la memoria Zona de datos: se alojan los datos estticos de nuestro programa, es decir, las variables globales del mismo. Suele ser un espacio de memoria limitado, por lo que el nmero y tamao de estas variables tambin est limitado. Forma junto con la Datos dinmicos zona de cdigo la parte esttica de la memoria La pila o stack, que suele encontrarse en las posiciones ms altas de memoria, creciendo dinmicamente hacia las direcciones ms bajas de la misma. En el stack se alojarn las variables locales de los diferentes mdulos conforme estos se van Datos estticos activando El heap, o zona de datos dinmicos, se encuentra entre la zona de datos estticos y la pila. Su tamao vara dependiendo de cmo vare el tamao de la pila, aunque por lo general los compiladores asignan como heap todo el espacio que no es zona de cdigo y de datos estticos. El programador no debe preocuparse de cmo se gestiona esta memoria, sino solo de su utilizacin ya que es el propio compilador el que se carga de ello
Tema 10. Punteros
Pila
Heap
La memoria que ocupa el heap est dividida en bloques de diferentes tamaos Cuando desde el programa se solicita memoria para alojar un objeto de tamao n, el gestor del heap le asigna un bloque libre de tamao n, si lo hay, o de tamao t ( siendo t el valor ms pequeo del tamao de todos los bloques libres con tamao mayor que n). El bloque asignado se marca como ocupado y no puede ser asignado a otro objeto, por lo que se desperdicia un pequeo trozo de memoria Cuando se libera un objeto, el bloque de memoria que ocupaba pasa a ser libre, por lo que podr ser ocupado por otros objetos que lo soliciten
6
Un puntero es un objeto cuyo contenido es la direccin de memoria que ocupa otro objeto de nuestro programa El rango de valores vlidos ser el de las direcciones de memoria capaces de ser accedidas por el procesador del ordenador, ms una direccin de memoria especial, que se corresponde con el puntero nulo El puntero nulo recibe nombres diferentes dependiendo del lenguaje (Pascal NIL, C NULL) Declaracin de una variable tipo puntero Id_puntero:^tipo El ejemplo siguiente se lee como p apunta a la direccin de memoria donde se encuentra almacenado un entero p:^entero
7
Son dos operaciones importantes Para indicar al compilador que debe reservar espacio en el heap hay que inicializar el puntero con NEW(id_puntero) Al realizar la inicializacin, se asigna un bloque del heap en tiempo de ejecucin y se marca como ocupado El bloque permanece ocupado hasta que el programa libera explcitamente esa zona de memoria mediante la operacin DISPOSE(Id_puntero) Cuando un objeto apuntado no vaya a volver a utilizarse, ste debe liberarse. De esta manera, la memoria libre del heap aumenta, por lo que podr ocuparse por otros objetos. De otra forma, puede ocurrir que el heap se llene de bloques ocupados que no estn apuntados por ningn puntero, lo que supone un gravsimo desperdicio de memoria
8
Ejemplo
Var p:^integer;
Heap ? Datos Globales
Operaciones bsicas
New(p);
30 ? Heap Datos Globales
Se utiliza el operador ^ (operador de indireccin o de desreferencia) Para acceder al contenido se usa Id_puntero^ Una vez que se accede al contenido se puede tratar con todas las operaciones vlidas para el tipo de datos apuntado por el puntero
New(p);
? Heap Datos Globales
P^:=50;
30 50 Heap Datos Globales
P^:=30;
30
Dispose(p);
30
p
Tema 10. Punteros
Asignacin de punteros (no est permitido asignar punteros que apunten a tipos de datos distintos) p:=q; Asignacin del contenido de los punteros p^:=q^; p^:=2300; Comparacin IF (p<>q) THEN IF (p=q) THEN Lectura y escritura: lgicamente, no se podrn realizar las operaciones de lectura y escritura de los punteros como tales. S que se podr leer o escribir el contenido de los objetos apuntados, siempre siguiendo las reglas de cada tipo concreto READLN(p^); WRITELN(q^); La constante NIL permite dar un valor a una variable puntero que no apunta a ninguna direccin. Puesto que NIL no apunta a ninguna posicin de memoria, cualquier referencia al contenido de la posicin que apunta un puntero NIL es ilegal p:=NIL; p^:=10; ERROR!
10
Ejemplos
VAR q,p:^integer; BEGIN New(p); p^:=30; p^:=p^*10+50; New(q); q^:=p^; p^:=p^+q^; q:=p;
Tema 10. Punteros
Ejemplos
?
Var
q q q p p p^ p p^ q^ q^ q^ p p^ p p^ p p^ p^
Errores comunes
q q q
DISPOSE(p); p^:=2300;
{asignar a p la direccin 2300} {se reserva un nuevo bloque para p sin haber liberado el bloque antiguo} {intenta acceder al contenido del bloque que ya ha sido liberado}
p^
q^
11
TYPE Empleado= RECORD Codigo:Integer; Nombre:string[30]; Edad:Integer; sueldo:real; END; VAR p p:^Empleado; BEGIN NEW(p); p^.codigo:=1001; P^.nombre:=Ana Garca; P^.edad:=35; P^.sueldo:=1754; DISPOSE(p); END;
12
Algunas consideraciones
El puntero nulo
Se dice que tiene el valor NIL (o NULL) Antes de utilizar un puntero, debemos asegurarnos de que su valor no es NIL El gestor de memoria devuelve NIL cuando no ha sido posible la asignacin de memoria requerida por la llamada NEW A la hora de pasar como parmetro un puntero, debe realizarse por referencia, siempre y cuando lo que se haga dentro del mdulo llamado afecte no al objeto apuntado por el puntero, sino al propio puntero En cambio, si lo que realizamos en el interior del mdulo llamado afecta no ya al puntero sino al objeto apuntado por el mismo, entonces es indiferente el modo de pasar el parmetro ya que ambos punteros - el puntero existente en memoria principal y el creado en la pila - apuntan al mismo espacio de memoria
Paso de parmetros
{-- programa principal ------} BEGIN referencia(p); writeln(p^); Dispose(p); valor(p); writeln(p^); END.
13
14
El operador @
Procesamiento de listas
El operador @ se puede aplicar a una variable (no puntero) y devuelve la direccin de memoria dnde est alojada dicha variable p := @v En este caso, no se est trabajando con memoria dinmica, sino con memoria esttica, y el puntero no va a apuntar a direcciones del heap sino a direcciones del rango de la zona de datos estticos Ejemplo
Var Begin v:=10; p:=@v; p^:=p^+1; writeln(v,p^); End. p:^integer; v:integer;
Mostrar los elementos de la lista Insertar un elemento Borrar un elemento Buscar un elemento Pilas o listas LIFO (Last In First Out)
Las inserciones siempre se realizan por el final Las eliminaciones siempre se realizan por el final La inserciones siempre se realizan por el final Las eliminaciones siempre se realizan por el principio
16
15
Insertar un elemento
PROCEDIMIENTO insetar( VAR lista:LISTAENTEROS; VAR NumElem:ENTERO; elem:ENTERO; pos:ENTERO ) {lista de enteros} {N de elementos de la lista} {elemento a insertar} {posicin en la que se inserta}
Se utiliza un array unidimensional para almacenar la lista, de manera que el i-simo elemento de la lista se corresponde con el i-simo elemento del array
TIPO listaenteros=ARRAY[1..Limite] de ENTEROS VARIABLES lista:listaenteros
Operaciones inmediatas
Leer y escribir los elementos de la lista Buscar un elemento de la lista Los arrays deben tener una longitud fija (son estructuras estticas) Operacin de insercin y eliminacin (algoritmos sencillos pero ineficientes)
17
Limitaciones
VARIABLES i:ENTERO INICIO PARA i=0 HASTA NumElem-pos HACER lista[NumElem+1-i] lista[NumElem-i] {Desplazar todos los elementos a partir de} FIN_PARA {la posicin en la que se va a insertar} Lista[pos] elem {Insertar el elemento en la posicin pos} NumElem NumElem+1 {Incrementar el n total de elementos} FIN_PROC Lista es (34,52,12,6,10) y NumElem es 6 Llamada al procedimiento INSERTAR(lista,NumElem,38,3) 34,52,12 ,6 ,10 34,52,38,12,6,10
18
Listas enlazadas
Lista enlazada
BOA GATO PERRO LEON
Direccin 150 151 152 153 154 155 BOA PERRO 157 NIL LEON 153
El tamao de una lista no se puede predecir a priori Las operaciones de insercin y borrado son frecuentes
Las listas enlazadas son una secuencia de nodos que se enlazan mediante un enlace o puntero Cada nodo o elemento de la lista debe tener dos campos:
Un campo con los valores de cada elemento (datos) Un campo que indica la posicin del elemento siguiente (enlace o puntero, representado por una flecha)
8 Lista 5 8 1 9 8 1 9 3 8 Lista de enteros con arrays
Implementacin de listas
TipoElemento puede ser cualquier tipo de datos vlido La declaracin de PunteroNodo precede a TipoNodo: sta es la nica situacin en la que se permite utilizar un identificador antes de ser definido Cuando se implementa una lista enlazada se necesita un puntero adicional (puntero cabecera) que se utiliza para apuntar al primer elemento de la lista El puntero cabecera es distinto a los elementos de la lista puesto que no contiene ningn elemento sino solo un dato de tipo puntero, sirve simplemente para obtener el principio de la lista por lo que se trata de un putero externo que est fuera de la lista y que debe existir siempre La declaracin sera de la siguiente manera VAR cabecera: PunteroNodo; Si el valor de cabecera es NIL significa que la lista est vaca
21
VAR
L:Lista; P:PunteroNodo; X:TipoElemento;
Tema 10. Punteros
22
24
********* segmento de cdigo en la siguiente diapositiva *********** END; END; (--- fin de cuando hay al menos un elemento ----} END;
27 Tema 10. Punteros 28
IF (p^.siguiente<>NIL) THEN BEGIN {- si hay 2 elementos o mas } encontrado:=FALSE; WHILE (p^.siguiente^.siguiente<>NIL) AND NOT encontrado DO BEGIN {mientras no se llegue al penltimo} IF (p^.siguiente^.elemento<q^.elemento) THEN { y no se haya encontrado dnde insertar} p:=p^.siguiente ELSE BEGIN q^.siguiente:=p^.siguiente; p^.siguiente:=q; encontrado:=TRUE; END; END; {---- Fin del while no llegue al penltimo y no hay encontrado dnde insertar----} IF NOT encontrado THEN BEGIN {-- insertar como ltimo o penltimo ---} IF (q^.elemento<p^.siguiente^.elemento) THEN BEGIN {insertar como penltimo } q^.siguiente:=p^.siguiente; p^.siguiente:=q; END ELSE BEGIN {insertar como ltimo} q^.siguiente:=NIL; p^.siguiente^.siguiente:=q; END; END; END {----- fin del SI hay 2 o mas elementos ----} ELSE BEGIN {- hay solo un elemento. se inserta el 2 como ltimo elemento --} p^.siguiente:=q; q^.siguiente:=NIL; END;
Tema 10. Punteros 29
Definir el tipo de dato Definir todas las operaciones (primitivas) que se van a utilizar sobre ese tipo de dato
VAR
L:Lista {---- Cabecera de la lista -----} P:PunteroNodo; {----- Nodo individual ---------}
30
Crear lista vaca Comprobar si la lista est vaca Localizar la posicin Recuperar elemento de una posicin Insertar elemento Borrar elemento
31
32
Localizar un elemento
FUNCTION localizar ( x : TipoElemento ; l : lista ) : PunteroNodo ; { Devuelve la posicin en que se encuentra el elemento x en la lista l } VAR p : PunteroNodo; encontrado : boolean; BEGIN { De la funcin localiza } p := l; encontrado := FALSE; WHILE ( (p <> NIL ) AND ( NOT encontrado )) DO IF ( p^.elemento = x ) THEN encontrado := TRUE ELSE p := p^.siguiente; localiza := p; END; { De la funcin localiza }
Recuperar un elemento
PROCEDURE recuperar ( VAR x: TipoElemento; p: PunteroNodo; l: lista ); { Recupera en x el elemento que ocupa la posicin p de la lista l } BEGIN { Del procedimiento recupera } IF (p<>NIL) THEN { No estamos al final de la lista } x:= p^.elemento ELSE WRITELN ( posicion errnea ); END; { Del procedimiento recupera }
33
34
Insertar un elemento
PROCEDURE insertar ( x: TipoElemento ; p :PunteroNodo; VAR l : lista ); { Inserta el elemento x en la posicion p de la lista l , si p es una posicin vlida } VAR q,aux : PunteroNodo; BEGIN { Del procedimiento insertar } IF (l=NIL) THEN BEGIN {Lista est vaca, se insertar el primer elemento} NEW(l); l^.elemento:=x; l^.siguiente:=NIL; END ELSE BEGIN NEW(aux); aux^.elemento:=x; IF (l=p) THEN BEGIN {se inserta como el primero de la lista} l:=aux; l^.siguiente:=p; END ELSE BEGIN {se inserta en cualquier otra posicin} q:=l; {q apuntar al anterior de p} WHILE (q^.siguiente<>p) DO q:=q^.siguiente; q^.siguiente := aux; aux^.siguiente:=p; END; END; END; { Del procedimiento insertar }
Tema 10. Punteros 35
Borrar un elemento
PROCEDURE borrar ( p : PunteroNodo ; VAR l: lista ); { Borra el elemento que ocupa la posicin p de la lista l, si p es una posicin vlida} VAR q : PunteroNodo; BEGIN { Del procedimiento borrar } IF (l=NIL) THEN {lista vaca} WRITELN (Error. No se puede borrar. Lista vaca) ELSE IF (l=p) THEN BEGIN {borrar el primero de la lista} l:=l^.siguiente; DISPOSE(p); END ELSE BEGIN {borra cualquier otro elemento} q:=l; WHILE (q^.siguiente<>p) AND (q^.siguiente<>NIL) DO q := q^.siguiente; IF (q^.siguiente<>NIL) THEN BEGIN q^.siguiente:=q^.siguiente^.siguiente; DISPOSE ( p ); END ELSE WRITLEN(Error. No se encuentra la posicin); END; END; END; { Del procedimiento borrar }
Tema 10. Punteros 36
Primitivas adicionales
37
38
39
40
Hasta ahora todos los nodos contenan informacin relevante Las operaciones de insercin y borrado deben considerar la posicin en la que se va a realizar la operacin Se puede utilizar otra implementacin en la que dichas operaciones fueran independientes de la posicin en las que se quiere realizar Para ello, se usar la Implementacin con Nodo Cabecera El primer nodo de la lista se llama cabecera y no contiene ningn elemento Siempre se deja el primer elemento vaco El primer nodo lgico (con informacin til) de la lista ser en realidad el segundo nodo fsico
L 5 8 1 8
8
42
43
44
Insertar un elemento
PROCEDURE insertar(x: tipoElemento ; p :PunteroNodo; VAR l : lista ); { Inserta el elemento x en la posicion p de la lista l } VAR q : PunteroNodo; BEGIN { Del procedimiento insertar } q := p^.siguiente; NEW ( p^.siguiente ); p^.siguiente^.elemento := x; p^.siguiente^.siguiente := q; END; { Del procedimiento insertar }
45
46
Borrar un elemento
PROCEDURE borrar ( p : PunteroNodo ; VAR l: lista ); { Borra el elemento que ocupa la posicin p de la lista l } VAR q : PunteroNodo; BEGIN { Del procedimiento borrar } IF (p^.siguiente<>NIL) THEN {posicin correcta de la lista} BEGIN q := p^.siguiente; p^.siguiente := q^.siguiente; DISPOSE ( q ); END; END; { Del procedimiento borrar }
Posicin anterior
FUNCTION anterior ( p: PunteroNodo; l : lista ) : PunteroNodo; { Devuelve la posicion anterior a la posicion p en la lista l } VAR aux: PunteroNodo; encontrado: boolean; BEGIN IF ( p = l ) THEN { Estamos al principio de la lista } error ( No hay posicion anterior ) ELSE BEGIN aux := l; encontrado := FALSE; WHILE ( aux^.siguiente <> NIL ) AND ( NOT encontrado ) DO IF ( aux^.siguiente = p ) THEN encontrado := TRUE; ELSE aux := aux ^.siguiente; IF encontrado THEN anterior := aux; ELSE anterior:=NIL; END; { De la funcin anterior }
47 Tema 10. Punteros 48
Posicin siguiente
FUNCTION siguiente ( p : PunteroNodo ; l : lista ) : PunteroNodo; { Devuelve la posicion siguiente a p en la lista l } VAR q : PunteroNodo; encontrado : boolean; BEGIN { De la funcin siguiente } q := l; encontrado := FALSE; WHILE ( q <> NIL ) AND ( NOT encontrado ) IF ( q = p ) THEN encontrado := TRUE ELSE q := q^.siguiente; IF encontrado THEN siguiente := q^.siguiente ELSE error ( posicion incorrecta ); END; { De la funcin siguiente }
49