21 Memoria Dinámica Y Su Uso En C - Eafranco

Transcription

Tema 21: Memoria dinámica y su uso en C1M. en C. Edgardo Adrián Franco dfrancomedgardoadrianfrancomEstructuras de datos (Prof. Edgardo A. Franco)

En muchas ocasiones no es posible conocer de antemano lacantidad de variables necesarias para un programacomputacional. Existen aplicaciones que requieren de enormes cantidades dearreglos o datos por momentos breves en el funcionamientodel mismo, por lo que no es viable declarar de antemano aestas como variables, globales o locales de una función. Loanterior implica emplear funciones de ANSI C que permitenreservar memoria de manera dinámica y ampliarla, reducirlao destruirla en tiempo de ejecución. El manejo de memoria dinámica es la base del poder dellenguaje C y le da la capacidad de crear programas complejosque emplean grandes cantidades de memoria y los maneja demanera eficiente.21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco MartínezIntroducción2

Las variables globales y del programa principal (main) sealmacenan en posiciones fijas de la memoria llamadamemoria de datos. Las variables locales se almacenan en el segmento dememoria llamada pila y existen solo cuando se hace unainvocación a la función que las declaro. También se puedendeclarar variables estáticas locales que también sealmacenan en segmentos fijos de memoria o en lamemoria de datos , sin embargo, también estándisponibles en la función que las declaro.21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco Martínez Todos los programas definen variables que pueden serdefinidas como globales y locales.3

Sin embargo, no todas las veces es posible conocer elnumero de variables con el que va a constar nuestroprograma. C ofrece al desarrollador la opción de creardiferentes tipos de variables de forma dinámica, para creartales variables se utilizan funciones como: malloc(),realloc(), calloc(), y free().21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco Martínez Todas estas variables comparten una característica encomún, se definen cuando se compila el programa. Estosignifica que el compilador reserva espacio en memoria paraalmacenar los valores para estas variables. Las regiones de memoria que reservan/liberan estasfunciones son almacenadas en el montículo o heap.4

(Main y código de funciones empleadas)DatosMemoria deproceso activo(Variables globales y declaradas dentro delmain)PilaPila(Stack)(Variables y datosde las funciones alestar en ejecución)21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco as delprograma)5

Por lo regular cuando se diseña un algoritmo, se debeconocer que elementos de entrada tendrá y cual será lasalida, sin embargo, en algunas ocasiones no se sabe deforma exacta el numero de variables que requeriránuestro algoritmo. Por ejemplo, suponga que se van a registrar el numerode calificaciones de un conjunto de alumnos, pararesolver este problema se podría utilizar una arreglo decalificaciones, sin embargo, si el numero de alumnoscrece, nuestro programa ya no seria valido, puesto queno existen los recursos necesarios para almacenar todoslos datos validos.Para resolver este problema es necesario recurrir al uso deapuntadores y a la asignación dinámica de memoria.21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco MartínezAsignación dinámica de memoria6

21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco Martínez El espacio de memoria asignado a una variablegenerada de manera dinámica se crea durante laejecución del programa (tiempo de ejecución), alcontrario de las variables declaradas en código, queel espacio de memoria se les asigna en tiempo decompilación. Una variable que es generada dinámicamente, seconstruye (por ejemplo con malloc) y se puededestruir en tiempo de ejecución (uso de free).7

21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco Martínez Recordatorio:Las instrucciones de un programa compilado sesitúan en segmentos de memoria denominadosegmento de código (memoria de programa). Losdatos del programa, tales como variables globales, sealmacenan en un área denominado segmento dedatos. Las variables locales y el respaldo de losregistros de control del programa se sitúan en elsegmento llamado pila. Y cuando un programasolicita memoria dinámica para una variable, se leasigna memoria del segmento denominadomontículo o heap.8

malloc() es la forma más habitual de obtenerbloques de memoria dinámica. La función genera oasigna un bloque de memoria que es el numero debytes pasados como argumento. malloc() devuelve un apuntador void* al bloque dememoria asignado, por lo tanto, hay que realizar uncast al tipo de apuntador requerido, para hacerbuen uso de la memoria o de los datos que selleguen a almacenar en dicho bloque de memoria.Nota: Todas las funciones de asignación dinámica dememoria se encuentran definidas en la bibliotecastdlib.h21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco MartínezFunción malloc()9

void* malloc( size t bytes); Donde: void*: es el apuntador que almacenará lareferencia o apuntara al bloque dememoria generado.bytes: es el tamaño en bytes del bloquede memoria que se va a solicitar.21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco Martínez El prototipo de la función malloc() sería:10

//otra forma de generar la memoria//dinámica seria:c (char *)malloc( sizeof(char) );entero (int *)malloc( sizeof(int) );flotante (float *)malloc( sizeof(float) );doble (double *)malloc( sizeof(double) );#include stdio.h #include stdlib.h int main( void ){char *c;int *entero;float *flotante;double *doble;//Uso de malloc para generar variables sencillasc (char *)malloc( 1 );entero (int *)malloc( 4 );flotante (float *)malloc( 4 );doble (double *)malloc( 8 );*c 'c';*entero 2378;*flotante 128.89172378;*doble 18947282.48263;printf( "valores: caracter %c, entero %d, flotante%f, doble %lf",*c, *entero, *flotante, *doble );free( c );free( entero );free( flotante );free( doble );return 0;}21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco Martínez Por ejemplo:*c 'a';*entero 10;*flotante 3.89172378;*doble 1.48263;printf( "valores: caracter %c, entero %d, flotante %f, doble %lf \n\n",*c, *entero, *flotante, *doble );//Importantísimo liberar la memoria//cuando ya no es requeridafree( c );free( entero );free( flotante );free( doble );11

int *ptr;ptr (int *)malloc( 10 * sizeof(int) ); Al llamar a malloc() puede ser que no haya suficientememoria disponible, entonces, malloc() devolverá NULL enla operación, por lo tanto, siempre es conveniente preguntardespués de la operación si se asigno el bloque de memoria.int *ptr;ptr (int *)malloc( 10 * sizeof(int) );if( ptr NULL){printf( "No hay memoria disponible \n" ); //no utilizar ptrreturn; //fin del programa o realizar la acción conveniente}//utilizar ptr21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco Martínez La función sizeof se utiliza con mucha frecuencia parareferirnos al tamaño de memoria que se va a generar por lasfunciones de memoria dinámica. Por ejemplo, si se requierereservar un bloque de memoria para un arreglo de 10enteros:12

int tam;int *ptr;printf( "Ingresa el tamaño del arreglo " );scanf( "%d", &tam; );ptr (int *)malloc( tam * sizeof(int) );Nota importante: Los apuntadores que se utilizan para hacer referencia al bloque dememoria asignado por malloc() son de tipo dinámico y NO es conveniente quedichos apuntadores apunten a otro lugar antes de liberar el bloque de memoriaasignado ya que se estará perdiendo la referencia al bloque de memoria y no abraforma de recuperar la referencia ha esta, por lo tanto, la memoria no será liberada yhasta finalizar el programa.21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco Martínez Si no se conoce el tamaño de memoria que se quiere reservaral momento de diseñar un algoritmo, dicho tamaño se puedesolicitar al usuario y generar el bloque de memoria en tiempode ejecución. Un pequeño ejemplo seria el siguiente:13

21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco Martínez Un arreglo bidimensional en realidad es unarreglo cuyos elementos son arreglos. Si elnombre de un apuntador unidimensionales un apuntador sencillo, entonces, elnombre de un arreglo bidimensional seráun apuntador a apuntadores sencillos. icacadadimensión del arreglo al igual que sedeclara un arreglo unidimensional.14

Para generar al arreglo bidimensionalutilizando memoria dinámica se hace en dospasos:1. Se solicita la memoria para crear un arreglode apuntadores que van a apuntar a cadafila del arreglo.21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco MartínezUso de malloc() para generarun arreglo bidimensionalint **arr2d (int *)malloc( 10 * sizeof(int *) );1. Se solicita memoria para almacenar elnumero de elementos que va a formarcada fila o arreglo unidimensional.arr2d[i] (int*)malloc( elemFilas * sizeof( int ) );15

r2d[6]Arreglosunidimensionalesde tamaño n21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco Martínezarr2dArreglo de apuntadores sencillosarr2d[7]arr2d[8]arr2d[9]Donde cada arr2d[i] es un apuntador sencillo que apunta a un arreglounidimensional de tamaño n.16

int main(){int **arr2d, **aux;int tamFilas, elemFilas,i,j;int tam;do{system( "cls" );printf( "Ingresa el numero de filas: " );scanf( "%d", &tamFilas );}while( !(tamFilas 0) );arr2d (int**)malloc( tamFilas * sizeof( int* ) );aux arr2d;//para asignar el tamaño de cada una de las filas o arreglos//unidimensionalesfor( i 0; i tamFilas; i ){do{printf( "Ingresa un valor valido de elementos de una fila: " );scanf( "%d", &elemFilas );}while( !(elemFilas 0) );//asignar valores a cada arregloarr2D[i]srand( time(NULL) );for( j 0; j elemFilas; j ){arr2d[i][j] rand()%100;}//imprimir los valoresfor( j 0; j elemFilas; j ){printf( "%d ", arr2d[i][j] );}printf( "\n");}//liberar la memoriafor(i 0; i tamFilas; i ){free( arr2d[i] );}free( arr2d );return 0;//dos formas para generar los arreglos unidimensional//de elementos//1.arr2d[i] (int*)malloc( elemFilas * sizeof( int ) );21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco Martínez#include stdio.h #include stdlib.h }//2./* *aux (int*)malloc( elemFilas * sizeof( int ) );aux ;*/17

Cuando se termina de utilizar un bloque de memoriapreviamente asignado por cualquier función de asignacióndinámica de memoria, se debe liberar el espacio dememoria y dejarlo disponible para otros procesos, esto serealiza utilizando la función free(). El prototipo lafunción free es:21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco MartínezUso de free() para liberar lamemoria asignada dinámicamentevoid free(void *ptr); Donde: *ptr es el apuntador que hace referencia al bloquede memoria asignado, si ptr es NULL entonces free nohace nada. Si embargo, si ptr es un apuntador mal referenciado, el usode free probablemente destruya el mecanismo de gestiónde memoria y provocará un fallo en la aplicación.18

calloc() es otra función que permiteobtener memoria dinámica. Al igual quemalloc() devuelve un apuntador void*que hace referencia al bloque de memoriagenerado o NULL si no existe memoriasuficiente para generar el bloque solicitado,por tal motivo, también es necesario realizarun cast a un apuntador valido para manejarlos datos que se van a almacenar en elbloque de memoria asignado.21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco MartínezFunción calloc()19

void* calloc( size t n, size t t ); Donde: n: es el numero de datos que se van a almacenaren la memoria. t: es el tamaño de cada elemento, es decir, eltamaño del tipo de dato.21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco Martínez El prototipo de la función calloc() es:20

Forma de uso:puntero (tipo*) calloc( numElem, tamElem );Donde:puntero: es un apuntador valido que hace referencia al bloque dememoria generado.tipo *: es el cast al un apuntador valido.numElem: es el numero de elementos que se van a almacenar en elbloque de memoria.tamElem: es el tamaño del tipo de dato que se va a almacenar en lamemoria.21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco MartínezFunción calloc()calloc() una cantidad de memoria igual a numElem * tamElem. Esdecir, calloc() asigna memoria suficiente para un arreglo que contienenumElem elementos con un tamaño tamElem cada uno.Por ejemplo:21int *ptr;ptr (int *)calloc( 10, sizeof(int) );

//otra forma de generar la memoria//dinamica seria:c (char *)calloc( 1, sizeof(char) );entero (int *)calloc( 1, sizeof(int) );flotante (float *)calloc( 1, sizeof(float) );doble (double *)calloc( 1, sizeof(double) );#include stdio.h #include stdlib.h int main( void ){char *c;int *entero;float *flotante;double *doble;c (char *)calloc( 1,1 );entero (int *)calloc( 1,4 );flotante (float *)calloc( 1,4 );doble (double *)calloc( 1,8 );*c 'c';*entero 2378;*flotante 128.89172378;*doble 18947282.48263;printf( "valores: caracter %c, entero %d, flotante %f,doble %lf",*c, *entero, *flotante, *doble );free( c );free( entero );free( flotante );free( doble );return 0;}21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco Martínez Ejemplo:*c 'a';*entero 10;*flotante 3.89172378;*doble 1.48263;printf( "valores: caracter %c, entero %d, flotante %f, doble %lf \n\n",*c, *entero, *flotante, *doble );//Importantisimo liberar la memoria//cuando ya no es requeridafree( c );free( entero );free( flotante );free( doble );22

realloc() es la tercera función para obtenermemoria dinámica. También devuelve un apuntadorvoid* que hace referencia al bloque de memoria porlo tanto necesario realizar un cast a un apuntadorvalido. A diferencia de malloc() y calloc(), realloc()cambia el tamaño de un bloque de memoria asignadodinámicamente, es decir, toma como parámetro deentrada un apuntador *ptr a esa memoria ydependiendo de un segundo parámetro incrementaráo reducirá el tamaño de dicho bloque de memoria.21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco MartínezFunción realloc()23

void* realloc(void* ptr, size t t); Donde: ptr: es el apuntador que hace referencia a unbloque de memoria generado dinámicamente. t: es el nuevo tamaño en bytes para el bloque dememoria referenciado por ptr. t pude ser mayoro menor que el bloque original. Se devuelve un apuntador debido a que puedeque realloc() tenga que desplazar el bloqueoriginal para poder modificar su tamaño. Si estees el caso, se copia la información del bloqueoriginal (hasta t bytes) en el nuevo bloque.21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco Martínez El prototipo de la función es:24

puntero (tipo*) realloc( ptr, nuevoTam );Donde:puntero: es un apuntador valido que hace referencia albloque de memoria generado.tipo *: es el cast al un apuntador valido.ptr: el apuntador que hace referencia a un bloque dememoria generado dinámicamente.nuevoTam: es el nuevo tamaño para el bloque dememoria referenciado por ptr.21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco Martínez Forma de uso:25

1. En el C99 se especifico que la memoria referenciadapor ptr se libera y se crea un nuevo bloque.2. El nuevo bloque contiene la misma información que elbloque original (hasta la longitud especificada pornuevoTam). Se regresa un apuntador al nuevo bloquede memoria, sin embargo, el compilador puedegenerar el nuevo bloque a partir de la misma direcciónde inicio del bloque anterior, es decir, el nuevo bloquepuede contener la misma dirección de inicio que elbloque anterior.21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco Martínez Hay que tener en cuanta varias consideraciones alutilizar la función realloc():26

4. Si no hay memoria suficiente para asignarnuevoTam bytes, realloc() devuelve unapuntador NULL y el bloque original permaneceráintacto.21 Memoria dinámica y su uso en CAlgoritmia y programación estructuradaProf. Edgardo Adrián Franco Martínez3. Si ptr es NULL, realloc() simplemente genera elbloque de memoria especificado por nuevoTam. SinuevoTam es cero, se libera la memoriareferenciada por ptr y la función devuelve NULL.27

El manejo de memoria dinámica es la base del poder del lenguaje C y le da la capacidad de crear programas complejos que emplean grandes cantidades de memoria y los maneja de manera eficiente. 2 . almacenan en segmentos fijos de memoria o en la memoria de datos, sin embargo, también están disponibles en la función que las declaro. 3 en .