Saltar a contenido

Biblioteca

Colecci贸n de libros de tama帽o variable

  • Se trata de escribir un programa para gestionar una colecci贸n de libros
  • El tipo de datos b谩sico en el programa se denomina tipoBiblio y se define en un archivo cabecera biblio.h (apartado Definici贸n de tipoBiblio)
  • OJO, de inicio en el programa no hay colecci贸n ni, consecuentemente, libros en la colecci贸n 馃馃
  • La figura siguiente representa una biblioteca con 3 libros que ya est谩 llena pues el tama帽o inicial es 3. Se muestra la organizaci贸n resultante en memoria seg煤n el modo de operaci贸n
  • El programa contempla dos modos de operaci贸n. Aunque la figura muestra ambos modos, se consideran excluyentes entre s铆: el primero implementa la biblioteca como un array de punteros a structs (declaraci贸n ptrLibro libadr[]) mientras que el segundo emplea un array de structs (declaraci贸n Libro libarr[])
  • En el modo 1 los structs se almacenan necesariamente en celdas de memoria consecutivas lo cual no aplica cuando el modo es 0 (es un array de punteros)
  • Se trata de valorar las ventajas y desventajas de cada modo. Para ello se considerar谩 tanto la eficiencia como la dificultad para implementar las operaciones habituales de inserci贸n, borrado y redimensionamiento
  • Llamadas al sistema relevantes en el ejercicio:
    1. Gesti贸n memoria din谩mica: ver Intro MemDin
    2. realloc() para ampliar/reducir tama帽o de la biblioteca
    3. Utilizar salida formateada con sprintf() como en la funci贸n spLibro() en ejemplo.c

Biblioteca.png


Moduilaridad C vs Java

biblio.h y biblio.c equivaldr铆an a una clase Biblio.java con:
- Atributos: variable local tipoBiblio biblio;
- M茅todos p煤blicos: funciones declaradas en biblio.h
- M茅todos privados: funciones no declaradas en biblio.h (en este caso ninguna)

Memory Leak 馃拃馃拃馃拃

Situaci贸n en la que los programas dejan bloques de memoria dereferenciados y, por tanto, inaccesibles e inutilizables. Nunca debe ocurrir: 馃憠 es esencial reservar/liberar la memoria correctamente

Ejemplo de Memory Leak
char *arr1 = (char *) calloc(20, sizeof(char));
char arr2[20];

arr1 = &arr2; /* 馃槺馃槺馃槺 */

Definici贸n de tipoBiblio

biblio.h (1)
typedef struct st_Biblio {
    unsigned char modo;
    /*
    * Direcciones del almac茅n de libros
    * en cada una de las dos modalidades de operaci贸n
    * En realidad bastar铆a con un 煤nico puntero
    * gestionado con el correspondiente casting (ejercicio)
    */
    ptrLibro libarr;   /* direcci贸n array de libros. Equivalente a Libro libarr[] */
    ptrLibro *libptr;  /* direcci贸n array de punteros a libros. Equivalente a ptrLibro libadr[] */
    unsigned int lmax; /* n潞 m谩ximo de libros */
    unsigned int lnum; /* n潞 actual de libros */
} tipoBiblio;

API: m茅todos "p煤blicos"

biblio.h (2)
/*
 * Crea una biblioteca para n libros
 * Si modo es 0 define un array de n punteros a Libro
 * y si es 1 utiliza un array de libros
 * Devuelve 0 si se crea y 1 en caso contrario
 */
int newBiblio(unsigned char modo, int n);
/*
 * Libera la memoria (din谩mica) asociada con la biblioteca
 * Seg煤n el modo libera memoria del array de libros
 * o del array de punteros a libros
 */
void freeBiblio(void);
/*
 * Ampl铆a la biblioteca para acomodar n libros m谩s
 * Devuelve 0 si se ampl铆a y 1 en caso contrario
 */
int masBiblio(int n);
/*
 * C贸digo equivalente a la declaraci贸n est谩tica de
 * un libro pero utilizando memoria din谩mica
 * Declaraci贸n est谩tica: Libro miLibro;
 */
ptrLibro newLibro(int isbn, char *titulo, char *autor, char *descripcion);
/*
 * getter Libro. Devuelve su direcci贸n en la biblioteca
 */
ptrLibro getLibro(int n);
/*
 * A帽ade libro a la biblioteca
 * Devuelve 0 si hay espacio y 1 en caso contrario
 */
int putLibro(ptrLibro p);

Requerimientos de funcionalidad del programa

  • Captura el modo desde los argumentos en la l铆nea de orden
  • Define una biblioteca con capacidad para n libros (3 en el ejemplo)
  • Crea libros y los a帽ade a la biblioteca
  • Muestra libros en la biblioteca
  • Ampl铆a la capacidad de la biblioteca para acomodar libros adicionales
  • Para demostrar que el redimensionado no debe afectar al contenido en ejemplo.c se muestra en pantalla el libro 2 despu茅s de ampliar el tama帽o de la biblioteca
  • Devuelve (libera) toda la memoria asignada de forma din谩mica

C贸digo fuente del programa ejemplo

ejemplo.c
  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
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*
 * Biblioteca
 *
 *  Created on: 18 oct. 2021
 *      Author: santiago
 */

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

#include "biblio.h"


/*
 * Volcar en buff el libro apuntado por pl (ni buff ni pl deben ser null)
 * Utiliza la llamada al sistema sprintf()
 */
void spLibro (char *buff, ptrLibro pl) {
    char *aux = buff;

    memset(buff, 0, 150);
    sprintf(buff, "\n##### Datos del libro:\n");
    for(; *aux != 0; aux++);
    sprintf(aux, "\tISBN: %d\n", pl->isbn);
    for(; *aux != 0; aux++);
    sprintf(aux, "\tT铆tulo: %s\n", pl->titulo);
    for(; *aux != 0; aux++);
    sprintf(aux, "\tAutor: %s\n", pl->autor);
    for(; *aux != 0; aux++);
    sprintf(aux, "\tDescripci贸n: %s\n", pl->descripcion);
    for(; *aux != 0; aux++);
    sprintf(aux, "#####\n");
}

/*
 * Invocar con un argumento char con valor '0' o '1'
 * Si '0' usa un array de punteros para el almacenamiento de libros
 * Si '1' usa un array de libros
 */
int main(int argc, char * argv[]) {
    ptrLibro pl;
    /*
     * Arrays para sprintf()
     */
    char buffout[150];
    char tit[15];
    char aut[15];
    char des[25];
    int rcode = 0, i = 0;

    if(argc != 2) {
        fprintf(stderr, "Par谩metros incorrectos. No hace nada\n");
        exit(0);
    }
    /*
     * Crear biblioteca para 3 libros
     */
    switch(argv[1][0]) {
    case '0':
    case '1':
        rcode = newBiblio(argv[1][0], 3);
        break;
    default:
        fprintf(stderr, "Par谩metros incorrectos. No hace nada\n");
        exit(0);
    }
    /*
     * A帽adir libros a biblioteca
     */
    for (i = 0; i < 3 && rcode == 0; i++) {
        sprintf(tit, "T铆tulo %d", 10 + i * 10);
        sprintf(aut, "Autor %d", 10 + i * 10);
        sprintf(des, "Descripci贸n %d", 10 + i * 10);
        /*
         * Crear libro. Asigna memoria de forma din谩mica
         */
        pl = newLibro(10 + i * 10, tit, aut, des);
        if (pl != NULL) {
            /*
             * A帽adir el libro a la bibliotexa
             */
            rcode = putLibro(pl);
            if(argv[1][0] == '1')
                /*
                 * Liberar memoria. No se necesita dado que el
                 * libro fue copiado en la biblioteca (modo 1)
                 */
                free(pl);
        }
    }
    /*
     * Mostrar libros en biblioteca
     */
    printf("----------------------------------------------------------------\n");
    for (i = 0; i < 3 && rcode == 0; i++) {
        /*
         * Obtener el libro de la biblioteca
         */
        pl = getLibro(i+1);
        if(pl != NULL) {
            /*
             * Si hay libro volcar en buffer
             */
            spLibro(buffout, pl);
            /*
             * Imprimir el buffer
             */
            printf("Libro #%d:%s", i+1, buffout);
        }
        else
            rcode = 1;
    }
    printf("----------------------------------------------------------------\n");
    printf("Direcci贸n buffer: %p; Bytes totales: %ld\n", buffout, strlen(buffout));
    printf("----------------------------------------------------------------\n");
    /*
     * Ampliar la biblioteca con espacio para dos libros adicionales
     */
    rcode = masBiblio(2);
    sprintf(tit, "T铆tulo %d", 55);
    sprintf(aut, "Autor %d", 55);
    sprintf(des, "Descripci贸n %d", 55);
    /*
     * Crear libro. Asigna memoria de forma din谩mica
     */
    pl = newLibro(55, tit, aut, des);
    if (pl != NULL) {
        /*
         * A帽adir el libro a la bibliotexa
         */
        rcode = putLibro(pl);
        if(argv[1][0] == '1')
            /*
             * Liberar memoria. No se necesita dado que el
             * libro fue copiado en la biblioteca
             */
            free(pl);
        /*
         * Obtener el libro de la biblioteca
         */
        pl = getLibro(2);
        if(pl != NULL) {
            /*
             * Si hay libro volcar en buffer
             */
            spLibro(buffout, pl);
            printf("Libro #%d:%s", 2, buffout);
            printf("----------------------------------------------------------------\n");
        }
        else
            rcode = 1;
    }
    /*
     * IMPORTANTE: liberar TODA la memoria asignada antes de salir
     */
    freeBiblio();
    return rcode;
}

Tarea

Completar el c贸digo de las funciones en biblio.c

  • ptrLibro newLibro(int isbn, char *titulo, char *autor, char *descripcion);
  • int newBiblio(unsigned char modo, int n);
  • void freeBiblio(void);
  • int masBiblio(int n);
  • ptrLibro getLibro(int n);
  • int putLibro(ptrLibro p);

Material de Apoyo

Disponible en Moodle