21 memoria dinámica y su uso en c - eafranco.com

27
Estructuras de datos (Prof. Edgardo A. Franco) 1 Tema 21: Memoria dinámica y su uso en C M. en C. Edgardo Adrián Franco Martínez http://www.eafranco.com [email protected] @edfrancom edgardoadrianfrancom

Upload: others

Post on 11-Jul-2022

6 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 21 Memoria dinámica y su uso en C - eafranco.com

Estructuras de datos (Prof. Edgardo A. Franco)

1

Tema 21: Memoria dinámica y su uso en C

M. en C. Edgardo Adrián Franco Martínez http://[email protected]

@edfrancom edgardoadrianfrancom

Page 2: 21 Memoria dinámica y su uso en C - eafranco.com

Introducción• En muchas ocasiones no es posible conocer de antemano la

cantidad 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.

2

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 3: 21 Memoria dinámica y su uso en C - eafranco.com

• Todos los programas definen variables que pueden serdefinidas como globales y locales.

• 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.

3

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 4: 21 Memoria dinámica y su uso en C - eafranco.com

• 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.

• 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().

• Las regiones de memoria que reservan/liberan estasfunciones son almacenadas en el montículo o heap.

4

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 5: 21 Memoria dinámica y su uso en C - eafranco.com

5

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Código (Main y código de funciones empleadas)

Datos (Variables globales y declaradas dentro del

main)

Pila

Memoria de proceso activo

Pila(Stack)(Variables y datos de las funciones al estar en ejecución)

Montículo (Heap)(Variables dinámicas del programa)

Page 6: 21 Memoria dinámica y su uso en C - eafranco.com

Asignación dinámica de memoria• Por lo regular cuando se diseña un algoritmo, se debe

conocer 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.

6

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 7: 21 Memoria dinámica y su uso en C - eafranco.com

• 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

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 8: 21 Memoria dinámica y su uso en C - eafranco.com

• 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

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 9: 21 Memoria dinámica y su uso en C - eafranco.com

Función malloc()

• 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.h

9

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 10: 21 Memoria dinámica y su uso en C - eafranco.com

• El prototipo de la función malloc() sería:

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.

10

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 11: 21 Memoria dinámica y su uso en C - eafranco.com

• Por ejemplo:

#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 = '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 );

//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) );

*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;

}

11

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 12: 21 Memoria dinámica y su uso en C - eafranco.com

• 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:

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 ptr 12

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 13: 21 Memoria dinámica y su uso en C - eafranco.com

13

• 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:

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

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.

int tam;

int *ptr;

printf( "Ingresa el tamaño del arreglo " );

scanf( "%d", &tam; );

ptr = (int *)malloc( tam * sizeof(int) );

Page 14: 21 Memoria dinámica y su uso en C - eafranco.com

•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. Paraasignar memoria a un arreglomultidimensional, se indica cadadimensión del arreglo al igual que sedeclara un arreglo unidimensional.

14

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 15: 21 Memoria dinámica y su uso en C - eafranco.com

Uso de malloc() para generar un arreglo bidimensional• Para generar al arreglo bidimensional

utilizando 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.int **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

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 16: 21 Memoria dinámica y su uso en C - eafranco.com

arr2d

arr2d[0]

arr2d[1]

arr2d[2]

arr2d[3]

arr2d[4]

arr2d[5]

arr2d[6]

arr2d[7]

arr2d[8]

arr2d[9]

Donde cada arr2d[i] es un apuntador sencillo que apunta a un arreglo unidimensional de tamaño n.

Arreglosunidimensionales de tamaño n

Arreglo de apuntadores sencillos

16

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 17: 21 Memoria dinámica y su uso en C - eafranco.com

#include <stdio.h>#include <stdlib.h>

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) );

//dos formas para generar los arreglos unidimensional//de elementos

//1.-arr2d[i] = (int*)malloc( elemFilas * sizeof( int ) );

//2.-/* *aux = (int*)malloc( elemFilas * sizeof( int ) );aux++;*/

//asignar valores a cada arreglo arr2D[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;

}

17

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 18: 21 Memoria dinámica y su uso en C - eafranco.com

Uso de free() para liberar la memoria asignada dinámicamente• Cuando se termina de utilizar un bloque de memoria

previamente 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:

void 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

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 19: 21 Memoria dinámica y su uso en C - eafranco.com

Función calloc()

• 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. 19

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 20: 21 Memoria dinámica y su uso en C - eafranco.com

• El prototipo de la función calloc() es:

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.

20

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 21: 21 Memoria dinámica y su uso en C - eafranco.com

Función calloc()• 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.

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:

int *ptr;ptr = (int *)calloc( 10, sizeof(int) );

21

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 22: 21 Memoria dinámica y su uso en C - eafranco.com

• Ejemplo:

#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 = '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 );

//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) );

*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;

}

22

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 23: 21 Memoria dinámica y su uso en C - eafranco.com

Función realloc()

• 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. 23

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 24: 21 Memoria dinámica y su uso en C - eafranco.com

• El prototipo de la función es: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. 24

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 25: 21 Memoria dinámica y su uso en C - eafranco.com

• Forma de uso: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.

25

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 26: 21 Memoria dinámica y su uso en C - eafranco.com

• Hay que tener en cuanta varias consideraciones alutilizar la función realloc():

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.

26

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez

Page 27: 21 Memoria dinámica y su uso en C - eafranco.com

3. 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.

4. Si no hay memoria suficiente para asignarnuevoTam bytes, realloc() devuelve unapuntador NULL y el bloque original permaneceráintacto.

27

21

Mem

ori

a d

inám

ica

y su

uso

en

CA

lgo

ritm

ia y

pro

gram

ació

n e

stru

ctu

rad

aP

rof.

Edga

rdo

Ad

rián

Fra

nco

Mar

tín

ez