Tema 6 Organización de la memoria Memoria estática Memoria dinámica Punteros Definición y declaración Tema 6: Memoria dinámica Programación 2 Dirección y contenido Declaración con inicialización Ejercicios Uso de punteros Reserva y liberación de memoria Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas Curso 2014-2015 Índice Tema 6 Organización de la memoria 1 2 Memoria estática Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización Ejercicios 3 Uso de punteros Reserva y liberación de memoria Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas 4 Organización de la memoria Memoria estática Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización Ejercicios Uso de punteros Reserva y liberación de memoria Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes Ejercicios Memoria estática Tema 6 Organización de la memoria Memoria estática Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización Ejercicios El tamaño es fijo y se conoce al implementar el programa Declaración de variables int i=0; char c; float vf[3]={1.0, 2.0, 3.0}; Uso de punteros i 0 c Punteros y vectores vf[0] 1.0 vf[1] 2.0 vf[2] 3.0 Punteros definidos con typedef 1000 1002 1004 1006 1008 Reserva y liberación de memoria Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas Memoria dinámica Tema 6 Organización de la memoria Memoria estática Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización Ejercicios Uso de punteros Reserva y liberación de memoria Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas Normalmente se utiliza para almacenar grandes volúmenes de datos, cuya cantidad exacta se desconoce al implementar el programa La cantidad de datos a almacenar se calcula durante la ejecución del programa y puede cambiar En C++ se puede hacer uso de la memoria dinámica usando punteros Definición y declaración Tema 6 Organización de la memoria Memoria estática Un puntero es un número (entero largo) que se corresponde con una dirección de memoria Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización Ejercicios Uso de punteros Reserva y liberación de memoria Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas En la declaración de un puntero, se debe especificar el tipo de dato que contiene la dirección de memoria Se declaran usando el carácter * Ejemplos: int *punteroAEntero; char *punteroAChar; int *VectorPunterosAEntero[tVECTOR]; double **punteroAPunteroAReal; Dirección y contenido Tema 6 Organización de la memoria Memoria estática *x &x Contenido de la dirección apuntada por x Dirección de memoria de la variable x Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización Ejercicios Uso de punteros Ejemplo: int i=3; int *pi; pi=&i; // pi=direccion de memoria de i *pi = 11; // contenido de pi=11. Por lo tanto, i = 11 Reserva y liberación de memoria Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas i 11 pi 1000 1000 1002 1004 1006 1008 Declaración con inicialización Tema 6 Organización de la memoria Declaración con inicialización: Memoria estática Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización int *pi=&i; // pi contiene la direccion de i El puntero NULL es aquel que no apunta a ninguna variable Ejercicios Uso de punteros Reserva y liberación de memoria Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas int *pi=NULL; Precaución: siempre que un puntero no tenga memoria asignada debe valer NULL. Ejercicios Tema 6 Organización de la memoria Ejercicio 1 Indica cuál sería la salida de los siguientes fragmentos de código: Memoria estática Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización Ejercicios Uso de punteros int e1; int *p1, *p2; e1 = 7; p1 = &e1; p2 = p1; e1++; (*p2) += e1; cout << *p1; Reserva y liberación de memoria Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas int a=7; int *p=&a; int **pp=&p; cout << **pp; Reserva y liberación de memoria (1/2) Tema 6 Organización de la memoria Memoria estática Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización Ejercicios Los punteros pueden usarse para reservar (con new) o liberar (con delete) memoria dinámica Ejemplo: double *pd; pd = new double; *pd = 4.75; cout << *pd << endl; delete pd; // reserva memoria // muestra 4.75 // libera memoria Uso de punteros Punteros y vectores pd 2000 Punteros definidos con typedef 1000 Reserva y liberación de memoria 4.75 1002 ... 2000 2002 Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas Ojo: Las variables locales y las reservadas con new van a zonas de memoria distintas. Reserva y liberación de memoria (2/2) Tema 6 Organización de la memoria Memoria estática Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización Ejercicios Uso de punteros Reserva y liberación de memoria Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas Cuando se usa new, el compilador reserva memoria y devuelve la dirección de inicio de ese espacio reservado Si no hay suficiente memoria para la reserva, new devuelve NULL Siempre que se reserva memoria con new hay que liberarla con delete Ojo: Tras hacer delete, el puntero no vale NULL por defecto Un puntero se puede reutilizar; tras liberar su contenido se puede reservar memoria otra vez con new Punteros y vectores (1/2) Tema 6 Organización de la memoria Memoria estática Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización Ejercicios Uso de punteros Reserva y liberación de memoria Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas Los punteros también pueden usarse para crear vectores o matrices Para reservar memoria hay que usar corchetes y especificar el tamaño Para liberar toda la memoria reservada es necesario usar corchetes Ejemplo: int *pv; int n=10; pv=new int[n]; // reserva memoria para n enteros pv[0]=585; // usamos el puntero como si fuera un vector delete [] pv; // liberar la memoria reservada Punteros y vectores (2/2) Tema 6 Organización de la memoria Memoria estática Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización Ejercicios Uso de punteros Reserva y liberación de memoria Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas Los punteros se pueden usar como accesos directos a componentes de vectores o matrices Ejemplo: int v[tVECTOR]; int *pv; pv = &(v[7]); *pv = 117; // v[7] = 117; Punteros definidos con typedef Tema 6 Organización de la memoria Memoria estática Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización Se pueden definir nuevos tipos de datos con typedef: typedef int entero; // entero es un tipo, como int entero a,b; // int a,b; Para facilitar la claridad en el código, suelen definirse los punteros con typedef: Ejercicios Uso de punteros Reserva y liberación de memoria Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas typedef int *punteroAEntero; typedef struct { char c; int i; } Registro, *PunteroRegistro; Punteros y registros Tema 6 Organización de la memoria Memoria estática Memoria dinámica Cuando un puntero referencia a un registro, se puede usar el operador -> para acceder a sus campos Punteros Definición y declaración Dirección y contenido Declaración con inicialización Ejercicios Uso de punteros Reserva y liberación de memoria Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas typedef struct { char c; int i; } Registro, *PunteroRegistro; PunteroRegistro pr; pr = new Registro; pr->c = ’a’; // (*pr).c = ’a’; Parámetros de funciones (1/2) Tema 6 Paso de parámetros a funciones Organización de la memoria Memoria estática Memoria dinámica Punteros void f (int *p) { *p=2; } // Por valor Definición y declaración Dirección y contenido Declaración con inicialización Ejercicios Uso de punteros Reserva y liberación de memoria Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas void f2 (int *&p) { // Por referencia int num=10; p=&num; } int main() { int i=0; int *p=&i; f(p); // Llamada a funciones f2(p); } Parámetros de funciones (2/2) Tema 6 Paso de parámetros a funciones usando typedef Organización de la memoria typedef int* PInt; Memoria estática Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización Ejercicios Uso de punteros Reserva y liberación de memoria Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas void f (PInt p){ *p=2; } // Por valor void f2 (PInt &p) { // Por referencia int num=10; p=&num; } int main() { int i=0; PInt p=&i; f(p); // Llamada a funciones f2(p); } Errores comunes Tema 6 Organización de la memoria Memoria estática Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización Ejercicios Uso de punteros Reserva y liberación de memoria Utilizar un puntero sin haberle asignado memoria o apuntando a nada int *pEntero; *pEntero = 7; // Error !!! Usar un puntero tras haberlo liberado punteroREGISTRO p,q; p = new REGISTRO; ... q = p; delete p; q->num =7; // Error !!! Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas Liberar memoria no reservada int *p=&i; delete p; Ejercicios Tema 6 Organización de la memoria Memoria estática Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización Ejercicio 2 Dado el siguiente registro: typedef struct { char nombre[32]; int edad; } Cliente; Ejercicios Uso de punteros Reserva y liberación de memoria Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas Realizar un programa que lea un cliente (sólo uno) de un fichero binario, lo almacene en memoria dinámica usando un puntero, imprima su contenido y finalmente libere la memoria reservada. Listas: Definición Tema 6 Organización de la memoria Memoria estática Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización Ejercicios Uso de punteros Reserva y liberación de memoria Se utilizan para almacenar un número variable de objetos Cada objeto se almacena en un nodo, que se enlaza con el siguiente La lista es un puntero al primer nodo, o NULL si está vacía Un nodo es un contenedor para almacenar información, y tiene dos partes: El objeto que se desea guardar Uno o más punteros para enlazar el nodo con otros nodos y construir la estructura de datos. Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas Objeto Listas: Implementación en C++ Tema 6 Organización de la memoria Memoria estática Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización Ejercicios Uso de punteros Reserva y liberación de memoria Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas typedef struct { char c; // informacion de cada objeto ... } Objeto; typedef struct tNodo { Objeto obj; // el objeto o dato a almacenar struct tNodo *pSig; // enlace con el siguiente } Nodo, *pNodo, *Lista; // Lista = pNodo = Nodo * = tNodo * // declaracion de la lista (dentro de una funcion) Lista li = NULL; Operaciones básicas con listas (1/5) Tema 6 Ver si la lista está vacía Organización de la memoria bool esVacia(Lista li) { return (li == NULL); } Memoria estática Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización Ejercicios Crear un nuevo nodo que contiene un objeto: pNodo crearNodo(const Objeto &o) { pNodo n = new Nodo; Uso de punteros if (n != NULL) { n->obj = o; n->pSig = NULL; } else cout << "Error de memoria" << end; Reserva y liberación de memoria Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes return n; Ejercicios Listas } Operaciones básicas con listas (2/5) Tema 6 Insertar un nodo al final: A Organización de la memoria C G L Memoria estática li Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización Ejercicios Uso de punteros void insertarAlFinal(Lista &li, const Objeto &o) { if (esVacia(li)) li = crearNodo(o); else { pNodo e = li; Reserva y liberación de memoria while (e->pSig != NULL) e = e->pSig; Punteros y vectores Punteros definidos con typedef Punteros y registros e->pSig = crearNodo(o); Parámetros de funciones } Errores comunes Ejercicios Listas } P Operaciones básicas con listas (3/5) Tema 6 Insertar un nodo al principio: Organización de la memoria A Memoria estática C G L P Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización Ejercicios Uso de punteros Reserva y liberación de memoria Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas li void insertarAlPrincipio(Lista &li, const Objeto &o) { if (esVacia(li)) li = crearNodo(o); else { pNodo p = crearNodo(o); p->pSig = li; li = p; } } Operaciones básicas con listas (4/5) Tema 6 Mostrar el contenido de la lista: Organización de la memoria A Memoria estática C G L Memoria dinámica Punteros Definición y declaración Dirección y contenido Declaración con inicialización Ejercicios Uso de punteros Reserva y liberación de memoria Punteros y vectores Punteros definidos con typedef li void mostrar(Lista li) { pNodo e = li; while (e != NULL) { cout << e->obj << endl; // Usar funcion si es necesar e = e -> pSig; } } Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas // Imprime: A C G L Operaciones básicas con listas (5/5) Tema 6 Organización de la memoria Memoria estática Memoria dinámica Punteros Borrar una lista: void borrarLista(Lista &li) { pNodo e = NULL; Definición y declaración while (!esVacia(li)) { e = li; li = li -> pSig; delete e; } Dirección y contenido Declaración con inicialización Ejercicios Uso de punteros Reserva y liberación de memoria } Punteros y vectores Punteros definidos con typedef Punteros y registros Parámetros de funciones Errores comunes Ejercicios Listas Las listas siempre deben borrarse cuando se hayan terminado de usar