Sie sind auf Seite 1von 16

2013 Memoria Dinmica

Autor: Bianca Gonzlez Editorial: Punteros-C 04/02/2013


0

Pg. 2

Definicin de Memoria Dinmica Diferencias y Ventajas, Desventajas Puntero Variable Puntero Declaracin de Variable Puntero en lenguaje C Funciones de la memoria dinmica Sabas que? Horscopo General para el Programador
Pg. 5-8
Un puntero tiene Su propia direccin de Memoria: &punt &car

Pg. 2-3 2-3

Pg. 4

Pg. 4-5

Pg. 5

Pg. 9-12

Pg. 13-14

contrapartida la memoria esttica es ms rpida ya que est disponible desde que se inicio el programa. Se refiere a aquella memoria que no puede ser definida ya que no se conoce o no se tiene idea del nmero de la variable a considerarse, la solucin a este problema es la memoria dinmica que permite solicitar memoria en tiempo de ejecucin, por lo que cuanta ms memoria se necesite, ms se solicita al sistema operativo. El sistema operativo maneja la memoria gracias al uso de punteros, por la misma naturaleza del proceso nos impide conocer el tamao de la memoria necesaria en el momento descompilar. En lenguaje C la memoria dinmica puede ser definida como aquella memoria que se reserva en tiempo de ejecucin. Su principal ventaja frente a la esttica, es que su tamao puede variar durante la ejecucin del programa.(En C, el programador es encargado de liberar esta memoria cuando no la utilice ms). El uso de memoria dinmica es necesario cuando a priori no conocemos el nmero de datos/elementos a tratar; sin embargo es algo ms lento, pues es en tiempo de ejecucin cuando se determina la memoria a usar. En

Diferencias y Ventajas
La memoria reservada de forma dinmica suele estar alojada en el heap o almacenamiento libre, y la memoria esttica en el stack o pila (con excepcin de los objetos de duracin esttica, que se vern ms adelante, los cuales normalmente se colocan en una zona esttica de datos).

La pila generalmente es una zona muy limitada. El heap, en cambio, en principio podra estar limitado por la cantidad de memoria disponible durante la ejecucin del programa y el mximo de memoria que el sistema operativo permita direccionar a un proceso. La pila puede crecer de forma dinmica, pero esto depende del sistema operativo. En 2

cualquier caso, lo nico que se puede asumir es que muy probablemente dispondremos de menor espacio en la pila que en el heap. Otra ventaja de la memoria dinmica es que se puede ir incrementando durante la ejecucin del programa. Esto permite, por ejemplo, trabajar con arreglos dinmicos. Aunque en C, a partir del estndar C99 se permite la creacin de arreglos cuyo tamao se determina en tiempo de ejecucin, no todos los compiladores implementan este estndar. Adems, se sigue teniendo la limitante de que su tamao no puede cambiar una vez que se especifica, cosa que s se puede lograr asignando memoria de forma dinmica.

Una desventaja de la memoria dinmica es que es ms difcil de manejar. La memoria esttica tiene una duracin fija, que se reserva y libera de forma automtica. la y hasta En contraste, explcita existiendo liberada, memoria contina que sea por

dinmica se reserva de forma

generalmente

parte del programador. La memoria dinmica puede afectar el rendimiento. Puesto que con la memoria esttica el tamao de las variables se conoce en tiempo de compilacin, esta informacin est incluida en el cdigo objeto generado, por lo cual el proceso es muy eficiente. Cuando se reserva memoria de manera dinmica, se tienen que llevar a cabo varias un y que ms esto carga 3 tareas, almacenar tamao asignada, pueda adelante. representa de de ser como la buscar posicin la manera liberada Todo una

Desventajas

bloque de memoria libre y memoria

adicional,

aunque

esto

depende de la implementacin y hay tcnicas para reducir su impacto.

localizacin exacta de ese dato en memoria.

En lenguaje c
Los punteros en el Lenguaje C, son variables que " apuntan ", es decir que poseen la direccin de las ubicaciones en memoria de otras variables, y por medio de ellos tendremos un poderoso mtodo de acceso a todas ellas. Quizs este punto es el ms conflictivo del lenguaje, ya que muchos programadores en otros idiomas, y novatos en C, lo ven como un mtodo extrao al menos desacostumbrado, lo que produce un cierto rechazo. Sin embargo , y en la medida que uno se va familiarizando con ellos, se convierten en la herramienta ms cmoda y directa para el manejo de variables complejas, argumentos, parmetros, etc, y se empieza a preguntar cmo es que hizo para programar hasta aqu, sin ellos . La respuesta es que no lo ha hecho, ya que los hemos usado en forma encubierta, sin decir lo que eran.

Puntero
Un puntero es una variable que contiene la direccin de memoria donde se encuentra almacenado un dato. Tambin se podra decir que es un objeto que apunta a otro objeto. Es decir, una variable cuyo valor es la direccin de memoria de otra variable. No hay que confundir una direccin de memoria con el contenido de esa direccin de memoria.

La direccin de la variable x (&x) es 1502 El contenido de la variable x es 25 En C no debemos, ni podemos, indicar numricamente la direccin de memoria, si no que utilizamos una etiqueta que conocemos como variable (en su da definimos las variables como direcciones de memoria). Lo que nos interesa es almacenar un dato, y no la

Una variable Puntero


Es el dato cuya posicin en memoria est contenida en un determinado puntero (variable dinmica). 4

int *punt;

Una variable puntero se declara como todas las variables. Debe ser del mismo tipo que la variable apuntada. Su identificador va precedido de un asterisco (*):

programa en C:

Es una variable puntero que apunta a variable que contiene un dato de tipo entero llamada punt.

char *car:

Es un puntero a variable de tipo carcter. long float *num; float *mat[5]; // . . .

Hay que tener cuidado con las direcciones apuntadas:

Un puntero tiene Su propia direccin de Memoria: &punt &car

Es decir: hay tantos tipos de punteros como tipos de datos, aunque tambin pueden declararse punteros a estructuras ms complejas (funciones, struct, ficheros...) e incluso punteros vacos (void ) y punteros nulos (NULL). Declaracin de variables puntero: Sea un fragmento de

*(punt + 1) repesenta el valor contenida en la direccin de memoria aumentada en una posicin (int=2bytes), que ser un valor no deseado. Sin embargo var+1 representa el valor 15. punt + 1 representa lo mismo que &var + 1 (avance en la direccin de memoria de var).

Funciones de la Memoria Dinmica:


El tratamiento de memoria dinmica sigue tres pasos fundamentales: 5

1) Peticin de memoria (funcin malloc). 2) Utilizacin de dicha memoria para nuestro propsito. 3) Liberacin de memoria (funcin free).

Uno de los usos ms comunes de la memoria dinmica es la creacin de vectores cuyo nmero de elementos se define en tiempo de ejecucin: int *vect1, n; printf("Nmero de elementos del vector: "); scanf("%d", &n);

malloc
La funcin malloc reserva un bloque de memoria y devuelve un puntero void al inicio de la misma. Tiene la siguiente definicin: void *malloc(size_t size); Donde el parmetro size especifica el nmero de bytes a reservar. En caso de que no se pueda realizar la asignacin, devuelve el valor nulo (definido en la macro NULL), lo que permite saber si hubo errores en la asignacin de memoria. Ejemplo: int *puntero; char *puntcarc; puntero=(int *)malloc(4); puntcarc=(char *)malloc(200);

/* Reservar memoria para almacenar n enteros */

vect1 = malloc(n * sizeof(int));

/* Verificamos que la asignacin se haya realizado correctamente */


if (vect1 == NULL) {

/* Error al intentar reservar memoria */


}

calloc
La funcin calloc funciona de modo similar a malloc, pero adems de reservar memoria, inicializa a 0 la memoria reservada. Se usa comnmente para arreglos y matrices. Est definida de esta forma: void *calloc(size_t nmemb, size_t size); El parmetro nmemb indica el nmero de elementos a reservar, y size el tamao de cada elemento.

El ejemplo anterior se podra reescribir con calloc de esta forma: int *vect1, n; printf("Nmero de elementos del vector: "); scanf("%d", &n);

puntero temporal. De lo contrario, podramos tener una fuga de memoria, si es que ocurriera un error en realloc. Ejemplo de realloc usando puntero temporal:

/* Reservar memoria almacenar n enteros */

para

/* Reservamos 5 bytes */
void *ptr = malloc(5);

vect1 = calloc(n, sizeof(int));

/* Verificamos que la asignacin se haya realizado correctamente */


if (vect1 == NULL) {

/* Redimensionamos el puntero (a 10 bytes) y lo asignamos a un puntero temporal */


void *tmp_ptr = realloc(ptr, 10); if (tmp_ptr == NULL) {

/* Error al intentar reservar memoria */


}

realloc
La funcin realloc redimensiona el espacio asignado de forma dinmica anteriormente a un puntero. Tiene la siguiente definicin: void *realloc(void *ptr, size_t size); Donde ptr es el puntero a redimensionar, y size el nuevo tamao, en bytes, que tendr. Si el puntero que se le pasa tiene el valor nulo, esta funcin acta como malloc. Si la reasignacin no se pudo hacer con xito, devuelve un puntero nulo, dejando intacto el puntero que se pasa por parmetro. Al usar realloc, se debera usar un

/* Error: tomar medidas necesarias */


} else {

/* Reasignacin exitosa. Asignar memoria a ptr */


ptr = tmp_ptr; } Cuando se redimension la

memoria con realloc, si el nuevo tamao (parmetro size) es mayor que el anterior, se conservan todos los valores originales, quedando los bytes restantes sin inicializar. Si el nuevo tamao los es menor, de se los conservan valores

primeros size bytes. Los restantes tambin se dejan intactos, pero no 7

son parte del bloque regresado por la funcin.

Free

int *i = malloc(sizeof(int)); free(i);

/* Reutilizamos i, ahora para reservar memoria para dos enteros */


i = malloc(2 * sizeof(int));

/* Volvemos a liberar la memoria cuando ya no la necesitamos */


free(i);

La funcin free sirve para liberar memoria que se asign dinmicamente. Si el puntero es nulo, free no hace nada. Tiene la siguiente definicin: void free(void *ptr); El parmetro ptr es el puntero a la memoria que se desea liberar: int *i; i = malloc(sizeof(int)); free(i); Una vez liberada la memoria, si se quiere volver a utilizar el puntero, primero se debe reservar nueva memoria con malloc o calloc: 8

Nociones de referencias:

elementos

Es bastante fcil saber diferenciar una estructura dinmica de una estructura esttica. Una ejemplificacin de esto en C#: 1 2 // Forma de declarar una estructura esttica no expansiva object[] arreglo object[TAMANO]; = new

En las estructuras estticas todos los datos estn localizados en lugares adyacentes de memoria: Supongamos a continuacin la creacin de la siguiente estructura esttica: 1 object[] arreglo = new object[5]; 1 Object[] Object[5]; arreglo = new

3 4

// Forma de declarar una estructura esttica expansiva ArrayList estructuraEstatica new ArrayList(); // Forma de declarar estructura dinmica = =

En ese momento la memoria se podra representar de la siguiente forma:

una

LinkedList<object> 6 estructuraDinamica LinkedList<object>();

new

Cmo crear mi propia estructura dinmica? A continuacin recrearemos las nociones bsicas de estructuras dinmicas creando una clase que nos permita modelar esto y controlar el flujo de memoria de manera correcta.

Como se puede observar, todas las posiciones del arreglo estn en posiciones seguidas de memoria y ocupan el espacio concedido aun si no estn guardando algn dato. De 9

hecho hacen notar como el 0 (cero) tambin es un valor que ocupa memoria. A continuacin, construiremos una estructura dinmica que supla solucin a este de problema 4 de desperdicio de memoria. Porque tratndose espacios desperdiciados de bytes no sera ningn problema pero pensemos en millones de registros cargados en memoria con valores nulos. Sera realmente un desperdicio. Para comenzar a construirla necesitaremos desarrollar un elemento bsico. Se trata de un nodo o Linker. sta es una clase que crearemos para representar cada uno de los elementos de la estructura de datos y tendr la siguiente estructura:

como

tal

correspondiente el

la

posicin en la estructura de datos y finalmente tercer campo se destinar a guardar la referencia (o direccin de memoria) del nodo correspondiente nodo Siguiente. La idea es que como la estructura va a ser dinmica y todos los elementos van a estar dispersos y en lugares aleatorios de memoria, en el momento de agregarlos a la estructura pasndoles de como datos los vincularemos con los otros nodos parmetro referencias a los otros nodos (como una cadena que previene que se vayan a perder los unos de los otros). La idea final sera obtener una estructura de datos que modelara los datos en memoria de la siguiente forma: a su

Segn el grfico, podemos ver que un campo del nodo se destinar a guardar la referencia (direccin de memoria) de otro nodo que corresponde al nodo Anterior, mientras que el segundo campo se destinar a guardar el elemento 10

Tal y como podemos percibir en el anterior grfico, a diferencia de la estructura esttica, la estructura dinmica almacena sus elementos en la memoria de una manera arbitraria, por ende el manejo de memoria es mucho ms eficiente. Por otro lado las estructuras dinmicas son ms ineficientes en el consumo bsqueda de de procesador, una esto debido a que en el momento de una posicin determinada tendremos que recorrer todos los nodos anteriores para llegar al que estamos buscando. Por ejemplo, en la estructura del grfico, si nos pidiesen el nodo nmero 3. Tenemos que llegar al nodo 2 que es el nico que sabe la localizacin del nodo 3. Pero para llegar al nodo 2 tenemos que usar al nodo 1 que es el que sabe la localizacin del nodo 2. De tal manera que para llegar al nodo nmero 100 en una estructura con 100 o ms elementos, tendremos que pasar primero por 99 posiciones, lo que reduce en gran manera la velocidad de acceso a posiciones arbitrarias. El Cdigo 1. Primero escribiremos la firma de la clase Linker que modelar la clase

nodo que necesitamos para comenzar a construir la estructura dinmica. Basndonos en lo siguiente:

En C#: (Tener en cuenta que aqu los mtodos de accesibilidad se convierten en propiedades) 01 class Linker 02 { 03 04 05 06 07 08 09 10 11 12 13 14 public Linker Back 11 } public Linker(Linker back, object content, Linker next) { this.back = back; this.content = content; this.next = next; private Linker back; private object content; private Linker next;

15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 }

{ get { return back; } set { back = value; } } public object Content { get { return content; } set { content = value; } } public Linker Next { get { return next; } set { next = value; } }

5 6 7 8 9}

public DynamicStruct() { start = null; }

Forma de agregar elementos a la estructura: Suponiendo que queramos un mtodo que nos agregue un nuevo elemento (en un nuevo nodo) al final de la estructura, la manera sera la siguiente: En C#: public 01 agregarElemento(object elemento) 02 { 03 04 05 06 07 08 09 10 11 12 13 14 } } if (runner == null) start = new elemento, null); else { while (runner.Next != null) runner = runner.Next; Linker agregado = new Linker(runner, elemento, null); runner.Next = agregado; Linker(null, Linker runner = start; void

A continuacin procedemos a crear la clase principal que contendr en nodo de anclaje. El nodo de anclaje es aquel que nos va a permitir acceder a la cadena por uno de los extremos. Por lo general se adopta el nodo de inicio, desde donde comenzaremos a recorrer toda la cadena hasta obtener nuestro objetivo. En C#: 1 public class DynamicStruct 2{ 3 4 private Linker start;

12

Como se vio en las secciones anteriores, siempre que se reserve memoria de forma dinmica con malloc, realloc o calloc, se debe verificar que no haya habido errores (verificando que el puntero no sea NULL). Cuando se trata de verificar el valor de un puntero (y slo en ese caso), se puede usar de forma indistinta 0 NULL. Usar uno u otro es cuestin de estilo. Como ya se vio, las funciones de asignacin dinmica de memoria devuelven un puntero void. Las reglas de C establecen que un puntero void se puede convertir automticamente a un puntero de cualquier otro tipo, por lo que no es necesario hacer una conversin (cast), como en el siguiente ejemplo:

Aunque no hay un consenso, muchos programadores prefieren omitir la conversin anterior porque la consideran menos segura. Si accidentalmente se olvida incluir el archivo stdlib.h (donde estn definidas malloc, calloc, realloc y fr ee) en un programa que use dichas funciones, el comportamiento puede quedar indefinido. Si omitimos la conversin explcita, el compilador lanzar una advertencia. Si, en cambio, realizamos la conversin, el compilador generar el cdigo objeto de forma normal, ocultado el bug.

Una posible razn para usar la conversin explcita es si se escribe cdigo en C que se vaya a compilar junto con cdigo C++, ya que en C++ s es necesario conversin. realizar esa

/* El puntero void devuelto por malloc es convertido explcitamente a puntero int */


int *i = (int *)malloc(sizeof(int));

En cualquier caso, dado que el manejo de memoria es un tema complejo, y ste es un error muy comn, se debe hacer nfasis en que cuando se trabaja con memoria 13

dinmica, siempre se debe verificar que se incluya el archivo stdlib.h. Tratar de utilizar un puntero cuyo bloque de memoria ha sido liberado con free puede ser sumamente peligroso. El comportamiento del programa queda indefinido: puede terminar de forma inesperada, sobrescribir otros datos y provocar problemas de seguridad. Liberar un puntero que ya ha sido liberado tambin es fuente de errores. Para evitar estos problemas, se recomienda que despus de liberar un puntero siempre se establezca su valor a NULL. int *i; i = malloc(sizeof(int)); free(i); i = NULL; Consejos para el programador: A las chicas: Ten en cuenta los detalles a la hora de programar no se te olviden ni las comas. Usa objetos que te individualicen y que a la vez te hagan ver genial!

A los chicos: Asegrate hasta dos veces que el programa corra de la manera correcta, no te adelantes simplemente al hecho de que corri. No ocultes a las chicas tu parte Nerd en ocasiones te pueden ayudar al igual que:

Spencer Reid de Criminal Minds.

14

15

Das könnte Ihnen auch gefallen