Saltar a contenido

Intro MemDin

Áreas de Memoria: Estática vs Dinámica

MemDin.png

Gestión memoria dinámica en C

Llamadas al sistema

Las llamadas a la librería del sistema más relevantes para este apartado del curso se declaran en stdlib.h:

El casting en C

C es un lenguaje fuertemente tipeado lo cual significa que todo tiene un tipo asignado. Entonces, puesto que cada tipo requiere un consumo de memoria particular habría que escribir funciones de asignación de memoria específicas para reservar y liberar memoria de cada tipo de datos. Para evitar esto (y por otras razones que no vienen al caso), las funciones que asignan memoria devuelven un puntero a void. Esto es, la definición de un puntero genérico que procede especificar al tipo de que se trata
En tal caso, el casting soporta la especificación o concreción de dicho puntero. Básicamente consiste en una conversión explícita de tipo análoga a la de cualquier otro tipo básico

Ejemplo:

arr2 = (char *) realloc( arr2, lstr + 1 );

El operador sizeof()

El operador unario (no es una función ni tampoco una macro) sizeof() devuelve el tamaño en bytes del operando. Este puede ser una variable, una expresión o (preferiblemente) un tipo. Cuando el operando es un array estático el resultado es el número de bytes que requiere almacenar el array completo. Por tanto, en este caso no es cierta la equivalencia entre arrays y punteros (es una excepción) pero tiene la ventaja de que es muy fácil prever desbordamientos de memoria cuando se trabaja con memoria estática o asegurarse de que el último byte de un array vale 0

Ejemplo básico: arrays con memoria reservada de manera dinámica

Arrays dinámicos
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/*
 * Código ejemplo acerca de memoria dinámica en C  
 * Se muestran:  
 * - funciones para asignación de memoria  
 * - el operador sizeof()  
 * - la conversión de tipos (type casting)  
 * En el código siguiente se crean dos arrays de manera dinámica y  
 * se copian en ellos dos strings  
 */

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

typedef char * ptrChar;

void ejMemDin(void) {
    char *arr1 = NULL, arr2 = NULL;   /* son punteros, esto es, almacenan direcciones */
    int lstr;

    /*
        De inicio no hay memoria asignada. Únicamente las dos
        variables puntero y el entero ocupan memoria (estática)
        Crear dos arrays invocando a malloc() y calloc()
        Declaraciones estáticas equivalentes:
        char arr1[200];
        char arr2[120];
    */
    arr1 = (char *) calloc( 200, sizeof(char) );
    arr2 = (char *) malloc( 120 * sizeof(char) );

    /* OJO, recomendable inicializar SIEMPRE los arrays */
    /* No es necesario memset(arr1, '\0', 200); */
    memset(arr2, '\0', 120);

    /* Mostrar el valor de los punteros */
    printf("Direcciones (ptr hex): arr1 = %p, arr2 = %p\n", arr1, arr2);

    /* Mostrar el tamaño real que ocupan los punteros */
    printf("Tamaños (ptrChar): %ld\n", sizeof(ptrChar));
    /* OJO: zoquetada del 13!!! */
    printf("Tontería supina!!!: sizeof(arr1) = %ld\n", sizeof(arr1));

    /* Copiar datos en uno de los arrays */
    strcpy(arr1, "Lo que más rabia te dé");
    lstr = strlen(arr1);
    printf("arr1: \"%s\" solo ocupa %d bytes del total (200 bytes)\n", arr1, lstr);
    printf("arr2: \"%s\" ocupa 120 bytes reales\n", arr2);

    /* Copiar arr1 en arr2 pero reasignado al tamaño justo necesario */
    arr2 = (char *) realloc( arr2, lstr + 1 );
    /* OJO, lo siguiente NO sirve!!!! */
    /* arr2[sizeof(arr2) - 1] = '\0'; */
    arr2[lstr] = 0;
    strcpy(arr2, arr1);
    printf("arr2: \"%s\" ahora son %d + 1 bytes reales\n", arr2, lstr);

    /* IMPORTANTE: Liberar SIEMPRE la memoria cuando ya no se use */
    free((ptrChar) arr1);
    free((ptrChar) arr2);

    /* Declaración array estático */
    char prueba[15];
    printf("sizeof(prueba) = %ld\n", sizeof(prueba));
    /* Luego, con memoria estática esto SÍ es válido: */
    prueba[sizeof(prueba) - 1] = '\0';
}

Lecturas recomendadas