Saltar a contenido

Biblioteca: Soluci贸n comentada

Pasos previos

  • Mejores pr谩cticas: revisar Dec谩logo 馃槑馃槑
  • An谩lisis concienzudo del las definiciones de los tipos de datos
  • Esqueleto de c贸digo conforme a la definici贸n de tareas y el API del programa
    Esqueleto del programa
    #include <stdlib.h>
    #include <string.h>
    #include "biblio.h"
    
    /*
     * Variable local para la biblioteca
     */
    tipoBiblio biblio;
    
    /*
     * 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) {
        return NULL;
    }
    
    /*
     * getter Libro. Devuelve su direcci贸n en la biblioteca
     */
    ptrLibro getLibro(int n) {
        return NULL;
    }
    
    /*
     * A帽ade libro a la biblioteca
     * Devuelve 0 si hay espacio y 1 en caso contrario
     */
    int putLibro(ptrLibro p) {
        return -1;
    }
    
    /*
     * 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) {
        return -1;
    }
    
    /*
     * 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) {
        return -1;
    }
    
  • 脫rdenes de compilaci贸n gcc
    # Compilar
    gcc -Wall -Wextra -pedantic -Werror -ansi -c biblio.c -o bin/biblio.o
    gcc -Wall -Wextra -pedantic -Werror -ansi -c ejemplo.c -o bin/ejemplo.o
    
    # Montar
    gcc bin/ejemplo.o bin/biblio.o -o bin/biblio
    

Implementaci贸n de biblio.c

Crear biblioteca (sin libros): int newBiblio(unsigned char modo, int n)

/*
 * 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) {
    int rcode = 1;
/* biblio es local, se accede directamente a los campos del struct */
    biblio.lmax = n;
    biblio.lnum = 0;
    biblio.modo = modo;
    if(modo == '0') {
        /*
         * Definir array de n punteros a libros
         */
        biblio.libptr = (ptrLibro *) calloc(n, (int) sizeof(ptrLibro));
        if (biblio.libptr != NULL)
            rcode = 0;
    }
    else {
        /*
         * Definir array de n libros
         */
        biblio.libarr = (ptrLibro) calloc(n, (int) sizeof(Libro));
        if (biblio.libarr != NULL)
            rcode = 0;
    }
    return rcode;
}

Eliminar biblioteca: void freeBiblio(void)

/*
 * 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) {
    int i;

    if(biblio.modo == '0') {
        /*
         * Liberar memoria n libros. Requiere iterar en array de punteros a libros
         */
        for(i = 0; i < (int)biblio.lnum; i++)
            free(biblio.libptr[i]);
        /*
         * Liberar memoria array de punteros. No requiere iterar
         */
        free(biblio.libptr);
    }
    else
        /*
         * Liberar memoria array de libros
         */
        free(biblio.libarr);
}

Crear libro: ptrLibro newLibro(int isbn, char *titulo, char *autor, char *descripcion)

/*
 * 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) {
    ptrLibro plibro;
    /*
     * Creaci贸n de un libro reservando memoria de forma din谩mica invocando calloc (malloc + init)
     * OJO: los datos del libro suministrados como argumento se copian al nuevo libro
     */
    plibro = (ptrLibro) calloc (1, sizeof(Libro));
    if (plibro != NULL) {
        plibro->isbn = isbn;
        strcpy(plibro->titulo, titulo);
        strcpy(plibro->autor, autor);
        strcpy(plibro->descripcion, descripcion);
    }
    return plibro;
}

Obtener libro n de la biblioteca (getter): ptrLibro getLibro(int n)

/*
 * getter Libro. Devuelve su direcci贸n en la biblioteca
 */
ptrLibro getLibro(int n) {
    ptrLibro aux;

    if(n > 0 && n < (int)biblio.lnum +1) {
        /*
         * Discriminar modo
         */
        if(biblio.modo == '0')
            /*
             * Devuelve el puntero en el array de punteros
             */
            aux = biblio.libptr[n - 1];
        else
            /*
             * Devuelve la direcci贸n en el array de libros
             */
            aux = &biblio.libarr[n - 1];
        return aux;
    }
    return NULL;
}

A帽adir libro a biblioteca (setter): int putLibro(ptrLibro p)

 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
/*
 * A帽ade libro a la biblioteca
 * Devuelve 0 si hay espacio y 1 en caso contrario
 */
int putLibro(ptrLibro p) {
    if(biblio.lnum < biblio.lmax) {
        /*
         * Discriminar modo
         */
        if(biblio.modo == '0')
            /*
             * Copiar puntero. OJO: los datos permanecen en origen
             */
            biblio.libptr[biblio.lnum] = p;
        else
            /*
             * Copiar libro apuntado por p en el array
             * En el retorno, el llamador deber铆a liberar esta memoria
             * Ver llamadas a free() en l铆neas 89 y 138 de ejemplo.c
             */
            memcpy(&biblio.libarr[biblio.lnum], p, sizeof(Libro));
        /*
         * Contabilizar libro
         */
        biblio.lnum++;
        return 0;
    }
    return 1;
}

Redimensionar la biblioteca: int masBiblio(int n)

/*
 * Ampl铆a la biblioteca para acomodar n libros adicionales
 * Devuelve 0 si se ampl铆a y 1 en caso contrario
 */
int masBiblio(int n) {
    int rcode = 1;
    ptrLibro *aux1, aux2;

    if(biblio.modo == '0') {
        /*
         * Redimensionar array de n punteros a libros (OJO: sizeof de puntero)
         */
        aux1 = (ptrLibro *) realloc(biblio.libptr, (biblio.lmax + n) * (int) sizeof(ptrLibro));
        if (aux1 != NULL) {
            biblio.libptr = aux1;
            /*
             * Incrementar la capacidad en n libros adicionales
             */
            biblio.lmax += n;
            rcode = 0;
        }
    }
    else {
        /*
         * Redimensionar array de n libros
         */
        aux2 = (ptrLibro) realloc(biblio.libarr, (biblio.lmax + n) * (int) sizeof(Libro));
        if (aux2 != NULL) {
            biblio.libarr = aux2;
            /*
             * Incrementar la capacidad en n libros adicionales
             */
            biblio.lmax += n;
            rcode = 0;
        }
    }
    return rcode;
}

Tarea

Abordar las siguientes modificaciones de la funcionalidad del programa

  • Importaci贸n de los libros a la biblioteca desde un archivo con datos tipo texto
  • Exportaci贸n de los libros a la biblioteca a un archivo con datos tipo texto
  • Importaci贸n de los libros a la biblioteca desde un archivo con datos tipo binario
  • Exportaci贸n de los libros a la biblioteca a un archivo con datos tipo binario
  • El c贸digo de masBiblio() contempla 煤nicamente incrementar la capacidad de la biblioteca
    Una soluci贸n m谩s general debiera permitir tanto aumentar como reducir la capacidad

  • Ajustar la memoria requerida por el programa al tama帽o exacto de cada libro. Para ello se requiere redefinir el tipo Libro de acuerdo a la siguiente declaraci贸n

    typedef struct Libros {
        int isbn;
        char *titulo;
        char *autor;
        char *descripcion;
    } Libro;