Estructuras de datos Estructuras de datos Estructuras de datos

Anuncio
Estructuras de datos
En la práctica de la programación de computadoras
existen muchos motivos para optimizar el uso de los
recursos, llamese tiempo de procesamiento o espacio
de almacenamiento.
El uso de la memoria dinámica permite contar con
medios racionales de almacenar datos de acuerdo a
los requerimientos actuales de cada aplicación o
ejecución de los programas.
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
Estructuras de datos
El lenguaje C provee de funciones para solicitar
memoria al sistema en tiempo de ejecución y para
liberarla en el momento en que ya no se use.
Esta facultad nos permite hacer uso de dicho recurso
a nuestro antojo y es junto con el manejo de los
apuntadores una de las caracteristicas más poderosas
del lenguaje C.
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Modelo
Modelode
delistas
listas
Estructuras de datos
Las funciones son:
void *malloc(size_t size); que reserva size bytes y
devuelve un apuntador generico(no asociado a
ningún tipo de dato). En caso de falla el apuntador es
nulo.
void free(void *ptr); libera la memoria apuntada
por ptr, ptr puede ser de cualquier tipo. Los bloques
a liberar debieron ser asignados de manera dinámica.
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
Estructuras de datos
Un ejemplo del uso de malloc se muestra a
continuación:
int *arreglo;
int longitud;
printf(“cuantos elementos quieres guardar?\n”):
scanf(“%d”, &longitud);
arreglo = (int *)malloc(longitud*sizeof(int));
cast
Aquí se esta reservando un arreglo de longitud
variable durante el tiempo de ejecución. Se hace un
cast y se usa la función sizeof.
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
1
Estructuras de datos
El cast es la capacidad del lenguaje C de convertir un
tipo de dato en otro. La condición es que el nuevo
tipo pueda contener al tipo de dato anterior. Por
ejemplo, un float puede contener a un entero o a un
char, pero un char no puede contener a un float o a
un int. Observese lo siguiente:
int a, b;
float c;
a = 5; b = 8;
c = a / b; //dara como resultado 0
c = (float)a /(float)b; //dara como resultado 0.625
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
Estructuras de datos
En el ejemplo de la lámina anterior, primero se
realiza la division de a y b como enteros y el
resultado es 0 como es natural. Después se
convierten tanto a como b en numeros flotantes y
se vuelve a realizar la división, ahora al ser los
operandos numeros flotantes el resultado será de
punto flotante.
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
Estructuras de datos
La función sizeof(datatype) devuelve el tamaño en
bytes de la memoria requerida para almacenar una
instancia de dicho tipo de datos.
Podemos usar las palabras reservadas para los tipos
de datos simples o las etiquetas que usemos con
typedef.
También es posible calcular el tamaño de estructuras
definidas con la palabra struct.
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
Estructuras de datos
Ejemplos:
a = sizeof(int);//resultara en 2 o 4 dependiendo del hardware
typedef struct{
char nombre[10];
float estatura;
int edad;
}PERSONA;
a = sizeof(PERSONA);//resultara en 16 o 18
struct agenda{
char nombre[10];
char telefono[10];
};
a = sizeof(struct agenda);//resultara en 20
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
2
Estructuras de datos
Regresando al ejemplo del arreglo que se declaro de
manera dinámica.
int *arreglo;
int longitud;
printf(“cuantos elementos quieres guardar?\n”):
scanf(“%d”, &longitud);
arreglo = (int *)malloc(longitud*sizeof(int));
Vemos que el número máximo de elementos en el
arreglo depende de la variable longitud. Hicimos un
cast al resultado de malloc y calculamos el tamaño
de un entero.
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
3F43
3F44
3F45
00001100
3F46
3F47
3F48
dirección
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
Si lo vemos desde el punto de vista del diseño de la
computadora tenemos que la memoria tiene dos
caracteristicas. Una es que toda localidad de
memoria tiene una dirección y dos que puede
guardar un valor y solo uno. En la siguiente lámina
se muestra esto de manera gráfica.
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
Estructuras de datos
La localidad con
dirección 3F43 contiene
el valor 12 en decimal.
Si despúes quisieramos
almacenar el 3 decimal
tedriamos que cambiar
los ultimos 4 bits y el
valor de 12 se perderá
para siempre.
Estructuras de datos
valor
Estructuras de datos
Cuando declaramos una
variable en algun
lenguaje de
programación no
hacemos mas que
ponerle una etiqueta a
una cierta dirección o
conjunto de direcciones.
3F43
3F44
3F45
00001100
a
3F46
3F47
3F48
dirección
valor
etiqueta
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
3
Estructuras de datos
Aquí declaramos que las
direcciones 3F43 y
3F44 estan etiquetadas
con la a. Es lo que
sucede con la siguiente
linea en C. int a = 12;
3F43
3F44
3F45
00001100
Estructuras de datos
a
3F46
3F47
3F48
dirección
valor
etiqueta
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
3F43
3F44
3F45
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
00001100
a
3F46
3F47
3F48
dirección
etiqueta
valor
00001100
Estructuras de datos
a
3F46
3F47
3F48
dirección
3F43
3F44
3F45
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
Estructuras de datos
Existen diferentes
técnicas para tener
acceso a los datos
almacenados en la
memoria. Uno de ellos
es el acceso directo
usando la etiqueta.
Así pues, podemos decir
que hablar de las
direcciones o de su
etiqueta es lo mismo.
Siempre es más fácil
recordar una etiqueta
que un numero
representando dicha
dirección.
valor
etiqueta
3F43
El otro es de manera
00001100
indirecta usando una
3F44
dirección de referencia y
3F45
un desplazamiento. Este
3F46
método se usa en los
3F47
arreglos. A la dirección
3F48
de referencia también se
dirección
valor
le conoce como
apuntador.
array[0]
array[1]
array[2]
etiqueta
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
4
Estructuras de datos
Ahora que conocemos las caracteristicas de la
memoria y los metodos para acceder a ella nos
concentraremos en el direccionamiento indirecto o
por medio de apuntadores.
Un apuntador es una variable que como dato
contendra una dirección y por tanto su tamaño
dependerá de la arquitectura de la computadora con
la que estemos trabajando. Es decir varia según el
tipo de computadora y no según el tipo de dato.
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
Estructuras de datos
Para declarar un apuntador la regla es, tipo de dato,
un asterisco y el nombre de la variable tipo
apuntador.
Ejemplos:
int *entero;//apuntador hacia numeros enteros
struct agenda *registro;//apuntador hacia una estructura agenda
POSICION *ptr;//apuntador hacia un tipo definido con typedef
Ahora podemos jugar con las dos caracteristicas de
una localidad de memoria.
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
Estructuras de datos
Para declarar un apuntador debemos pensar en el
tipo de dato hacia el que va a “apuntar”. Esto es
importante a la hora de querer acceder a los datos de
la dirección apuntada.
Esto porque el compilador marcará un conjunto de
direcciones a partir del dato apuntado, i.e., para un
flotante considerará 4 bytes consecutivos a partir de
la dirección guardada en el apuntador.
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
Estructuras de datos
Una variable normal como vimos representa una etiqueta de
una dirección de memoria y su uso nos da acceso al contenido
de dicha posición de memoria pero no sabemos nada respecto
a su dirección.
Del mismo modo de un apuntador sabemos la dirección pero
no podemos saber nada acerca del contenido de dicha
localidad de memoria.
Para resolver este pequeño inconveniente existen dos
operadores el * y el &. Conocidos tambien como operadores
de indirección y referenciación.
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
5
Estructuras de datos
Este ejemplo es similar
a tener es el resultado de
las siguientes lineas de
codigo.
int a, *ptr;
ptr = &a;
3F43
00001100
3F44
3F45
3F46
3F
3F47
43
3F48
dirección
valor
a
ptr
etiqueta
*ptr = 12;
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
Estructuras de datos
Otra cuestión interesante es el comportamiento de las
estructuras cuando las usamos con apuntadores o
variables normales.
Tomemos el siguiente ejemplo:
typedef struct{
char nombre[50];
int edad;
float estatura;
char sexo;
}ENCUESTA;
ENCUESTA
persona, *puntero;
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
Estructuras de datos
En este caso decimos que ptr apunta hacia la dirección de a.
Y tambien podemos decir que queremos que el contenido de
la dirección apuntada por ptr sea 12. De esta manera el
operador de indirección (*) aplicado a un apuntador nos
permite tener acceso al contenido de una localidad y el
operador de referenciación (&) aplicado a una variable nos
permite conocer su dirección.
En el ejemplo anterior guardamos la dirección de la variable a
en ptr. Despúes de manera indirecta guardamos en a el valor
de 12.
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
Estructuras de datos
Haciendo la siguiente sentencia puntero = &persona;
persona.nombre es equivalente a puntero->nombre.
Y resulta indistinto hacer las siguientes operaciones:
puntero->nombre = “Jose Luis”;
persona.edad = 19;
puntero->estatura = 1.72;
Y asi sucesivamente, todas las sentencias
modificarán el mismo bloque de memoria.
Ing.
Ing.Jorge
JorgeA.
A.Hernández
HernándezP.:
P.:Memoria
Memoriadinámica
dinámica
6
Descargar