Memoria Dinamica
Memoria Dinamica
Memoria Dinamica
Memoria Dinámica
Énfasis en el Quien
Programación Orientadas a Objetos
C++, Smalltalk, Java
Énfasis en el Qué
Lenguajes Declarativos
Programación Funcional
LISP, Scheme, Haskell
Programación Lógica
Prolog
Lenguaje C
Fue desarrollado originalmente por Dennis Ritchie y aparece
en el año 1972.
• Proposito general.
• Nivel Intermedio.
• No es fuertemente tipado.
• Alcance estático.
• Maneja una etapa de preprocesamiento para definición de macros e
inclusión de archivos.
• Soporta llamadas recursivas.
• Permite el uso de apuntadores.
• No soporta declaración anidada de funciones.
Lenguaje C
.h .h .h .h
Preprocesamiento
.c .c
Compilación
.o .o
Enlace
Ejecutable
Lenguaje C
Estructura de un programa
Inclusion de Bibliotecas
Declaraciones globales
tipo función(parámetros){
declaraciones
secuencia de instrucciones
int main(){
secuencia de instrucciones
}
Lenguaje C
Ejemplo
Variables y tiempo de vida
Una variable es un elemento cuyo valor puede cambiar durante la ejecución. Esta
consta básicamente de una dirección de memoria y un espacio asignado a esta.
• Un espacio en memoria puede ser reservado incluso sin una declaración formal de
variable.
Dirección
Valor
Variables y tiempo de vida
char caracter
int entero
float real
Todos los demás tipos se basan en los anteriores. De igual forma se pueden emplear
los siguientes modificadores:
short corto
long largo
Calificadores de acceso
const
volatile
extern
Específica (declara) que un objeto esta declarado con enlace externo en otro
módulo (archivo) del programa, es decir esta definido en otro archivo.
static
register
Uniones: Una misma parte de la memoria es definida como dos o más tipos.
union numero{
int entero;
float real;
}
Campo Bits: tipo especial de estructura que permite el fácil acceso a bits
individuales.
struct estado{
unsigned: 4; (Campos sin nombre usados para padding)
unsigned cts:1;
unsigned drs:1;
}
Enumeraciones y Arreglos
Tipo identificado[tamaño];
double balance[100];
balance[0] = 123.5;
Arreglos multidimensionales
tipo *nombre;
Apuntadores
Los operadores empleados al momento de usar punteros suelen ser “*” para
acceder al contenido de una dirección de memoria y “&” para obtener la dirección
de un espacio de memoria.
p i
int i, *p; 10
i=10;
p=&i;
p i
*p = 5;
5
Aritmética de Apuntadores
Así como los apuntadores pueden apuntar a variables, puede darse el caso en
que un apuntador apunte a otro. Esta situación se denomina apuntador de
apuntador o indirección múltiple. Esta situación puede llevarse a la extensión
que se desee, pero son pocos los casos que lo requieran más allá de un
apuntador a un apuntador. /*
* UCAB Guayana
* Introduccion al Lenguaje C
*/
int i, *p, **q;
#include <stdio.h>
i=5; int main(int argc,char **argv){
int i=5,j=10,*p=&i,**pp=&p;
p=&i;
printf("valor de *p:%d\n", *p);
q=&p; printf("valor de **pp:%d\n", **pp);
p=&j; /* No se cambia pp pero ... */
printf("valor de **pp:%d\n", **pp);
q p i return 0;
5 }
/* --- Fin del programa --- */
Aritmética de Apuntadores
Operaciones Permitidas
• Incrementar o Decrementar cierta cantidad entera.
p
10 15 2 7 23 9
p = p+4
p++;
p-=2;
• Comparaciones.
i p q
i=p<q 1 10 15 2 7 23 9
Por ejemplo
"HOLA MUNDO"
H O L A M U N D O \0
Veamos:
msg_a:
H O L A M U N D O \0
msg_p:
H O L A M U N D O \0
Arreglos y Apuntadores
Los apuntadores y los arreglos en C están relacionados íntimamente y puede ser utilizado
casi en forma indistinta. Un nombre de arreglo puede considerarse como un apuntador, los
apuntadores puede utilizarse para realizar cualquier operación que involucre arreglos.
Por ejemplo si se declara un arreglo de enteros int ia[5]; y un apuntador a entero int *iap;
Dado que el nombre del arreglo sin elemento es un apuntador al primer elemento se
puede hacer al apuntador igual a la dirección del primer elemento con iap=ia; (o más
extraño iap=&ia[0];) alternativamente el elemento ia[3] puede ser referenciado como
*(ia+3)
/*
* UCAB Guayana
* Introduccion al Lenguaje C
*/
#include <stdio.h>
int main(int argc,char *argv[]){
int *iap, ia[5]={0,1,2,3,4};
iap=ia;
printf("ia[3]:%d\n",ia[3]);
printf("*(iap+3):%d\n",*(iap+3));
printf("*(3+iap):%d\n",*(3+ia));
printf("3[ia]:%d\n",3[ia]);
return 0;
}
/* --- Fin ejemplo --- */
Apuntadores
char *s
const char *s
int * const ip
Estos son empleados cuando deseamos manejar apuntadores cuyos tipo de dato
base son desconocidos o bien no tienen importancia para la acción que se desea
llevar a cabo.
Existen 2 primitivas básicas que facilitan el manejo de memoria dinámica. Estas están
definidas en la biblioteca estándar <stdlib.h> y se conocen como malloc y free.
Un Alias ocurre cuando el mismo elemento, por ejemplo una variable, está vinculado a
dos nombres diferentes al mismo tiempo. Esto puede ocurrir entre otras causas al hacer
uso de apuntadores.
El problema que presentan el alias son los efectos colaterales que producen, se define
como un efecto colateral de una instrucción como cualquier cambio en el valor de una
variable que persiste más allá de la ejecución de la instrucción, dichos efectos pueden ser
altamente dañinos y el uso de alias presenta dificultades para controlarlos.
*ap = 10;
printf("a: %d\n",a);
Referencias Pendientes
Una referencia pendiente es una localización que ha sido desasignada del entorno, pero a
la que el programa puede tener acceso todavía, es decir una localización puede ser
accedida más allá de su tiempo de vida.
En este caso la función ha retornado la dirección de buffer, pero el arreglo buffer tiene un
tiempo de vida igual a la ejecución de la función, es decir cuando se utilice la dirección
retornada por i2a luego de la llamada el espacio de buffer ya estará desasignado.
Referencias Pendientes
#include <stdio.h>
#include <stdlib.h>
xp = (int *) malloc(sizeof(int));
*xp = 5;
free(xp);
printf("*xp: %d\n",*xp);
return 0;
}
/* --- Fin ejemplo --- */
Basura
EJEMPLO 1
int *x;
x = (int *)malloc(sizeof(int));
x = NULL;
EJEMPLO 2
void p(void){
int *x;
x = (int *)malloc(sizeof(int));
*x = 2;
}
Paso por Referencia
El paso por referencia en lenguaje C se hace mediante el uso de apuntadores, de tal forma
que al pasar una referencia el método receptor puede alterar el valor de la variable cuyo
ámbito no es el mismo de la función.
*x=*y;
*y=t;
}
Paso de Estructuras
En el caso de las estructuras, estas pueden pasarse por valor (donde no se puede
modificar el contenido de la misma fuera de la función) o bien por referencia (donde se
pasa la dirección de memoria de la misma).
int main(){
restp = (char*)malloc(n+1);
for(i=0;i<n;i++) Abecedario: ABCDEFGHIJ
restp[i]='A'+i;
restp[i]='\0';
return restp;
}
Listas Simplemente Enlazadas
…
Listas Simplemente Enlazadas
Esta declaración recursiva de node podría parecer riesgosa, pero es correcta. Es ilegal
que una estructura contenga una instancia de si misma , pero
struct node *next;
p Nuevo
…
Listas Simplemente Enlazadas
p Nuevo
prev
…
Listas Simplemente Enlazadas
p Nuevo
…
Listas Simplemente Enlazadas
…
Listas Simplemente Enlazadas
prev
…
Listas Simplemente Enlazadas
prev
…
Implementación
gestionlistas.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node { char name[20]; int value; struct node *next;} Node;
gestionlistas.c
newp name value next
/*
* New_item: Crea un nuevo elemento a partir del nombre y un valor
*/
if((newp=(Node *)malloc(sizeof(Node)))==NULL){
fprintf(stderr,"new_item: error en malloc\n");
exit(1);
}
strcpy(newp->name,name);
newp->value = value;
newp->next=NULL;
return newp;
}
Implementación
gestionlistas.c
/*
* add_front: añade newp al frente de listp
* y retorna la nueva lista
*/
newp Node
listp
…
Implementación
/*
gestionlistas.c
* add_end añade newp al final de la listp
* y retorna la nueva lista
*/
if(listp==NULL)
return newp;
for(p=listp;p->next!=NULL;p=p->next);
p->next = newp;
return listp;
}
newp Node
listp
…
Implementación
gestionlistas.c
/*
* insert: inserta newp ordenado en listp y retorna la nueva lista
*/
Node *insert(Node *listp, Node *newp){
Node *p,*prev=NULL;
/* gestionlistas.c
* lookup: busca un nombre en listp
*/
Node *lookup(Node *listp, char *name){
for(;listp!=NULL;listp=listp->next)
if(strcmp(name,listp->name)==0)
return listp;
return NULL; /* No se encontro */
}
/*
* in_counter: cuenta los elementos en listp
*/
int in_counter(Node *listp){
int n=0;
gestionlistas.c
/*
* free_all: libera todos los elementos de listp
*/
Node *free_all(Node *listp){
Node *next;
gestionlistas.c
/*
* del_item: elimina la primera ocurrencia de name
*/
Node *del_item(Node *listp, char *name){
Node *p, *prev = NULL;
for(p=listp;p!=NULL;p=p->next){
if(strcmp(p->name,name)==0){
if(prev==NULL)
listp=p->next;
else
prev->next=p->next;
free(p);
return listp;
}
prev=p;
}
return listp; /* name no esta en la lista */
}
Implementación
gestionlistas.c
/*
* print: muestra los elementos en listp
*/
void print(Node *listp){
printf("-->");
for(;listp!=NULL;listp=listp->next)
printf("%s:%d-->",listp->name,listp->value);
printf("NULL\n");
}
/*
* is_empty: retorna 1 si esta vacia 0 en caso
contrario
*/
int is_empty(Node *listp){
return listp == NULL;
}
Ejemplo de Uso
#include "gestionalistas.h"
int main(){
return 0;
Salida
-->Daniela Perez:23-->Jose Saad:7-->Miguel Alvarez:12-->Mireya Orta:17-->NULL
-->Daniela Perez:23-->Miguel Alvarez:12-->Mireya Orta:17-->NULL
Ejercicios
Dada una lista de elementos y las operaciones: primero, cola, insertar un elemento
por el frente e insertar un al final, vacio: Escriba los algoritmos en pseudo código,
para: