Está en la página 1de 34

ETSI Telecomunicacin Memoria Dinmica

Elementos de Programacin Pgina 1




Tema
2. Memoria Dinmica

Contenido
Gestin de Memoria Dinmica
Introduccin. Datos estticos y dinmicos
Asignacin dinmica de memoria
Tipo Puntero
Declaracin de variables de tipo puntero
Operaciones con punteros
Gestin dinmica de memoria
Punteros a registros
Operaciones sobre Listas Enlazadas
Otras clases de listas enlazadas
Ejemplo de Gestin de Memoria Dinmica en C/C++
Ejercicios Propuestos
Bibliografa
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 2

2.1. Gestin Dinmica de Memoria
En este apartado se analizarn las causas que llevan a los lenguajes de programacin a
ofrecer elementos y caractersticas necesarias para permitir la gestin de memoria de manera
dinmica. Se vern cules son las ventajas e inconvenientes de esta tcnica, as como las
diferencias entre tipos de datos estticos y dinmicos en cuanto a su almacenamiento en
memoria principal y su tratamiento por parte de los programas (algoritmos) que los manejan.
As mismo, se establecern las bases tericas necesarias para la comprensin del
funcionamiento del mecanismo de gestin dinmica de memoria.
2.1.1. Introduccin
Los tipos de datos, tanto simples como estructurados, vistos hasta ahora en los temas
anteriores de las asignaturas de Introduccin a los Computadores (IC) y Elementos de
Programacin (EP), sirven para describir datos o estructuras de datos cuyos tamaos y formas
se conocen de antemano. Sin embargo, en muchos programas es necesario que las
estructuras de datos estn diseadas de manera que su tamao y forma vare a lo largo de la
ejecucin de aquellos. Con esto se consigue, fundamentalmente, que estos programas
funcionen de manera ms eficiente y con un aprovechamiento ptimo de los recursos de
almacenamiento en memoria principal.
Las variables de todos los tipos de datos vistos hasta el momento son denominadas
variables estticas, en el sentido en que se declaran en el programa, se designan por medio
del identificador declarado, y se reserva para ellas un espacio en memoria en tiempo de
compilacin de los programas. El contenido de la variable esttica puede cambiar durante la
ejecucin del programa o subprograma donde est declarada, pero no as el tamao en
memoria reservado para ella. Esto significa que la dimensin de las estructuras de datos a las
que se refieren estas variables debe estar determinada en tiempo de compilacin, lo que puede
suponer una gestin ineficiente de la memoria, en el sentido de que puede implicar el
desperdicio (por sobredimensionamiento) o la insuficiencia (por infradimensionamiento) de
memoria.
Sin embargo, son muchos los lenguajes de programacin que ofrecen la posibilidad de
crear y destruir variables en tiempo de ejecucin, de manera dinmica, a medida que van
siendo necesitadas durante la ejecucin del programa. Puesto que estas variables no son
declaradas explcitamente en el programa y no tienen identificador (nombre) asignado, se
denominan variables annimas. El pseudolenguaje utilizado en las asignaturas de IC y EP
permite el uso de este tipo de variables. Para ello, ofrece los mecanismos y la sintaxis
necesaria para su creacin, a la vez que proporcionar una manera de referirse a estas
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 3

variables para el acceso a los datos que contienen y la asignacin de valores a los mismos.
Todo esto se lleva a cabo mediante el empleo del tipo puntero, cuyas caractersticas se
expondrn en los siguientes apartados.
Datos estticos: su tamao y forma es constante durante la ejecucin de un programa y, por
tanto, se determinan en tiempo de compilacin. El ejemplo tpico son los arrays. Tienen el
problema de que hay que dimensionar la estructura de antemano, lo que puede conllevar
desperdicio o falta de memoria.
Datos dinmicos: su tamao y forma es variable (o puede serlo) a lo largo de un programa,
por lo que se crean y destruyen en tiempo de ejecucin. Esto permite dimensionar la estructura
de datos de una forma precisa: se va asignando memoria en tiempo de ejecucin segn se va
necesitando.
2.1.2. Asignacin dinmica de memoria
Cuando se habla de asignacin dinmica de memoria se hace referencia al hecho de crear
variables annimas es decir, reservar espacio en memoria para estas variables en tiempo de
ejecucin del programa as como liberar el espacio reservado para dichas variables annimas,
cuando ya no son necesarias, tambin durante el tiempo de ejecucin.

Instrucciones de
programa
Datos estticos
Pila
Lmite de datos
estticos
Lmite de la pila
Puntero de la pila
(stack pointer)
Zona dinmica
fragmentada
(heap)

Figura 2.1. Esquema de asignacin de memoria
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 4

La zona de la memoria principal del computador donde se reservan espacios para
asignarlos a variables dinmicas se denomina heap o montn. Cuando el sistema operativo
carga un programa para ejecutarlo y lo convierte en proceso, le asigna cuatro partes lgicas en
memoria principal: instrucciones, datos (estticos), pila y una zona libre. Esta zona libre (heap)
es la que va a contener los datos dinmicos. En cada instante de la ejecucin del programa, el
heap tendr partes asignadas a datos dinmicos y partes libres disponibles para asignacin de
memoria, como puede observarse en la figura 2.1. El mecanismo de asignacin-liberacin de
memoria durante la ejecucin del programa hace que esta zona est usualmente fragmentada
(ver figura 2.1), siendo posible que se agote su capacidad si no se liberan las partes utilizadas
ya inservibles. (La pila tambin vara su tamao dinmicamente, pero la gestiona el sistema
operativo, no el programador.)
Para trabajar con datos dinmicos son necesarias dos cosas:
Subalgoritmos predefinidos en el lenguaje (pseudolenguaje) que permitan gestionar la
memoria de forma dinmica (asignacin y liberacin).
Algn tipo de dato con el que sea posible acceder a esos datos dinmicos (ya que con
los tipos vistos hasta ahora en las asignaturas de IC y EP slo se puede acceder a
datos con un tamao y forma ya determinados).
2.2. Tipo Puntero
El tipo puntero y las variables declaradas de tipo puntero se comportan de manera diferente a
las variables estticas estudiadas en los temas anteriores de las asignaturas de IC y EP. Hasta
ahora, cuando se declaraba una variable de un determinado tipo, sta poda contener
directamente un valor de dicho tipo, simplemente llevando a cabo una asignacin de ese valor
a la variable. Con las variables de tipo puntero esto no es as.
Las variables de tipo puntero permiten referenciar datos dinmicos, es decir, estructuras de
datos cuyo tamao vara en tiempo de ejecucin. Para ello, es necesario diferenciar claramente
entre:
la variable referencia o apuntadora, de tipo puntero,
y la variable annima referenciada o apuntada, de cualquier tipo, tipo que est
asociado siempre al puntero.
Fsicamente, el puntero no es ms que una direccin de memoria. En la figura 2.2 se
muestra un ejemplo, a modo de esquema terico, de lo que podra ser el contenido de varias
posiciones de memoria principal, en la que se puede ver cmo una variable apuntadora o
puntero, almacenado en la posicin de memoria 7881
(16
, contiene, a su vez, otra direccin de
memoria, la 78AC
(16
, la de la variable referenciada o annima, que contiene el dato 6677
(16
.
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 5

De esta manera se ilustra cmo el puntero contiene una direccin de memoria que apunta a la
posicin de memoria donde se almacena un dato de cierto tipo asociado al puntero.

...
78AC
(16

...
AACC
(16

6743
(16

6677
(16

89FF
(16

DC34
(16

...
...
7881
(16
...

78AA
(16
78AB
(16
78AC
(16
78AD
(16
78AE
(16
...
Puntero
Variable
referenciada
Direccin Contenido

Figura 2.2. Esquema de posiciones de memoria con punteros
Definicin: un puntero es una variable cuyo valor es la direccin de memoria de otra variable
Segn su definicin, un puntero se refiere indirectamente a un valor, por lo que no hay que
confundir una direccin de memoria con su contenido (ver figura 2.3).

... ... ...
z
... ... ...
Direccin 7C16
(16
7C17
(16
7C18
(16

VARIABLES
C car = z
Direccin de la variable car = 7C17
(16

Contenido de la variable car = z

Figura 2.3. Esquema de posiciones de memoria donde se muestra la diferencia entre la
direccin de una variable y su contenido
Una variable de tipo puntero no puede apuntar a cualquier variable annima; debe apuntar
a variables annimas de un determinado tipo. El tipo de la variable annima debe ser incluido
en la especificacin del tipo de la variable puntero.
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 6

2.2.1. Declaracin de variables de tipo puntero
La declaracin de una variable de tipo puntero
1
en el pseudolenguaje de la asignatura consiste
en un tipo base, un asterisco * y el nombre de la variable. La forma general de la declaracin
de una variable de tipo puntero es, segn la notacin BNF, la siguiente (en la correspondiente
seccin de VARIABLES):
<Def_TipoPuntero> ::= <TipoBase> *<TipoPuntero>
donde <TipoBase> es el tipo base del puntero, que puede ser cualquier tipo vlido, simple
o compuesto. Ejemplos de declaracin de variables de tipo puntero son los siguientes:
VARIABLES
N *contador // Puntero a una variable de tipo natural (N)
C *car // Puntero a una variable de tipo carcter (C)
As, la variable contador del ejemplo anterior no contiene un valor de tipo natural (N), sino
la direccin de memoria donde estar almacenado un valor de tipo natural. El valor
almacenado en la variable annima de tipo natural ser accesible a travs del puntero
contador.
Tambin es posible, como para el resto de los tipos simples o compuestos vistos en las
asignaturas de IC y EP, declarar nuevos tipos puntero, mediante la inclusin de los mismos en
la correspondiente seccin de TIPOS del algoritmo, siguiendo la sintaxis vista ms arriba. A
partir de estos nuevos tipos, pueden declararse nuevas variables. Por ejemplo,
TIPOS
N *TipoPtrNatural // Tipo puntero a un nmero natural
C *TipoPtrCaracter // Tipo puntero a un carcter
...
VARIABLES
TipoPtrNatural contador, ptr // Variables de tipo puntero
// a un nmero natural
TipoPtrCaracter car // Variable de tipo puntero a un carcter


33
ptr

Figura 2.4. Representacin grfica de punteros

1
Para abreviar, se suele llamar puntero a una variable de tipo puntero, por lo que, a partir de ahora, se utilizar ms
asiduamente ese primer trmino por ser de uso ms comn y conciso.
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 7

El hecho de que la variable ptr, declarada en el ejemplo anterior, est apuntado a un dato
de tipo natural de valor, por ejemplo, 33, puede representarse grficamente como en la figura
2.4 (siendo muy til este tipo de representacin para posteriores operaciones donde intervienen
punteros de una manera ms compleja, como en el caso de las listas enlazadas que se
analizarn al final del captulo).
Un puntero puede apuntar a cualquier tipo de dato predefinido del pseudolenguaje o bien
definido por el usuario, tanto tipos simples como tipos compuestos. Es importante tener en
cuenta, en el caso de tipos definidos por el usuario, que primero debe declararse el tipo de
datos al que apuntar el puntero (un array, un registro, etc.) y, posteriormente, el tipo de datos
puntero a ese tipo definido por el usuario. Por ejemplo,
TIPOS
REGISTRO TipoComplejo
R parteReal, parteImaginaria
FINREGISTRO
TipoComplejo *TipoPtrComplejo /* TipoPtrComplejo es un tipo
puntero a un registro */
VARIABLES
TipoComplejo *ptr1 // Puntero a un registro
TipoPtrComplejo ptr2 // Puntero a un registro
De esta forma, en el ejemplo anterior, ptr1 y ptr2 son variables de tipo puntero que
contendrn direcciones de memoria donde estarn almacenadas variables (annimas) de tipo
TipoComplejo. Es importante, por tanto, que el dato al que apunte el puntero sea del tipo
base del que se ha declarado ste. Puede considerarse como una buena norma de estilo, la
declaracin del tipo de datos puntero a <TipoBase> inmediatamente despus de la propia
declaracin de <TipoBase>, como se ha hecho en el ejemplo anterior para
TipoPtrComplejo y TipoComplejo, respectivamente.
2.2.2. Operaciones con Punteros
Las operaciones que se pueden llevar a cabo con punteros son:
Operaciones especficas de punteros.
Asignacin de punteros.
Comparacin de punteros.
Operadores especficos de punteros
Para trabajar con punteros se utilizan dos operadores especficos: el operador de direccin (&)
y el operador de indireccin (*).
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 8

El operador de direccin (&) es un operador monario (slo requiere un operando) que
devuelve la direccin de memoria del operando. Por ejemplo,
...
VARIABLES
Z valor, dato = -333
Z *ptrValor
...
INICIO
...
valor = 999
ptrValor = &valor
En el ejemplo anterior se consigue que el puntero ptrValor contenga la direccin de
memoria donde est almacenado el dato que contiene la variable valor, es decir, 999. Puede
decirse que la instruccin ptrValor = &valor significa ptrValor recibe la direccin de
valor. Esto puede verse grficamente en la figura 2.5.

... ...
-333 999
... ...
7C17

Direccin 7C16 7C17 7C18
valor ptrValor dato
ptrValor = &valor

Figura 2.5. Operador de direccin
El operador de contenido o indireccin (*) es el operador complementario del operador de
direccin (&). Es tambin un operador monario, que devuelve el valor de la variable annima
ubicada en la direccin a la que apunta el puntero.
Continuando con el ejemplo anterior, si ptrValor contiene la direccin de memoria de la
variable valor, entonces es posible hacer la siguiente asignacin:
dato = *ptrValor

... ...
999 999
... ...
7C17

Direccin 7C16 7C17 7C18
valor ptrValor dato
dato = *ptrValor

Figura 2.6. Operador de indireccin
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 9

Esta asignacin colocar el valor de la posicin de memoria 7C17
(16
, es decir el nmero
999, en la variable dato, como se esquematiza en la figura 2.6.
Nota: no se debe confundir el operador * de las declaraciones de punteros (N *ptrNatural)
con el operador de indireccin usado en los ejemplos anteriores (*ptrNatural = 939).
Asignacin de punteros
Justo despus de declarar un puntero con la sintaxis vista en el apartado 2.2.1, el puntero
contiene un valor indeterminado. Por ello, no es correcto, desde el punto de vista del
pseudolenguaje, hacer uso del puntero (por ejemplo a la derecha de una asignacin en la que
aparece precedido del operador de indireccin) antes de asignarle valor al mismo.
Una primera manera de inicializar el valor de un puntero es asignarle el valor nulo. De esta
manera podemos considerar que el puntero, en lugar de apuntar a una posicin indeterminada
cuyo acceso sera incorrecto (porque podra contener cualquier dato incluso de otros
programas), no estar apuntando a ninguna parte. La manera de que dispone el
pseudolenguaje de realizar esta inicializacin es mediante la asignacin al puntero,
independientemente de su tipo, de la constante predefinida NULO. Podramos considerar que el
pseudolenguje garantiza que no existe ningn dato en la posicin NULO. Por ejemplo, si se
declara la variable ptrReal como un puntero a un nmero real (R), sera posible hacer la
siguiente asignacin, indicando que ptrReal no apunta a ninguna parte en este momento:
ptrReal = NULO
Esto se representar grficamente como en la figura 2.7.


ptrReal
ptrReal = NULO

Figura 2.7. Asignacin de NULO a una variable de tipo puntero
Es posible asignar el valor de una variable puntero a otra variable puntero, siempre que
ambas sean del mismo tipo. Por ejemplo,
R *ptrReal1, *ptrReal2=NULO
...
ptrReal1 = ptrReal2
En este ltimo ejemplo la variable ptrReal1 apuntar a donde apunte la variable
ptrReal2, en este caso a NULO. Es importante tener en cuenta que si ptrReal1, antes de la
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 10

asignacin, estaba apuntando a una variable annima de tipo real (y, por tanto, tena un valor
distinto del valor NULO), sta ser a partir de ahora inaccesible, puesto que la nica manera de
acceder a ella era a travs del puntero ptrReal1 y ahora ste apunta a otra variable annima
o, como en este ejemplo, a NULO.
Comparacin de punteros
Es posible comparar dos variables de tipo puntero en una expresin relacional usando
operadores relacionales de igualdad (==), desigualdad (!=) y comparacin (<, >, <=, >=).
Dos variables puntero son iguales si ambas apuntan a la misma variable annima o ambas
estn inicializadas al valor NULO. Los punteros que constituyen los operandos de estas
operaciones relacionales binarias deben ser siempre del mismo tipo. Sin embargo, siempre es
posible comparar cualquier puntero (igualdad o desigualdad) con el valor NULO. Ejemplo,
SI (ptr1 < ptr2) ENTONCES
Escribir(ptr1 apunta a una direccin menor que ptr2)
FINSI
2.2.3. Gestin Dinmica de Memoria
Por gestin dinmica de memoria se entiende el hecho de crear variables annimas, es decir,
reservar espacio en memoria para estas variables en tiempo de ejecucin, y tambin de liberar
el espacio ocupado en memoria por una variable annima, asimismo en tiempo de ejecucin,
cuando esa variable ya no es necesaria.
Por tanto, antes de asignar a la variable annima de un puntero un determinado valor (por
ejemplo, *ptrNatual = 333) es necesario reservar memoria para almacenar dicho valor.
Reservar memoria significa que el sistema le asigna al puntero (ptrNatural) una direccin de
memoria libre para su variable annima donde podr guardar el valor asignado (en este caso
333). Si la reserva de memoria no se realiza como paso previo a la asignacin anterior, se
producir una violacin de acceso a memoria porque el puntero estar inicialmente apuntando
a una direccin indeterminada o nula donde no es posible guardar el dato.
El pseudolenguaje de las asignaturas de introduccin a la programacin consta de dos
subalgoritmos predefinidos para la gestin de memoria dinmica: ASIGNAR y LIBERAR. Ambos
tienen un nico parmetro, de tipo puntero (a cualquier tipo de dato). El subalgoritmo ASIGNAR,
como su propio nombre indica, asigna (reserva) memoria para la variable annima del puntero
cuyo identificador se le pasa como parmetro. No es necesario indicar el tamao del dato que
se reserva, ya que la funcin ASIGNAR se encarga de reservar tanto espacio en memoria como
sea necesario para almacenar el tipo de dato base del puntero. Por su parte, el sugprograma
LIBERAR libera la memoria asignada a la variable annima del puntero cuyo identificador se
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 11

pasa como parmetro. Como efecto lateral derivado de la llamada a la funcin LIBERAR para
un determinado puntero, se le asigna a ste la constante NULO. Por ejemplo,
VARIABLES
R *ptr1, *ptr2 // 1) Declaracin de punteros
INICIO
ASIGNAR(ptr1) // 2) Reserva memoria
ASIGNAR(ptr2) // 2) Reserva memoria
*ptr1 = 99.9 // 3) Asignacin de valor a la variable annima
*ptr2 = -33.3 // 3) Asignacin de valor a la variable annima
*ptr1 = *ptr2 // 4) Asigna 333 al dato apuntado por ptr1
ptr1 = ptr2 /* 5) Asignacin de punteros.
Se pierde la referencia al dato previamente
apuntado por ptr1!!!! */
LIBERAR(ptr2) /* 6) Se libera la memoria a la que apunta ptr2
Se pone ptr2 a NULO */
*ptr1 = -999 // Error! La posicin est liberada

ptr1
ptr2
ptr1
ptr2
?
?
?
?
ptr1
ptr2
99.9
-33.3
1)
ptr1
ptr2
-33.3
-33.3
ptr1
ptr2
-33.3
-33.3
2) 3) 4)
5)
ptr1
ptr2
-33.3
?
6)

Figura 2.8. Ilustracin de un ejemplo de gestin dinmica de memoria
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 12

En la figura 2.8 se ilustra el funcionamiento del ejemplo anterior. Como puede
comprobarse, hay que diferenciar claramente entre la asignacin de punteros (operacin 5 en
el ejemplo) y la asignacin de valores a las variables annimas correspondientes a esos
punteros (operaciones 3 y 4). Por otro lado, es importante sealar la necesidad de una correcta
gestin de la memoria dinmica que evite dejar posiciones de memoria inaccesibles, como
ocurre como resultado de la operacin 5 en el ejemplo anterior, as como acceder a posiciones
de memoria incorrectas (no asignadas al puntero), como ocurre en la operacin 6 de dicho
ejemplo.
Es importante sealar aqu que la funcin ASIGNAR del pseudolenguaje se comporta de
manera ideal, en el sentido en que se considera que la memoria tiene una capacidad terica
infinita y siempre es posible reservar espacio para nuevos datos. En esto la semntica de la
funcin ASIGNAR difiere de la de las funciones equivalentes en los lenguajes de programacin
reales (incluyendo C/C++) donde s existen las inevitables limitaciones de recursos de
almacenamiento y no siempre se satisfacen las peticiones de reserva, por lo que dichas
funciones necesitan devolver algn dato que indique si la reserva ha sido efectuada
correctamente.
2.2.4. Punteros a registros
Hasta ahora, en los apartados anteriores, en los que se ha definido el tipo puntero y sus
operaciones bsicas, no se ha mostrado la verdadera utilidad de los punteros. En los ejemplos
vistos hasta ahora, los punteros manejados han sido meros punteros a datos simples, como
reales, naturales o caracteres. Aunque puede considerarse que se trata de una verdadera
gestin dinmica de memoria, dado que es necesario asignar memoria antes de usar esos
datos y liberarla cuando dejan de usarse, realmente no aporta grandes ventajas a las variables
de tipo esttico. La situacin cambia cuando el tipo base de las variables puntero es un tipo
complejo, como es el caso de los registros. En ese momento, se pone de manifiesto la
verdadera potencialidad de los punteros como elementos para una eficiente gestin de
memoria en tiempo de ejecucin, como se ver en el siguiente apartado sobre listas enlazadas.
Como se ha comentado en los apartados anteriores, es posible declarar tipos y variables
de tipo puntero de cualquier tipo base, ya sea ste simple o complejo. Un tipo especial, de gran
utilidad, es el tipo puntero a registro. La declaracin de un puntero a un registro sigue la
sintaxis vista en los apartados anteriores. Por ejemplo,
TIPOS
REGISTRO TipoComplejo
R real, imag
FINREGISTRO
TipoComplejo *TipoPtrComplejo
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 13

VAR
TipoPtrComplejo ptr
En este ltimo ejemplo la variable ptr es un puntero a un dato de tipo registro,
concretamente de tipo TipoComplejo. En el momento en que tenga lugar una asignacin de
memoria a ptr ste apuntar a una posicin de memoria donde se almacenan los datos
correspondientes a los dos campos que contiene el registro: real y imag. Esto puede
representarse grficamente como en la figura 2.9.


?
ptr
?
ASIGNAR(ptr)
real imag

Figura 2.9. Asignacin de memoria para un puntero a registro
Para acceder a los campos del registro puede combinarse el operador de indireccin (*)
con la notacin punto, ayudndose de los parntesis para tener que evitar establecer una
precedencia en estos operadores. Por ejemplo, podra hacerse lo siguiente:
(*ptr).real = 3.33
(*ptr).imag = -9.99
Adems de esta notacin, el pseudolenguaje introduce una nueva notacin mediante el
operador -> (podemos llamarlo flechita) como simplificacin del uso combinado del operador
de indireccin y la notacin punto. Basta con intercalar este nuevo operador entre el
identificador del puntero y del campo para indicar que se accede a ese campo de la variable
annima de tipo registro. Por ejemplo, las dos operaciones equivalentes a las anteriores seran:
ptr->real = 3.33
ptr->imag = -9.99
El resultado, de una u otra forma, sera el ilustrado en la figura 2.10.


3.33
ptr
-9.99
ptr->real = 3.33
ptr->imag = -9.99
real imag

Figura 2.10. Asignacin a campos de registros apuntados por punteros
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 14

Como se ha comentado ms arriba, el tipo base de un puntero puede ser tan complejo
como se quiera, incluyendo registros o arrays que, a su vez, contienen otros registros o arrays
y as sucesivamente. De la misma manera, es posible declarar registros que contienen campos
de tipo puntero e, incluso, arrays de punteros. La utilidad y el uso de cada uno de estos tipos
dependern de la aplicacin. Sirvan simplemente como muestra los siguientes ejemplos, cuyo
funcionamiento se ilustra en la figura 2.11:
TIPOS
REGISTRO TpConstitucion // Registro con dos punteros
R *peso, *altura
FINREGISTRO
C TpNombre[1..100]
REGISTRO TpDatosPersonales
TpNombre nombre
TpConstitucion fisico /* Este campo es un registro
con punteros */
N edad
FINREGISTRO
TpDatosPersonales *TpPtrDatosPersonales // Puntero a registro
TpPtrDatosPersonales TpArrayPtrs[1..200] // Array de punteros
TpNombre *TpPtrArray // Puntero a un array de caracteres
VARIABLES
TpArrayPtrs grupo
TpPtrArray miNombre
...
INICIO
...
ASIGNAR(grupo[1]) /* Reservo memoria para el primer
puntero del array /*
ASIGNAR(grupo[1]->fisico.peso) /* Reservo memoria para el campo
peso del campo fisico del
primer puntero del array */
*(grupo[1]->fisico.peso) = 99.9
ASIGNAR(miNombre) // Reservo memoria para el array de caracteres
*miNombre[1]=A // O bien (*miNombre)[1] = A
...
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 15


...
grupo

33 A n ... e z
nombre fisico edad
peso altura
99,9 1.99

Figura 2.11. Estructuras complejas basadas en punteros
2.3. Operaciones sobre Listas Enlazadas
Los punteros y la asignacin dinmica de memoria permiten la construccin de estructuras
enlazadas. Una estructura enlazada es una coleccin de nodos, cada uno de los cuales
contiene uno o ms punteros a otros nodos. Cada nodo es un registro en el que uno o ms
campos son punteros.
La estructura enlazada ms sencilla es la lista enlazada. Una lista enlazada consiste en un
nmero de nodos, cada uno de los cuales contiene uno o varios datos, adems de un puntero;
el puntero permite que los nodos formen una estructura a modo de cadena o de lista
enlazada. En la figura 2.12 puede verse una representacin que ilustra este concepto. Como
puede observarse en esta figura, un puntero externo apunta al primer nodo de la lista. El
primer nodo es un registro que contiene (adems de los campos de datos) un puntero que
apunta al segundo nodo de la lista, y as sucesivamente. El puntero del ltimo nodo apuntar a
NULO, indicando que es el ltimo nodo de la lista.

Puntero externo
Campos de datos de
un nodo (registro)
Puntero a siguiente
ltimo nodo de la
lista (siguIente es
NULO)

Figura 2.12. Esquema de lista enlazada con punteros
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 16

Para ilustrar la listas enlazadas se mostrar a continuacin cmo definir, crear y manipular
(insertar elementos, buscar, eliminar, etc.) una lista enlazada cuyos nodos contienen un nico
campo de datos (adems de un puntero al siguiente nodo) de tipo carcter (C). Como se ha
dicho anteriormente, los elementos de las listas (en este caso caracteres) se guardan como
campos de registros que, adems, contienen un puntero que sirve de enlace con el siguiente
nodo de la lista que contiene el siguiente elemento.
Para este ejemplo se va a declarar el tipo TpLista, que se definir como un tipo puntero a
un tipo registro TpNodo que contiene un campo de tipo carcter y un puntero de tipo TpLista.
Ntese que la declaracin de TpLista es recursiva, en el sentido de que necesita TpNodo
para efectuarse, a la vez que TpNodo hace uso nuevamente de TpLista. Esta licencia se le
concede al pseudolenguaje de la asignatura para aumentar su expresividad y permitir este tipo
de declaraciones en las que se declara un tipo en base a otro tipo que, a su vez, vuelve a
recurrir al primero en su definicin.
TIPOS
TpNodo *TpLista
REGISTRO TpNodo
C caracter // Elemento del nodo
TpLista sig // Puntero al siguiente nodo
FINREGISTRO
Otra manera de hacer esto, completamente equivalente a la anterior, consiste en declarar
primero el registro, declarando el puntero sig como un puntero al mismo TpNodo para,
posteriormente, declarar TpLista. De esta manera,
TIPOS
REGISTRO TpNodo
C caracter // Elemento del nodo
TpNodo *sig // Puntero al siguiente nodo
FINREGISTRO
TpNodo *TpLista

lista
a b c

Figura 2.13. Lista enlazada de caracteres
En cualquier caso, se puede dibujar cada nodo de la lista enlazada como una caja con dos
campos: un carcter y un puntero. De esta forma, en la figura 2.13 se muestra una lista
enlazada con tres caracteres donde lista es una variable de tipo TpLista (puntero externo)
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 17

que apunta al primer nodo de la lista enlazada. Para ello sera necesaria, en primer lugar, la
siguiente declaracin de datos:
VARABLES
TpLista lista
Con esta estructura declarada, para almacenar una cadena de caracteres de cualquier
tamao bastar con ir leyendo (por ejemplo, por teclado) los caracteres uno a uno e ir creando
para cada uno un nuevo nodo (variable annima de tipo registro) donde almacenarlo, haciendo
siempre que cada nodo enlace con el siguiente y que el ltimo nodo de la lista apunte a NULO.
Si la entrada se realiza por teclado, puede establecerse un convenio para indicar dnde acaba
la introduccin de caracteres. Por ejemplo, el retorno de carro (carcter 13 en la tabla ASCII)
puede servir de indicador de fin de la entrada de datos.
A partir de lo expuesto, pueden identificarse tres operaciones bsicas sobre listas
enlazadas:
Creacin de una lista enlazada vaca.
Insercin de un nuevo nodo en la lista enlazada.
Eliminacin de un nodo en la lista enlazada.
Creacin de una lista enlazada vaca
El subalgoritmo para la creacin de una lista enlazada vaca (sin ningn elemento inicialmente)
es relativamente simple: basta con inicializar el puntero externo a NULO. Este algoritmo
recibir como parmetro de ES un elemento de tipo TpLista.
ALGORITMO CrearLista(ES TpLista lista)
INICIO
lista = NULO
FIN CrearLista
Insercin de un nuevo nodo en la lista enlazada
En la operacin de insercin de un nodo en una lista enlazada pueden distinguirse dos casos
claramente diferenciados:
Insercin de un nodo al principio de una lista.
Insercin de un nodo despus de un determinado nodo existente (por ejemplo, de
manera que la lista se mantenga ordenada en orden ascendente).
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 18

1) Insercin de un nuevo nodo al principio de una lista enlazada
Para insertar un nuevo nodo al comienzo de una lista enlazada deben seguirse los siguientes
pasos:
1. Crear un nodo para una variable annima auxiliar, previamente declarada de tipo TpLista.
ASIGNAR(ptr) // ptr antes declarado como TpLista ptr
2. Asignar un valor (carcter) al campo de datos de la nueva variable annima.
ptr->caracter = d
3. Hacer que el campo siguiente del nuevo nodo apunte donde actualmente apunte el puntero
externo de la lista, es decir, lista.
ptr->sig = lista
4. Por ltimo, debe actualizarse el puntero externo de la lista, es decir, lista, para que
apunte al primer nodo de la lista, que ser el que se acaba de introducir.
lista = ptr
Todo estos pasos se dan en el siguiente subalgoritmo para insertar un nuevo elemento al
principio de una lista de caracteres (cuyo funcionamiento se ilustra grficamente en la figura
2.14), que recibir como parmetros la lista (puntero de tipo TpLista) y el carcter a insertar
en el nuevo nodo:
ALGORITMO InsertarAlPrincipio(ES TpLista lista; E C car)
VARIABLES
TpLista ptr // Puntero auxiliar
INICIO
ASIGNAR(ptr) // Nuevo nodo
ptr->caracter = car
ptr->sig = lista
lista = ptr
FIN InsertarAlPrincipio
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 19


lista
a b c
1) y 2)
ASIGNAR(ptr)
ptr->caracter = d
ptr
d
3) ptr->sig = lista
4) lista=ptr
ptr
a
3)
4)

Figura 2.14. Insercin de un nodo al principio de una lista enlazada de caracteres
2) Insercin de un nuevo nodo en una posicin determinada de la lista
Cuando se desea insertar un nuevo elemento en una lista enlazada ordenada, de manera que
esta permanezca ordenada despus de la insercin, los pasos a seguir seran los siguientes
(para el caso de una lista de caracteres ordenados alfabticamente en orden ascendente):
1. Si la lista est vaca o el primer elemento de la lista es mayor (alfabticamente) que el
elemento a insertar, se procede como en el caso anterior en el que se insertaba el elemento al
principio de la lista. En otro caso, se sigue con los puntos siguientes.
2. Crear el nuevo nodo, reservando espacio para el mismo y almacenando en su campo de
datos (caracter) el nuevo elemento que se desea insertar. Es aconsejable utilizar, para ello,
una variable auxiliar de tipo TpLista, por ejemplo, la variable nuevoNodo. Opcionalmente,
puede ponerse el puntero sig del nuevo nodo apuntando inicialmente a NULO.
ASIGNAR(nuevoNodo)
nuevoNodo->caracter = d
nuevoNodo->sig = NULO
3. Se utiliza una nueva variable auxiliar ptr, de tipo TpLista, para recorrer cada uno de los
nodos de la lista hasta encontrar en lugar exacto donde debe insertarse el nuevo elemento;
para ello, ptr estar siempre apuntando al nodo anterior al nodo cuyo elemento se est
comparando con el elemento a insertar, de manera que una vez que se localice el lugar de
insercin sea posible enlazar correctamente el nuevo nodo en la lista, mantenindola
ordenada. Esto se hara de la siguiente manera, para el ejemplo que se viene mostrando:
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 20

ptr = lista
MIENTRAS (ptr->sig != NULO) Y
(nuevoNodo->carcter > ptr->sig->caracter) HACER
ptr = ptr->sig
FINMIENTRAS
nuevoNodo->sig = ptr->sig
ptr->sig = nuevoNodo
El algoritmo quedara de la siguiente manera (grficamente, en la figura 2.15):
ALGORITMO InsertarOrdenada(ES TpLista lista; E C car)
VARIABLES
TpLista nuevoNodo, ptr
INICIO
SI lista == NULO O lista->carcter >= car ENTONCES
InsertarAlPrincipio(lista, car)
SINO
ASIGNAR(nuevoNodo)
nuevoNodo->caracter = car
nuevoNodo->sig = NULO
ptr = lista
MIENTRAS ptr->sig != NULO Y
(car > ptr->sig->caracter HACER
ptr = ptr->sig
FINMIENTRAS
nuevoNodo->sig = ptr->sig
ptr->sig = nuevoNodo
FINSI
FIN InsertarOrdenada
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 21


lista
a b d
2)
ASIGNAR(nNodo)
nNodo->caracter = c
nNodo->sig = NULO
nNodo
c
3) /* Localizacin
del lugar de
insercin (bucle)*/

ptr
lista
a b d
nNodo
c
ptr
3) /* Enlace de
punteros para
mantener la
ordenacin */


Figura 2.15. Insercin de un nodo en una lista ordenada
Eliminacin de un nodo de una lista enlazada
Como en el caso de la insercin de nuevos nodos, en la operacin de eliminar un nodo de una
lista enlazada pueden tambin diferenciarse dos situaciones:
Borrar el primer nodo de la lista enlazada.
Borrar un determinado nodo de la lista enlazada.
1) Borrar el primer nodo de una lista enlazada
Los pasos a seguir son los siguientes:
1. Declaracin de un puntero auxiliar, que se inicializar de manera que apunte al primer nodo
de la lista, que es el que se desea borrar.
ptr = lista
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 22

2. Se actualiza el puntero externo de la lista (lista) para que apunte al segundo elemento de
la misma, si existe, o bien a NULO. Para ello, basta con hacer:
lista = lista->sig
3. Por ltimo, es importante liberar la memoria correspondiente al nodo que se desea eliminar y
al que est apuntando actualmente el puntero auxiliar ptr.
LIBERAR(ptr)
El algoritmo (ilustrado en la figura 2.16) quedara de la siguiente manera:
ALGORITMO EliminarPrimero(ES TpLista lista)
VARIABLES
TpLista ptr
INICIO
SI lista != NULO ENTONCES // Si no, no hay que eliminar nada
ptr = lista
lista = lista->sig
LIBERAR(ptr)
FINSI
FIN EliminarPrimero

lista
a b c
ptr
lista
a b c
ptr
1)
2) y 3)

Figura 2.16. Borrar el primer nodo de una lista enlazada
2) Borrar un determinado nodo de la lista enlazada
Para borrar un nodo concreto de la lista enlazada ordenada (diferente del primero) son
necesarios dos punteros auxiliares: uno apuntando al nodo a borrar, que tendr el nombre de
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 23

ptr en el algoritmo que sigue, y otro puntero que apunte al nodo anterior al nodo que debe
eliminarse, que se denominar ant. De este modo, la operacin de enlace de los nodos para
saltar el nodo eliminado ser bastante simple, como se muestra en algoritmo
BorrarOrdenada. La localizacin del nodo a borrar debe tener en cuenta el hecho de que la
lista est ordenada y de que puede que el elemento no exista. Si la lista no estuviese
ordenada, lo nico que sera diferente en este algoritmo sera la forma de localizar el nodo a
borrar.
ALGORITMO BorrarOrdenada(ES TpLista lista; E C car)
VARIABLES
TpLista ptr, ant=NULO
INICIO
SI lista != NULO ENTONCES // Si no, no hay que hacer nada
ptr = lista
MIENTRAS ptr != NULO Y ptr->caracter != car HACER
ant = ptr
ptr = ptr->sig
FINMIENTRAS
SI ptr != NULO ENTONCES // Encontrado
SI ant == NULO ENTONCES // Es el primer elemento
lista = lista->sig
SINO
ant->sig = ptr->sig
FINSI
LIBERAR(ptr)
FINSI
FINSI
FIN BorrarOrdenada
En la figura 2.17 se muestra la operacin de eliminacin de un nodo (que contiene la letra
b) en una lista enlazada ordenada.

lista
a b c
ptr ant

Figura 2.17. Eliminacin de un nodo en una lista enlazada ordenada
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 24

Otras operaciones con listas enlazadas
Puede completarse el conjunto de operaciones bsicas con listas enlazadas incorporando dos
nuevas operaciones, de gran utilidad: visualizar una lista escribindola, por ejemplo, en la
salida estndar (pantalla) y eliminar todos los nodos de una lista. Esta ltima operacin es
necesaria en situaciones donde es preciso eliminar una lista completa y liberar la memoria
ocupada por todos sus nodos. A continuacin se muestran ambos subalgoritmos.
ALGORITMO EscribirLista(E TpLista lista)
VARIABLES
TpLista ptr = lista
INICIO
MIENTRAS ptr != NULO HACER
Escribir(ptr->caracter)
ptr = ptr->sig
FINMIENTRAS
FIN EscribirLista
ALGORITMO BorrarLista(ES TpLista lista)
VARIABLES
TpLista ptr
INICIO
MIENTRAS lista != NULO HACER
ptr = lista
lista = lista->sig
LIBERAR(ptr)
FINMIENTRAS
FIN BorrarLista
2.3.1. Otras clases de listas enlazadas
Otras clases de listas enlazadas son las listas doblemente enlazadas. A diferencia de las listas
enlazadas vistas en los apartados anteriores, las listas doblemente enlazadas contienen dos
punteros en cada nodo, adems de los campos de datos propiamente dichos. Uno de estos
punteros, de manera similar a las listas enlazadas simples, apunta al siguiente nodo de la
lista, mientras que el otro puntero apunta al nodo anterior, tal y como se ilustra en la figura
2.18. Disponer de dos enlaces en lugar de uno tiene varias ventajas:
La lista puede recorrerse en cualquier direccin. Esto simplifica la gestin de la lista,
facilitando las inserciones y las eliminaciones.
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 25

Mayor tolerancia a fallos. Se puede recorrer la lista tanto con los enlaces hacia delante
como con los enlaces hacia atrs, con lo que si algn enlace queda invalidado por
algn error, se puede reconstruir la lista utilizando el otro enlace.
El inconveniente principal de estas listas es que a la hora de realizar operaciones de
insercin o eliminacin de nodos es mayor el nmero de punteros que hay que mover para
mantener la lista correctamente enlazada. Eso requiere que la implementacin de las
operaciones deba ser ms cuidadosa que en el caso de las listas simples.
Existe un caso especial de lista doblemente enlazada donde el puntero que apuntan al
nodo anterior del primer nodo de la lista, en lugar de estar apuntando a NULO, apunta al ltimo
elemento de la lista, mientras que el puntero que apunta al nodo siguiente del ltimo nodo de la
lista, en lugar de apuntar a NULO, apunta al primer nodo de la lista. Este tipo de lista se
denomina lista doblemente enlazada circular y permite, entre otras cosas, hacer recorridos
completos de la lista sin necesidad de empezar en el primer nodo y sin tener que cambiar el
sentido del recorrido. Tambin es posible implementar listas simples circulares, donde el
campo sig del ltimo nodo de la lista apunta al primer nodo de la lista.

datos datos datos
lista

Figura 2.18. Lista doblemente enlazada
La forma de construir una lista doblemente enlazada es similar a la de la lista enlazada
simple, con la principal diferencia de que hay que mantener dos enlaces en lugar de uno. Por
tanto, el registro que constituye cada nodo debe contener, adems de los campos de datos,
dos campos de tipo puntero a un nodo. Siguiendo con listas de caracteres, puede hacerse:
TIPOS
TpNodo *TpListaDoble
REGISTRO TpNodo
C caracter
TipoListaDoble *ant, *sig
FINREGISTRO
Las operaciones bsicas realizables con listas doblemente enlazadas coinciden con el caso
de las listas enlazadas simples, y son:
Creacin de una lista doblemente enlazada.
Insercin de un nodo en una lista doblemente enlazada.
Eliminacin de un nodo en una lista doblemente enlazada.
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 26

Creacin de una lista doblemente enlazada
Una lista doblemente enlazada se crea de la misma forma que una lista enlazada simple, esto
es, inicializando el puntero externo de la lista a NULO para indicar que la lista est vaca.
ALGORITMO CrearListaDoble (ES TpListaDoble listaDoble)
INICIO
listaDoble = NULO
FIN CrearListaDoble
Insercin de un nodo en una lista doblemente enlazada
En la operacin de insertar un nodo en una lista doblemente enlazada pueden distinguirse dos
casos claramente diferenciados, como en el caso de las listas simples:
Insercin de un nodo al principio de la lista.
Insercin del nodo despus de un determinado nodo existente (por ejemplo, para
mantener la lista ordenada alfabticamente en orden ascendente).
1) Insercin de un nodo al principio de una lista doblemente enlazada
El algoritmo para insertar un nodo al comienzo de una lista doblemente enlazada que ha sido
previamente creada (precondicin necesaria) se muestra a continuacin:
ALGORITMO InsertaAlPrincipioDoble(ES TpListaDoble listaDoble; E C car)
VARIABLES
TpListaDoble ptr
INICIO
ASIGNAR(ptr) // Reserva de memoria
ptr->caracter = car // Inicializacin de campos del nuevo nodo
ptr->ant = NULO
ptr->sig = NULO
SI (listaDoble != NULO) ENTONCES // Lista no vaca
ptr->sig = listaDoble
listaDoble->ant = ptr
FINSI
listaDoble = ptr // Nuevo primer nodo de la lista
FIN InsertaAlPrincipioDoble
2) Insercin de un nodo en una posicin determinada de una lista doblemente enlazada
Para insertar un nodo en una lista doblemente enlazada ordenada, de manera que se
mantenga ordenada despus de la insercin, es necesario, en primer lugar, localizar la posicin
de la lista donde debe insertarse el nodo. Un algoritmo para insertar un nodo en una posicin
determinada de una lista enlazada doble es el siguiente:
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 27

ALGORITMO InsertarOrdenadaDoble (ES TpListaDoble listaDoble; E C car)
VARIABLES
TpListaDoble ptr, ant, nuevo
INICIO
SI listaDoble == NULO O listaDoble->caracter >= car) ENTONCES
InsertaAlPrincipoDoble(listaDoble, car)
SINO
ASIGNAR(nuevo)
ant = listaDoble
ptr = listaDoble->sig // Apunta al segundo nodo o NULO
MIENTRAS ptr != NULO Y car > ptr->caracter HACER
ant = ptr
ptr = ptr->sig
FINMIENTRAS
SI ptr == NULO ENTONCES // Se inserta al final
nuevo->ant = ant
ant->sig = nuevo
SINO // Se inserta en medio de la lista
nuevo->sig = ptr
nuevo->ant = ant
ant->sig = nuevo
ptr->ant = nuevo
FINSI
FINSI
FIN InsertarOrdenadaDoble
En la figura 2.19 se muestra el funcionamiento de este algoritmo. Ntese el movimiento de
punteros necesario para mantener la lista enlazada.




c

k

a

v

f

ant

ptr

listaDoble


Figura 2.19. Insercin en una lista doblemente enlazada
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 28

Eliminacin de un nodo de una lista doblemente enlazada
En la operacin de eliminar un nodo de una lista doblemente enlazada pueden distinguirse dos
casos claramente diferenciados, como en el caso de las listas simples:
Borrar el primer nodo de la lista.
Borrar un determinado nodo existente (por ejemplo, de forma que se mantenga la lista
ordenada alfabticamente en orden ascendente despus de la operacin de borrar).
1) Borrar el primer nodo de la lista doblemente enlazada
ALGORITMO EliminarPrimeroDoble(ES TpListaDoble listaDoble)
VARIABLES
TpListaDoble ptr
INICIO
SI listaDoble != NULO ENTONCES // Si no, no hacemos nada
ptr = listaDoble
listaDoble = listaDoble->sig
LIBERAR(ptr)
FINSI
FIN EliminarPrimeroDoble
2) Borrar un nodo de una posicin determinada de la lista
Para borrar un nodo de una posicin determinada de la lista se necesitan dos punteros
auxiliares: uno apuntando al nodo a borrar, que se denominar ptr en el algoritmo que se
muestra a continuacin; y otro que apunte al nodo anterior al nodo que se va a eliminar, que se
llamar ant. Esto permitir dejar la lista correctamente enlazada despus de la liberacin de la
memoria correspondiente al nodo borrado.
ALGORITMO BorrarOrdenadaDoble(ES TpListaDoble listaDoble; E C car)
VARIABLES
TpListaDoble ant, ptr
INICIO
ant = NULO
ptr = listaDoble
MIENTRAS ptr != NULO Y ptr->caracter != car HACER
ant = ptr
ptr = ptr->sig
FINMIENTRAS
SI ptr != NULO ENTONCES // Se ha encontrado el elemento
SI ant == NULO ENTONCES
// El elemento a borrar es el primero
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 29

listaDoble = listaDoble->sig
SI listaDoble != NULO ENTONCES
// Hay ms nodos en la lista
listaDoble->ant = NULO
FINSI
SINO SI ptr->sig == NULO ENTONCES // Borrar el ltimo
ant->sig = NULO
SINO // El elemento a borrar est en medio de la lista
ant->sig = ptr->sig
ptr->sig->ant = ant
FINSI
LIBERAR(ptr)
FINSI
FIN BorrarOrdenadaDoble
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 30

2.4. Ejemplo de Gestin de Memoria Dinmica
en C/C++
En C/C++ la sintaxis de declaracin de punteros es similar a la vista para el pseudolenguaje en
los apartados anteriores: se usa el asterisco (*) a continuacin del tipo base para indicar que
se trata de un puntero a ese tipo base. Por otro lado, la operacin de asignacin de memoria se
lleva a cabo mediante la funcin new. Para ello se asigna al puntero el resultado de invocar la
funcin new para el tipo base del mismo, como se muestra en el ejemplo a continuacin. La
funcin delete equivale al subalgoritmo ASIGNAR del pseudolenguaje para la liberacin de
memoria. El siguiente ejemplo se presenta como una simple muestra de la sintaxis de C/C++
en el manejo de memoria dinmica mediante el uso de punteros
2
:
#include <iostream>
#include <stdlib.h>

struct TpNodo{
char car;
TpNodo *sig;
};
typedef TpNodo *TpPtrNodo;
void main(){
TpPtrNodo ptr;

ptr = new TpNodo; // Asignacin de memoria
ptr->car = 'a';
ptr->sig = NULL; // NULL equivale a NULO en el pseudolenguaje

cout << ptr->car << endl;
delete ptr; // Liberacin de memoria apuntada por ptr

system("pause");
}

2
En la asignatura de Laboratorio de Programacin se presentarn estos conceptos de manera ms extensa y
detallada.
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 31

Ejercicios Propuestos
1) Dada la siguiente declaracin de tipos adjunta:

a) Disea un algoritmo que imprima cada uno de los elementos
de una lista.
b) Disea un algoritmo que devuelva una copia de una lista.
c) Disea un algoritmo que devuelva la longitud de una lista.
d) Disea un algoritmo que elimine el ltimo elemento de una
lista.
e) Disea un algoritmo que ordene los elementos de una lista.
2) Dada la declaracin de tipos anterior y las variables l1 y l2 de tipo Lista, y siendo l1 la
siguiente lista enlazada:

l1
3 5 7


a) Qu diferencia existe entre las dos
instrucciones l2=l1 y Copiar(l1, l2), la
cual duplica una lista?
b) Qu valor contiene l2->sig tras realizar la
secuencia de instrucciones?:
l2=l1; LIBERAR(l1)
c) Dado el algoritmo Ejemplo adjunto, donde p
se pasa por valor, y el estado inicial de la lista
l1, qu ocurrir a la lista apuntada por l1 tras la siguiente llamada: Ejemplo(l1)?
3) Dada la declaracin de tipos adjunta:

a) Disea un algoritmo que inserte un elemento al inicio de una
lista.
b) Disea un algoritmo que inserte un elemento al final de una
lista.
c) Disea un algoritmo que elimine el primer elemento de una
lista.
d) Disea un algoritmo que elimine el ltimo elemento de una
lista.
e) Disea un algoritmo que elimine los datos correspondientes a
una persona con un nombre determinado de una lista.
f) Disea un algoritmo que devuelva una copia de una lista.
g) Disea un algoritmo que devuelva la longitud de una lista.
h) Disea un algoritmo que ordene una lista por el nombre de las personas.
TIPOS
Nodo *Lista
REGISTRO Nodo
Z elem
Lista sig
FINREGISTRO
ALGORITMO Ejemplo(E Lista p)
INICIO
SI p !=NULO ENTONCES
p->elem = 3
FINSI
FIN Ejemplo
REGISTRO Persona
C nombre[0..99]
N telfono
FINREGISTRO
Nodo *Lista
REGISTRO Nodo
Persona elem
Lista sig
FINREGISTRO
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 32

4) Dadas las definiciones de tipos adjuntas, disear los siguientes algoritmos:
a) Borrar todos los nodos de una lista enlazada y liberar
toda la memoria.
b) Duplicar una lista enlazada.
c) Borrar el nodo que contiene el mximo valor de una
lista enlazada.
d) Intercambiar el valor n-simo con el m-simo de la
lista.
e) Concatenar dos listas enlazadas.
f) Borrar el n-simo elemento de la lista.
g) Disear el algoritmo con la siguiente cabecera:
ALGORITMO TipoPuntero Busca(E TipoPuntero lista; E N elem)
que devuelva el puntero al nodo que contiene el natural elem, si existe, y NULO en
caso contrario.
h) Dada la siguiente cabecera:
ALGORITMO TipoPuntero InsBusca(ES TipoPuntero lista; E N elem)
aada elem a lista, si no est en ella, y siempre devuelve un puntero al nodo
que contiene elem.
5) Sea el tipo TipoLista adjunto. Resolver los siguientes apartados en base a este
tipo.
a) Disea un algoritmo Purgar(...) que elimine todos los
elementos duplicados una lista.
b) Disea un algoritmo BorrarUltimo(...) que elimine de
una lista el ltimo nodo que contiene la informacin k.
c) Dadas dos listas enlazadas ordenadas, l1 y l2 de tipo
TipoLista, escribe un algoritmo que mezcle las dos listas
(pasadas como parmetros) en otra, de forma que esta
ltima est tambin ordenada. l1 y/o l2 pueden estar
vacas. Resolverlo de dos formas:
Sin modificar las listas l1 y l2, creando una
lista nueva.
Modificando las listas l1 y l2, sin reservar
memoria adicional.
6) Hay muchas aplicaciones en las que se debe almacenar en la memoria un vector de
grandes dimensiones. Si la mayora de los elementos del vector son ceros, ste puede
representarse ms eficientemente utilizando una lista enlazada con punteros, en la que
cada nodo es un registro con tres campos: el dato en esa posicin si es distinto de cero, el
ndice de esa posicin y un puntero al siguiente nodo. Por ejemplo, para un vector de
longitud 7 la lista


1 25 5 14


representa el vector (25, 0, 0, 0, -14, 0, 0). Dado un tipo TVector de longitud
constante Dim disea algoritmos para:
a) Calcular su Producto_Escalar, pasndole como entrada v1 y v2 de tipo TVector.
Devolver un vector nuevo.
b) Insertar un valor teniendo en cuenta que si ya existe, se debe eliminar el valor
anterior. Si la posicin est fuera de rango, no har nada. Y si es cero el valor a
insertar no deber quedar guardado en la lista ningn nodo de ndice cero.
Nodo *TipoPuntero
REGISTRO Nodo
N valor
TipoPuntero sig
FINREGISTRO

Nodo *TipoLista
REGISTRO Nodo
N valor
TipoLista sig
FINREGISTRO

ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 33

c) Obtener el valor en una determinada posicin del vector.
d) Mejorar los apartados anteriores redefiniendo el tipo TVector como un registro de dos
campos, uno de ellos contendr el vector en el formato anterior y el otro indicar la
longitud, la cual ya no ser necesariamente constante.
7) Una forma de almacenar un nmero natural de valor mayor que el permitido en una
computadora es introducir cada dgito, de tipo natural, en un nodo de una lista enlazada.
Por ejemplo, la siguiente lista representa al nmero 357:

numero
3 5 7

a) Escribe un algoritmo que tome como parmetro un puntero a una lista enlazada que
represente un nmero de la forma indicada y devuelva el nmero correspondiente en
una variable de tipo natural.
b) Disea tambin un algoritmo que lea por teclado una sucesin de dgitos, de tipo
carcter, y los introduzca como dgitos de tipo natural en una lista enlazada.
c) Disea dos algoritmos que realicen, respectivamente, la suma y producto de nmeros
representados de esta forma.
8) Un polinomio en x, de tipo entero, de grado arbitrario se puede representar mediante una
lista enlazada, donde cada nodo contiene 1) el coeficiente, 2) el exponente de un trmino
del polinomio, y 3) un puntero al siguiente nodo. Por ejemplo, el polinomio P(x)25x 14x
5
se representara como indica la figura adjunta:

1 25 5 -14
p

a) Define el tipo TPolinomio que represente un polinomio mediante una lista enlazada
con punteros.
b) Escribe una funcin que evale un polinomio en un punto x:
ALGORITMO Z Evaluar(E TPolinomio p; E Z valor)
c) Escribe una funcin que obtenga el coeficiente del trmino de un determinado grado:
ALGORITMO TPolinomio Coeficiente(E TPolinomio p1; E N grado)
d) Escribe una funcin que sume 2 polinomios p1 y p2:
ALGORITMO TPolinomio Sumar(E TPolinomio p1, p2)
e) Escribe una funcin que realice la derivada de un polinomio P, con la siguiente
cabecera:
ALGORITMO TPolinomio Derivada(E TipoPolinomio p)
9) Supn que tienes diseado el tipo conjunto (coleccin no ordenada de elementos distintos)
mediante una lista enlazada dinmica con los tipos adjuntos:
a) Queremos disear las operaciones interseccin
y unin de dos conjuntos: Cmo seran las
cabeceras de los dos algoritmos que realizaran
estas tareas?. Al disear estos algoritmos,
modificas alguno de los dos conjuntos con los
que operas? Se ve eso reflejado en las
cabeceras?
b) Disea los algoritmos de acuerdo con las cabeceras del apartado a).
Elemento *Conjunto
REGISTRO Elemento
Z elem
Conjunto sig
FINREGISTRO
ETSI Telecomunicacin Memoria Dinmica


Elementos de Programacin Pgina 34

Bibliografa
Aho, A. V., Hopcroft, J. E., & Ullman, J. D. (1988). Estructuras de Datos y Algoritmos. Addison
Wesley Iberoamericana.
Cerrada, J. A., & Collado, M. (1995). Programacin I. UNED.
Dale, N., & Weems, C. (1989). Pascal (2 ed.). McGraw Hill.
Helman, P., Veroff, R., & Carrano, F. (1991). Intermediate Problem Solving and Data
Structures. Walls & Mirrors (2 ed.). The Benjamin/Cummings Publishing.
Horowitz, E., & Sahni, S. (1999). Fundamentals of Data Structures in Pascal (4 ed.). W. H.
Freeman & Co.
Joyanes, L. (1996). Fundamentos de Programacin. Algoritmos y Estructuras de Datos. (2 ed.).
McGraw Hill.
Langsam, Y., Augenstein, M. J., & Tanenbaum, A. M. (1995). Data Structures using C and C++
(2 ed.). Prentice Hall.
Weiss, M. A. (1995). Estructuras de Datos y Algoritmos. Addison Wesley Iberoamericana.

También podría gustarte