domingo, 10 de febrero de 2013

MANEJO DE MEMORIA Y PALABRAS RESERVADAS


1.   EL MANEJO DE MEMORIA EN EL LENGUAJE C

Todos los objetos tienen un tiempo de vida, es decir, el tiempo durante el cual se garantiza que el objeto exista. Las variables globales y las variables locales declaradas con el especificador static tienen duración estática. Se crean antes de que el programa inicie su ejecución y se destruyen cuando el programa termina. Las variables locales no static tienen duración automática. Se crean al entrar al bloque en el que fueron declaradas y se destruyen al salir de ese bloque. Duración asignada se refiere a los objetos cuya memoria se reserva de forma dinámica. Como se explicó anteriormente, esta memoria se crea y se debe liberar de forma explícita. Los arreglos de longitud variable de C99 son un caso especial. Tienen duración automática, con la particularidad de que son creados a partir de su declaración.
La biblioteca estándar de C proporciona las funciones malloc, calloc, realloc y free para el manejo de memoria dinámica. Estas funciones están definidas en el archivo de cabecera stdlib.h.
Los datos se almacenan en uno de los tres segmentos de memoria que el programador dispone. La zona estática para datos, que permite almacenar variables globales durante la ejecución de un programa.
El stack que permite almacenar los argumentos y variables locales durante la ejecución de las funciones.
El heap que permite almacenar variables adquiridas dinámicamente durante la ejecución de un programa.
1.1  MANEJO ESTÁTICO DE LA MEMORIA.
La zona estática para datos, permite almacenar variables globales y estáticas.
Si se encuentra una variable definida fuera de las funciones, se la considera global; el compilador le asigna un espacio determinado y genera la referencia para accesarla en la zona estática. El tamaño de las variables no puede cambiarse durante la ejecución del programa, es asignado en forma estática.
El tiempo de vida de las variables de la zona estática es la duración del programa.
Estas variables son visibles para todas las funciones que estén definidas después de ellas.
Si se precede con la palabra static a una variable local a una función, ésta también es ubicada en la zona estática, y existe durante la ejecución del programa; no desaparece al terminar la ejecución de la función, y conserva su valor, entre llamados a la función.
1.1.1 MEMORIA ESTÁTICA
Es el espacio en memoria que se crea al declarar variables de cualquier tipo de dato (primitivas [int,char...] o derivados [struct,matrices,punteros...]). Este tipo de memoria no puede cambiarse una vez es declarada, y tampoco liberarse cuando ya no es necesaria, consumiendo de esta forma recursos innecesariamente.
1.2  MANEJO DINÁMICO DE LA MEMORIA EN C
El compilador asigna un espacio determinado para las variables y genera las referencias para accesar a las variables del stack y de la zona estática. El tamaño de las variables no puede cambiarse durante la ejecución del programa, es asignado en forma estática.
El tiempo de vida de las variables de la zona estática es la duración del programa; las variables denominadas automáticas, o en la zona del stack, existen durante la ejecución de la función que las referencia. Los frames en el stack, son asignados y desasignados en forma dinámica durante la ejecución de las funciones; pero en forma automática, el programador no tiene responsabilidad en ese proceso.
En el heap el programador debe solicitar la asignación de espacio, establecer las referencias entre el espacio asignado y las variables en las otras zonas, liberar el espacio, desasignar las referencias. Cualquier equivocación lleva a errores, en tiempo de ejecución, difíciles de depurar.
Este mecanismo permite al programador tener un mayor control de la memoria, tanto en tamaño como en tiempo de vida, pero al mismo tiempo le da la responsabilidad de administrarla correctamente. Un arreglo en la zona estática debe ser definido con un tamaño determinado, el cual no puede cambiar durante la ejecución del programa, sin embargo en el heap se puede solicitar un arreglo del tamaño que se desee, siempre que no exceda el tamaño máximo asignado al heap.
Escribir programas que manejen el heap es notablemente más difícil, por esta razón lenguajes más modernos efectúan automáticamente la programación del heap, y no le permiten al programador realizar esta tarea.  Algunos errores de programas que manejan el heap, compilan correctamente, sin embargo al ejecutarlos se producen errores difíciles de depurar.
1.2.1 MEMORIA DINÁMICA
Es memoria que se reserva en tiempo de ejecución. Su principal ventaja frente a la estática, es que su tamaño puede variar durante la ejecución del programa.(En C, el programador es encargado de liberar esta memoria cuando no la utilice más). El uso de memoria dinámica es necesario cuando a priori no conocemos el número de datos/elementos a tratar; sin embargo es algo más lento, pues es en tiempo de ejecución cuando se determina la memoria a usar. En contrapartida la memoria estática es más rápida ya que está disponible desde que se inicio el programa.
1.2.1.1 DIFERENCIAS, VENTAJAS Y DESVENTAJAS
La memoria reservada de forma dinámica suele estar alojada en el heap o almacenamiento libre, y la memoria estática en el stack o pila (con excepción de los objetos de duración estática, que se verán más adelante, los cuales normalmente se colocan en una zona estática de datos). La pila generalmente es una zona muy limitada. El heap, en cambio, en principio podría estar limitado por la cantidad de memoria disponible durante la ejecución del programa y el máximo de memoria que el sistema operativo permita direccionar a un proceso. La pila puede crecer de forma dinámica, pero esto depende del sistema operativo. En 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 dinámica es que se puede ir incrementando durante la ejecución del programa. Esto permite, por ejemplo, trabajar con arreglos dinámicos. Aunque en C, a partir del estándar C99 se permite la creación de arreglos cuyo tamaño se determina en tiempo de ejecución, no todos los compiladores implementan este estándar. Además, se sigue teniendo la limitante de que su tamaño no puede cambiar una vez que se especifica, cosa que sí se puede lograr asignando memoria de forma dinámica.
Una desventaja de la memoria dinámica es que es más difícil de manejar. La memoria estática tiene una duración fija, que se reserva y libera de forma automática. En contraste, la memoria dinámica se reserva de forma explícita y continúa existiendo hasta que sea liberada, generalmente por parte del programador.
La memoria dinámica puede afectar el rendimiento. Puesto que con la memoria estática el tamaño de las variables se conoce en tiempo de compilación, esta información está incluida en el código objeto generado, por lo cual el proceso es muy eficiente. Cuando se reserva memoria de manera dinámica, se tienen que llevar a cabo varias tareas, como buscar un bloque de memoria libre y almacenar la posición y tamaño de la memoria asignada, de manera que pueda ser liberada más adelante. Todo esto representa una carga adicional, aunque esto depende de la implementación y hay técnicas para reducir su impacto.
1.2.1.2  RESERVA DE MEMORIA
.La función g_malloc posibilita la reserva de una zona de memoria, con un número de bytes que le pasemos como parámetro. Además, también existe una función similar llamada g_malloc0 que, no sólo reserva una zona de memoria, sino que, además, llena esa zona de memoria con ceros, lo cual nos puede beneficiar si se necesita un zona de memoria totalmente limpia.gpointer g_malloc (gulong numero_de_bytes );gpointer g_malloc0 (gulong numero_de_bytes );Existe otro conjunto de funciones que nos permiten reservar memoria de una forma parecida a cómo se hace en los lenguajes orientados a objetos.
1.2.1.3  LIBERACIÓN DE MEMORIA.
 Cuando se hace una reserva de memoria con g_malloc y, en un momento dado, el uso de esa memoria no tiene sentido, es el momento de liberar esa memoria. Y el sustituto de free es g_freeque, básicamente, funciona igual que la anteriormente mencionada. Void g_free (gpointer memoria_reservada);
1.2.1.4  REALOJAMIENTO DE MEMORIA
 En determinadas ocasiones, sobre todo cuando se utilizan estructuras de datos dinámicas, es necesario ajustar el tamaño de una zona de memoria (ya sea para hacerla más grande o más pequeña). Para eso, GLib ofrece la función g_realloc, que recibe un puntero a memoria que apunta a una región que es la que será acomodada al nuevo tamaño y devuelve el puntero a la nueva zona de memoria. El anterior puntero es liberado y no se debería utilizar más: gpointer g_realloc (gpointer memoria_reservada, gulong numero_de_bytes).

1.2.2  FUNCIONES
1.2.2.1 MALLOC
La función malloc reserva un bloque de memoria y devuelve un puntero void al inicio de la misma. Tiene la siguiente definición:
void *malloc(size_t size);
donde el parámetro size especifica el número de bytes a reservar. En caso de que no se pueda realizar la asignación, devuelve el valor nulo (definido en la macro NULL), lo que permite saber si hubo errores en la asignación de memoria.
Ej.:
int*puntero;

char*puntcarc;

puntero=(int*)malloc(4);

puntcarc=(char*)malloc(200);
A continuación se muestra un ejemplo de su uso:
int*i;
/* Reservamos la memoria suficiente para almacenar un int y asignamos su dirección a i */

i =malloc(sizeof(int));

/* Verificamos que la asignación se haya realizado correctamente */
if(i  == NULL){
/* Error al intentar reservar memoria */
}
Uno de los usos más comunes de la memoria dinámica es la creación de vectores cuyo número de elementos se define en tiempo de ejecución:
int*vect1, n;
printf("N£mero de elementos del vector: ");
scanf("%d",&n);

/* Reservar memoria para almacenar n enteros */
vect1 =malloc(n *sizeof(int));

/* Verificamos que la asignación se haya realizado correctamente */
if(vect1  == NULL){
/* Error al intentar reservar memoria */
}
1.2.2.2  CALLOC
La función calloc funciona de modo similar a malloc, pero además de reservar memoria, inicializa a 0 la memoria reservada. Se usa comúnmente para arreglos y matrices. Está definida de esta forma:
void *calloc(size_t nmemb, size_t size);
El parámetro nmemb indica el número de elementos a reservar, y size el tamaño de cada elemento. El ejemplo anterior se podría reescribir con calloc de esta forma:
int*vect1, n;
printf("N£mero de elementos del vector: ");
scanf("%d",&n);

/* Reservar memoria para almacenar n enteros */
vect1 =calloc(n,sizeof(int));

/* Verificamos que la asignación se haya realizado correctamente */
if(vect1  == NULL){
/* Error al intentar reservar memoria */
}
1.2.2.3  REALLOC
La función realloc redimensiona el espacio asignado de forma dinámica anteriormente a un puntero. Tiene la siguiente definición:
void *realloc(void *ptr, size_t size);
Donde ptr es el puntero a redimensionar, y size el nuevo tamaño, en bytes, que tendrá. Si el puntero que se le pasa tiene el valor nulo, esta función actúa como malloc. Si la reasignación no se pudo hacer con éxito, devuelve un puntero nulo, dejando intacto el puntero que se pasa por parámetro. Al usar realloc, se debería usar un puntero temporal. De lo contrario, podríamos tener una fuga de memoria, si es que ocurriera un error en realloc.
Ejemplo de realloc usando puntero temporal:
/* Reservamos 5 bytes */
void*ptr=malloc(5);
/* Redimensionamos el puntero (a 10 bytes) y lo asignamos a un puntero temporal */
void*tmp_ptr =realloc(ptr,10);

if(tmp_ptr== NULL){
/* Error: tomar medidas necesarias */
}
else{
/* Reasignación exitosa. Asignar memoria a ptr */
ptr=tmp_ptr;
}
Cuando se redimension la memoria con realloc, si el nuevo tamaño (parámetro size) es mayor que el anterior, se conservan todos los valores originales, quedando los bytes restantes sin inicializar. Si el nuevo tamaño es menor, se conservan los valores de los primeros size bytes. Los restantes también se dejan intactos, pero no son parte del bloque regresado por la función.
1.2.2.4  FREE
La función free sirve para liberar memoria que se asignó dinámicamente. Si el puntero es nulo, free no hace nada. Tiene la siguiente definición:
void free(void *ptr);
El parámetro 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:
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); 

2.   PALABRAS RESERVADAS

Las palabras reservadas son identificadores predefinidos (tienen un significado especial). En todos los lenguajes de programación existe un conjunto de palabras reservadas.
El lenguaje de programación C se reserva el uso de algunas palabras como identificadores internos clave para sus tipos de datos, estructuras de control,sus instrucciones y otras funciones y características propias del lenguaje. Por esta razón no es posible usarlos como identificadores de variables, de funciones o de cualquier otro objeto. Los editores de texto modernos las resaltan automáticamente para hacer los programas más legibles. A continuación una lista de dichas palabras.

auto - break - case - char - const - continue - default - do - double - else - enum - extern - float - for - goto - if - int - long - register - return - short - signed - sizeof - static - struct - typedef - union - unsigned - void - volatile – while.

No hay comentarios:

Publicar un comentario