UNIVERSIDAD TECNOLÓGICA NACIONAL
FACULTAD REGIONAL TUCUMÁN
DEPARTAMENTO DE SISTEMAS
CÁTEDRA: ALGORITMOS Y ESTRUCTURAS DE DATOS
UNIDAD 6.- ABSTRACCIONES CON DATOS
OBJETIVOS:
Que el alumno:
• Comprenda el concepto de variables de tipo puntero.
• Utilice las variables de tipo puntero con las distintas estructuras de datos.
• Comprenda y utilice las variables de tipo puntero en una estructura dinámica
lineal y no lineal.
TEMAS:
1. Variables de tipo puntero.
2. Listas
1
UNIVERSIDAD TECNOLÓGICA NACIONAL
FACULTAD REGIONAL TUCUMÁN
DEPARTAMENTO DE SISTEMAS
CÁTEDRA: ALGORITMOS Y ESTRUCTURAS DE DATOS
1. VARIABLES DE TIPO PUNTERO.
Todo programa que está siendo ejecutado por la CPU, ocupa un bloque de
bytes en la memoria RAM del computador. Cuando un computador inicia su
funcionamiento, el programa que toma el control es el Sistema Operativo. El
mismo ocupa las direcciones bajas de memoria, es decir un bloque de bytes que
comienza en la posición 0. Normalmente estas direcciones tienen un tamaño de 4
bytes (32bits) y se representan en Hexadecimal. De tal manera que la memoria
RAM a la que se puede acceder en forma directa por la CPU comienza en la
posición “00 00 00 00” y termina en “FF FF FF FF”.
Cuando un programa se prepara para ejecutarse, el sistema operativo le
asigna un bloque de memoria RAM que se divide en los siguientes sectores:
CÓDIGO, DATOS, STACK (PILA), HEAP (MONTÍCULO).
• El sector CÓDIGO contiene las instrucciones del programa en lenguaje de
máquina absoluto.
• El de DATOS contendrá las variables globales del programa.
• En el STACK se almacenará las variables locales y los parámetros por valor
de las funciones que utilice el programa, y la dirección del código donde
deberá retornar cuando termine su ejecución.
• En el HEAP, que suele ser más grande que los otros sectores, se utiliza
para almacenar estructuras de datos que requieren cambiar su tamaño
durante la ejecución del programa y necesitan gran cantidad de bloques de
bytes.
Una distribución típica de
estos sectores se
representa en el siguiente
esquema:
2
UNIVERSIDAD TECNOLÓGICA NACIONAL
FACULTAD REGIONAL TUCUMÁN
DEPARTAMENTO DE SISTEMAS
CÁTEDRA: ALGORITMOS Y ESTRUCTURAS DE DATOS
En general los bloques de byte en el sector Stack, se van asignando a
medida que se ejecutan las funciones y se liberan cuando las mismas finalizan;
funcionando como una verdadera pila de datos, ya que el último bloque que se
ocupa es el primero que se desocupa cuando la función correspondiente termina
su ejecución. El Stack crece desde una posición determinada hacia la parte baja
de la memoria.
Por su parte, el Heap va creciendo desde una posición determinada,
normalmente la que sigue a la posición de inicio del Stack, hacia la parte alta de la
memoria. Los bloques de byte se van asignando mediante acciones del programa
y su manejo es muy particular, ya que se va ocupando y desocupando bloques de
memoria en forma prácticamente aleatoria tratando de aprovechar al máximo el
espacio que va quedando liberado o disponible.
Los tipos de datos que se almacenan en el sector DATOS y en el STACK,
ocupan un espacio fijo de memoria que no puede cambiarse durante la ejecución
del programa. Por ello es que se llama estos tipos “Estructuras ESTÁTICAS”, por
ejemplo, las variables simples tipo entero, real, lógicas o carácter, los arreglos, las
cadenas, los registros.
Por otro lado, los datos que se almacenan en el HEAP tienen como
característica que el espacio de memoria ocupado por los mismos puede
aumentar o disminuir durante la ejecución del programa. De ahí el nombre de
“Estructuras DINÁMICAS”, por ejemplo, las listas, pilas, colas, árboles y grafos.
TIPO PUNTERO Y ASIGNACIÓN DINÁMICA DE MEMORIA
Un tipo puntero representa la dirección de memoria de un bloque de byte
correspondiente a una estructura de datos cualquiera.
Las variables de tipo puntero ocupan 4 bytes de memoria, de tal manera
que pueden contener valores en el rango hexadecimal de “00 00 00 00” a “FF FF
FF FF”. Estas variables se alojan en el Sector DATOS o STACK, según donde se
declaren, en forma estática; pero, como veremos a continuación, nos permitirán
acceder al Sector HEAP para manejar Estructuras Dinámicas de Datos.
En lenguaje C++ se declaran las variables punteros utilizando la siguiente
sintaxis:
<tipo apuntado> *<identificador puntero>
Para realizar la asignación dinámica de memoria en C++ se cuenta con el
operador new, que lleva como operando el tipo de dato correspondiente al bloque
y devuelve como resultado un puntero al mismo. Si se produce algún problema
3
UNIVERSIDAD TECNOLÓGICA NACIONAL
FACULTAD REGIONAL TUCUMÁN
DEPARTAMENTO DE SISTEMAS
CÁTEDRA: ALGORITMOS Y ESTRUCTURAS DE DATOS
con la asignación de memoria en el HEAP, por ejemplo, falta de espacio; se
devuelve el valor NULL.
La característica principal de la asignación dinámica de memoria es la de
poder variar el tamaño de memoria que ocupa la estructura de datos.
Es importante destacar que cuando no se necesitan más esos bloques, se
puede desocuparlos o liberarlos y de ese modo disminuir el espacio de memoria
que ocupa la estructura, en el lenguaje C++ se usa el operador delete que
también lleva como operando al puntero.
Ejemplos:
Puntero a tipo int
#include <stdio.h>
#include <stdlib.h>
main()
{
int a, *p; //declara la variable a de tipo entera y la variable p que es un puntero
a una variable entero
a=15;
p=&a;
printf("El valor de a es: %d\n",a);
printf("Esta en la Direccion: %x",p);
*p=1000;
printf("\n\nNUEVO valor de a: %d\n",a);
printf("Esta en la Direccion: %x",p);
}
En el próximo ejemplo se usa sólo la variable de tipo puntero.
#include <stdio.h>
#include <stdlib.h>
main()
{
int *p;
p=new int;
*p=20;
printf("La direccion obtenida en p es: %x",p);
printf("\n\nEl valor almacenado es: %d\n",*p);
4
UNIVERSIDAD TECNOLÓGICA NACIONAL
FACULTAD REGIONAL TUCUMÁN
DEPARTAMENTO DE SISTEMAS
CÁTEDRA: ALGORITMOS Y ESTRUCTURAS DE DATOS
delete p;
}
Puntero con array
En el próximo ejemplo se declara al vector v como una variable de tipo puntero.
#include <stdio.h>
#include <stdlib.h>
main()
{
int *v,n,i;
printf("Ingrese el valor de n: ");
scanf("%d",&n);
/*crea el arreglo de n elementos en forma dinámica*/
v=new int[n];
for (i=0;i<n;i++)
{
printf("Ingrese el elemento de posicion %d: ",i);
scanf("%d",&v[i]);
}
/*devuelve la memoria usada*/
delete v;
}
Puntero con registros
En el próximo ejemplo se usa un registro en forma estática y dinámica.
#include <stdio.h>
#include <stdlib.h>
struct registro
{
int codigo;
float precio;
};
5
UNIVERSIDAD TECNOLÓGICA NACIONAL
FACULTAD REGIONAL TUCUMÁN
DEPARTAMENTO DE SISTEMAS
CÁTEDRA: ALGORITMOS Y ESTRUCTURAS DE DATOS
main()
{
registro a,*p;
//en forma estática
a.codigo=2;
a.precio=2.2;
printf("Codigo: %d\n",a.codigo);
printf("Precio: %.2f\n",a.precio);
//en forma dinámica
p=&a;
p->codigo=4;
p->precio=4.4;
printf("Codigo: %d\n",p->codigo);
printf("Precio: %.2f\n",p->precio);
}
ESTRUCTURA AUTO REFERENCIADA
Se llama estructura auto referenciada a un registro que tiene al menos dos
campos, en uno de los cuales se almacena una información determinada y en el
otro un puntero a la misma estructura. Se dice que esta definición es recursiva, ya
que para declarar el tipo correspondiente a este registro se debe declarar un
puntero al propio tipo que se está declarando.
Ejemplo:
struct nodo
{
int info;
nodo *sig;
};
Con esta clase de registros se pueden implementar estructuras dinámicas
más complejas, como ser: listas, pilas, colas, árboles y grafos.
2. LISTAS
Una lista es una estructura de datos en lineal, compuestas por nodos; en
ella no hay restricciones para las operaciones de inserción y eliminación.
6
UNIVERSIDAD TECNOLÓGICA NACIONAL
FACULTAD REGIONAL TUCUMÁN
DEPARTAMENTO DE SISTEMAS
CÁTEDRA: ALGORITMOS Y ESTRUCTURAS DE DATOS
Los tipos de listas pueden ser simples encadenadas, dobles encadenadas o
listas circulares.
PILAS
Es una estructura de datos lineal, donde la inserción y el borrado de los
nuevos elementos se realiza por sólo un extremo que se denomina frente. Esta
estructura posee numerosas analogías en la vida real, por ejemplo, imagine una
pila de platos.
Dado que las operaciones de insertar y eliminar se realizan por un solo
extremo (el superior), los elementos solo pueden eliminarse en orden inverso al
que se insertan en la pila. El último elemento que se pone en la pila es el primero
en sacar; dado a esto a estas estructuras se les conoce con el nombre de LIFO
(Last Input First Output).
Las operaciones que se pueden realizar con una pila son:
▪ INICIALIZAR (pila): Crea la estructura de pila asignando el valor NULL al
puntero.
▪ INSERTAR (pila, elemento): Introduce un elemento en la pila.
▪ ELIMINAR (pila): Elimina un elemento de la pila.
▪ RECORRER (pila): Permite recorrer la estructura de pila para ver o trabajar
con sus elementos.
/*CREA UNA PILA CON ESTRUCTURA DINAMICA Y ALMACENA DE LA MISMA
NUMEROS ENTEROS*/
#include <stdio.h>
#include <stdlib.h>
#include <conio.c>
struct nodo
{
int info;
nodo *sig;
};
7
UNIVERSIDAD TECNOLÓGICA NACIONAL
FACULTAD REGIONAL TUCUMÁN
DEPARTAMENTO DE SISTEMAS
CÁTEDRA: ALGORITMOS Y ESTRUCTURAS DE DATOS
void inicializar(nodo *&frente);
void insertar(nodo *&frente, int x);
int borrar(nodo *&frente);
void recorrer(nodo *frente);
main()
{
nodo *frente,*p;
int i,x;
inicializar(frente);
/*INGRESA TRES NODOS*/
for (i=0;i<3;i++)
{
printf("Ingrese el valor de x: ");
scanf("%d",&x);
insertar(frente,x);
}
printf("\n\nSE BORRA EL VALOR: %d\n\n",borrar(frente));
recorrer(frente);
}
void inicializar(nodo *&frente)
{
frente=NULL;
}
void insertar(nodo *&frente, int x){
nodo *p;
p=new nodo;
if (p!=NULL)
{
p->info=x;
p->sig=frente;
frente=p;
}
else
printf("ERROR - PILA LLENA");
}
8
UNIVERSIDAD TECNOLÓGICA NACIONAL
FACULTAD REGIONAL TUCUMÁN
DEPARTAMENTO DE SISTEMAS
CÁTEDRA: ALGORITMOS Y ESTRUCTURAS DE DATOS
int borrar(nodo *&frente)
{
if (frente!=NULL)
{
nodo *p;
int x;
p=frente;
x=frente->info;
frente=frente->sig;
delete p;
return x;
}
else
{
printf("ERROR - PILA VACIA");
return 0;
}
}
void recorrer(nodo *frente)
{
nodo *p;
p=frente;
while (p!=NULL)
{
printf("%d\n",p->info);
p=p->sig;
}
getch();
}