Lenguaje de programación C

C – Ejercicio resuelto sobre gestión de películas

En este post de programación en C voy a resolver un ejercicio que trata sobre cines y la gestión de películas. Es un ejercicio para practicar ANSI C. Dice así:

Diseñar un programa en Lenguaje C que almacene la información de las películas que se proyectan en las distintas salas de los siguientes cines: CDMX Norte, CDMX Oriente, Reforma y Perisur.

Cada cine tiene 3 salas, hay 2 horarios distintos en cada sala (4:00 pm y 6:00 pm) Realizar un menú para el uso de este programa. En el programa debe definirse las estructuras de datos (struct) necesarias para almacenar la información sobre las películas: título de la película, hora de inicio, cines y salas donde se proyecta, clasificación (A todo público, B adolescentes y adultos y C mayores de 21 años).

El menú del programa debe tener las siguientes opciones:

  1. Registrar una película. Si ya había alguna película, está será sustituida por la proporcionada en esta opción.
  2. Desplegar toda la información de la película que se proyecta en la sala de un cine. Se pedirá al usuario que proporcione el cine, la sala, la hora y el día correspondiente, y el programa listará la información de la película que está proyectada en la cartelera. En caso de no haber película proyectada, se visualizará el mensaje correspondiente.
  3. Buscar película. El usuario elige la película que quiere buscar y desplegar toda la información.
  4. Listar películas que se están exhibiendo en un cierto día por clasificación de edad.
  5. Salir del Programa.

Veamos entonces cómo resolver ese ejercicio.

Solución general

Vamos a usar una pila dinámica para almacenar los datos, de este modo puede haber ilimitada cantidad de los mismos.

Para registrar, simplemente apilamos un elemento. Y para realizar las búsquedas vamos a recorrer toda la pila y ver si la búsqueda coincide comparando cadenas con strcmp.

Así que comenzamos incluyendo los encabezados y definiendo el struct del detalle de la película.

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

// En C no podemos tener cadenas sin límite, por eso definimos un límite considerable
#define MAXIMA_LONGITUD_CADENA 101


// El struct que guarda los datos de las películas
struct detalleDePelicula {
    char nombre[MAXIMA_LONGITUD_CADENA];
    char horaInicio[MAXIMA_LONGITUD_CADENA];
    char cine[MAXIMA_LONGITUD_CADENA];
    char sala[MAXIMA_LONGITUD_CADENA];
    char dia[MAXIMA_LONGITUD_CADENA];
    char clasificacion;
    // Aquí hay un struct dentro de un struct, pues vamos a guardar los datos en una "pila" en donde este dato puede tener
    // otro dato en "siguiente"
    struct detalleDePelicula *siguiente;
};

// El inicio de la pila es un nodo superior que al inicio es NULL
struct detalleDePelicula *superior = NULL;

Fíjate en que el struct tiene el nombre, la hora, el cine, la sala y la clasificación. Todos los datos son cadena, exceptuando a la clasificación que es un char y al nodo siguiente que es a su vez un struct de tipo detalleDePelicula.

Registrar una película

Cuando agregamos una nueva película debemos buscar si la misma existe, en caso de que exista simplemente actualizamos el struct. Veamos las funciones que nos van a ayudar a realizar esta operación:



// Función que regresará un detalle de película en caso de encontrarla
struct detalleDePelicula *
buscar(char horaInicio[MAXIMA_LONGITUD_CADENA], char cine[MAXIMA_LONGITUD_CADENA], char sala[MAXIMA_LONGITUD_CADENA],
       char dia[MAXIMA_LONGITUD_CADENA]) {
    // Vamos a usar este temporal para leer toda la pila
    struct detalleDePelicula *temporal = superior;
    // Recorremos toda la pila
    while (temporal != NULL) {
        // Si encontramos que coincide lo buscado con lo que hay en la pila en este momento, entonces regresamos el detalle
        if (
                strcmp(cine, temporal->cine) == 0 &&
                strcmp(sala, temporal->sala) == 0 &&
                strcmp(horaInicio, temporal->horaInicio) == 0 &&
                strcmp(dia, temporal->dia) == 0
                ) {
            return temporal;
        }
        // Y vamos avanzando
        temporal = temporal->siguiente;
    }
    // En caso de terminar de recorrer la pila y que no haya nada, regresamos NULL
    return NULL;
}


// Agrega una película por primera vez
void
agregarPorPrimeraVez(char nombre[MAXIMA_LONGITUD_CADENA], char horaInicio[MAXIMA_LONGITUD_CADENA],
                     char cine[MAXIMA_LONGITUD_CADENA], char sala[MAXIMA_LONGITUD_CADENA],
                     char dia[MAXIMA_LONGITUD_CADENA], char clasificacion) {
    // Requerir RAM para alojar este detalle de película
    struct detalleDePelicula *d = malloc(sizeof(struct detalleDePelicula));
    // Llenamos el struct. Copiamos el nombre, hora, etcétera
    memcpy(d->nombre, nombre, MAXIMA_LONGITUD_CADENA);
    memcpy(d->horaInicio, horaInicio, MAXIMA_LONGITUD_CADENA);
    memcpy(d->cine, cine, MAXIMA_LONGITUD_CADENA);
    memcpy(d->sala, sala, MAXIMA_LONGITUD_CADENA);
    memcpy(d->dia, dia, MAXIMA_LONGITUD_CADENA);
    d->clasificacion = clasificacion;
    // Y como estamos agregando un elemento, ahora éste es el superior, y su siguiente es el que antes era el superior
    d->siguiente = superior;
    superior = d;
}


// Si ya existe, la actualiza. Si no, la agrega por primera vez
void agregarOActualizar(char nombre[MAXIMA_LONGITUD_CADENA], char horaInicio[MAXIMA_LONGITUD_CADENA],
                        char cine[MAXIMA_LONGITUD_CADENA], char sala[MAXIMA_LONGITUD_CADENA],
                        char dia[MAXIMA_LONGITUD_CADENA], char clasificacion) {
    // Buscar película con estos datos
    struct detalleDePelicula *existente = buscar(horaInicio, cine, sala, dia);
    // Si no existe, lo agregamos por primera vez
    if (existente == NULL) {
        agregarPorPrimeraVez(nombre, horaInicio, cine, sala, dia, clasificacion);
        printf("\nPelicula agregada\n");
    } else {
        // Si no, solo actualizamos (y lo indicamos)
        memcpy(existente->nombre, nombre, MAXIMA_LONGITUD_CADENA);
        memcpy(existente->horaInicio, horaInicio, MAXIMA_LONGITUD_CADENA);
        memcpy(existente->cine, cine, MAXIMA_LONGITUD_CADENA);
        memcpy(existente->sala, sala, MAXIMA_LONGITUD_CADENA);
        memcpy(existente->dia, dia, MAXIMA_LONGITUD_CADENA);
        existente->clasificacion = clasificacion;
        printf("\nPelicula ya existia, fue reemplazada\n");
    }
}

La función buscar regresa un apuntador a la película en caso de que exista, o NULL en caso de que no. La función agregarPorPrimeraVez hace la inserción en la pila y finalmente la función agregarOActualizar actualiza la película.

Es importante notar el código que actualiza la película dentro de la pila, pues usamos memcpy para intercambiar las cadenas, ya que no podemos usar una simple asignación (en el caso de la clasificación, que es un char, no hay problema).

Desplegar información de película

Veamos el siguiente requisito: desplegar la información de la película. Para ello vamos a reutilizar la función buscar que vimos anteriormente, y solo vamos a imprimir los detalles en caso de que el apuntador devuelto no sea NULL.


// Esta función se reutiliza varias veces. Simplemente recibe un detalle de película y lo imprime
void imprimirPelicula(struct detalleDePelicula *detalleDePelicula) {
    printf("Nombre: %s, hora: %s, cine: %s, sala: %s, dia: %s, clasificacion: %c\n", detalleDePelicula->nombre,
           detalleDePelicula->horaInicio, detalleDePelicula->cine, detalleDePelicula->sala, detalleDePelicula->dia,
           detalleDePelicula->clasificacion);
}

// Esta función busca una película existente con los datos (usando la función "buscar" vista anteriormente
// En caso de que encuentre datos, invoca a "imprimirPelicula" vista anteriormente de igual modo
void desplegarInformacion(char horaInicio[MAXIMA_LONGITUD_CADENA], char cine[MAXIMA_LONGITUD_CADENA],
                          char sala[MAXIMA_LONGITUD_CADENA], char dia[MAXIMA_LONGITUD_CADENA]) {
    printf("\n--Resultados de busqueda por hora, cine, sala y dia --\n");
    struct detalleDePelicula *existente = buscar(horaInicio, cine, sala, dia);
    if (existente == NULL) {
        printf("No hay pelicula para los datos proporcionados");
    } else {
        imprimirPelicula(existente);
    }
}

La función imprimirPelicula recibe un struct e imprime todos los detalles de la película. Presta atención a esa función porque vamos a usarla de nuevo en los siguientes puntos de este ejercicio resuelto en lenguaje C.

Buscar película por nombre

Aquí vamos a recorrer toda la pila y comparar si hay alguna película con el mismo nombre que la búsqueda. En caso de que sí, la imprimimos:


// Recorre toda la pila de películas y en caso de que encuentre una en la que coincide el nombre, la imprime
void buscarPeliculaPorNombre(char nombre[MAXIMA_LONGITUD_CADENA]) {
    printf("\n--Resultados de busqueda por nombre --\n");
    struct detalleDePelicula *temporal = superior;
    while (temporal != NULL) {
        if (strcmp(nombre, temporal->nombre) == 0) {
            imprimirPelicula(temporal);
        }
        temporal = temporal->siguiente;
    }
}

En la línea 8 estamos reusando la función que dije que íbamos a estar usando en varios puntos del programa. El siguiente requisito es muy parecido a éste, solo que también comparamos otros campos.

Listar películas por clasificación y día

Veamos el último requisito de este ejercicio para un programa en C. Ahora vamos a listar las películas basándonos en una fecha y en la clasificación. Solo vamos a imprimir aquellas películas que coincidan:


// Lo mismo que "buscarPeliculaPorNombre" pero ahora también busca por día y clasificación
void buscarPeliculaPorDiaYClasificacion(char dia[MAXIMA_LONGITUD_CADENA], char clasificacion) {
    printf("\n--Resultados de busqueda por dia y clasificacion --\n");
    struct detalleDePelicula *temporal = superior;
    while (temporal != NULL) {
        if (strcmp(dia, temporal->dia) == 0 && temporal->clasificacion == clasificacion) {
            imprimirPelicula(temporal); // <-- Aquí reusamos la función "imprimirPelicula"
        }
        temporal = temporal->siguiente;
    }
}

Lo que resta ahora es hacer el menú de opciones e invocar a las funciones según la elección del usuario. Eso lo veremos a continuación.

Poniendo todo junto

El ejercicio completo queda como se ve a continuación. Recuerda que eres libre de modificarlo y adaptarlo a tu gusto o necesidades:

/*
  ____          _____               _ _           _
 |  _ \        |  __ \             (_) |         | |
 | |_) |_   _  | |__) |_ _ _ __ _____| |__  _   _| |_ ___
 |  _ <| | | | |  ___/ _` | '__|_  / | '_ \| | | | __/ _ \
 | |_) | |_| | | |  | (_| | |   / /| | |_) | |_| | ||  __/
 |____/ \__, | |_|   \__,_|_|  /___|_|_.__/ \__, |\__\___|
         __/ |                               __/ |
        |___/                               |___/

____________________________________
/ Si necesitas ayuda, contáctame en \
\ https://parzibyte.me               /
 ------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
Creado por Parzibyte (https://parzibyte.me). Este encabezado debe mantenerse intacto,
excepto si este es un proyecto de un estudiante.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// En C no podemos tener cadenas sin límite, por eso definimos un límite considerable
#define MAXIMA_LONGITUD_CADENA 101


// El struct que guarda los datos de las películas
struct detalleDePelicula {
    char nombre[MAXIMA_LONGITUD_CADENA];
    char horaInicio[MAXIMA_LONGITUD_CADENA];
    char cine[MAXIMA_LONGITUD_CADENA];
    char sala[MAXIMA_LONGITUD_CADENA];
    char dia[MAXIMA_LONGITUD_CADENA];
    char clasificacion;
    // Aquí hay un struct dentro de un struct, pues vamos a guardar los datos en una "pila" en donde este dato puede tener
    // otro dato en "siguiente"
    struct detalleDePelicula *siguiente;
};

// El inicio de la pila es un nodo superior que al inicio es NULL
struct detalleDePelicula *superior = NULL;


// Función que regresará un detalle de película en caso de encontrarla
struct detalleDePelicula *
buscar(char horaInicio[MAXIMA_LONGITUD_CADENA], char cine[MAXIMA_LONGITUD_CADENA], char sala[MAXIMA_LONGITUD_CADENA],
       char dia[MAXIMA_LONGITUD_CADENA]) {
    // Vamos a usar este temporal para leer toda la pila
    struct detalleDePelicula *temporal = superior;
    // Recorremos toda la pila
    while (temporal != NULL) {
        // Si encontramos que coincide lo buscado con lo que hay en la pila en este momento, entonces regresamos el detalle
        if (
                strcmp(cine, temporal->cine) == 0 &&
                strcmp(sala, temporal->sala) == 0 &&
                strcmp(horaInicio, temporal->horaInicio) == 0 &&
                strcmp(dia, temporal->dia) == 0
                ) {
            return temporal;
        }
        // Y vamos avanzando
        temporal = temporal->siguiente;
    }
    // En caso de terminar de recorrer la pila y que no haya nada, regresamos NULL
    return NULL;
}


// Agrega una película por primera vez
void
agregarPorPrimeraVez(char nombre[MAXIMA_LONGITUD_CADENA], char horaInicio[MAXIMA_LONGITUD_CADENA],
                     char cine[MAXIMA_LONGITUD_CADENA], char sala[MAXIMA_LONGITUD_CADENA],
                     char dia[MAXIMA_LONGITUD_CADENA], char clasificacion) {
    // Requerir RAM para alojar este detalle de película
    struct detalleDePelicula *d = malloc(sizeof(struct detalleDePelicula));
    // Llenamos el struct. Copiamos el nombre, hora, etcétera
    memcpy(d->nombre, nombre, MAXIMA_LONGITUD_CADENA);
    memcpy(d->horaInicio, horaInicio, MAXIMA_LONGITUD_CADENA);
    memcpy(d->cine, cine, MAXIMA_LONGITUD_CADENA);
    memcpy(d->sala, sala, MAXIMA_LONGITUD_CADENA);
    memcpy(d->dia, dia, MAXIMA_LONGITUD_CADENA);
    d->clasificacion = clasificacion;
    // Y como estamos agregando un elemento, ahora éste es el superior, y su siguiente es el que antes era el superior
    d->siguiente = superior;
    superior = d;
}


// Si ya existe, la actualiza. Si no, la agrega por primera vez
void agregarOActualizar(char nombre[MAXIMA_LONGITUD_CADENA], char horaInicio[MAXIMA_LONGITUD_CADENA],
                        char cine[MAXIMA_LONGITUD_CADENA], char sala[MAXIMA_LONGITUD_CADENA],
                        char dia[MAXIMA_LONGITUD_CADENA], char clasificacion) {
    // Buscar película con estos datos
    struct detalleDePelicula *existente = buscar(horaInicio, cine, sala, dia);
    // Si no existe, lo agregamos por primera vez
    if (existente == NULL) {
        agregarPorPrimeraVez(nombre, horaInicio, cine, sala, dia, clasificacion);
        printf("\nPelicula agregada\n");
    } else {
        // Si no, solo actualizamos (y lo indicamos)
        memcpy(existente->nombre, nombre, MAXIMA_LONGITUD_CADENA);
        memcpy(existente->horaInicio, horaInicio, MAXIMA_LONGITUD_CADENA);
        memcpy(existente->cine, cine, MAXIMA_LONGITUD_CADENA);
        memcpy(existente->sala, sala, MAXIMA_LONGITUD_CADENA);
        memcpy(existente->dia, dia, MAXIMA_LONGITUD_CADENA);
        existente->clasificacion = clasificacion;
        printf("\nPelicula ya existia, fue reemplazada\n");
    }
}


// Esta función se reutiliza varias veces. Simplemente recibe un detalle de película y lo imprime
void imprimirPelicula(struct detalleDePelicula *detalleDePelicula) {
    printf("Nombre: %s, hora: %s, cine: %s, sala: %s, dia: %s, clasificacion: %c\n", detalleDePelicula->nombre,
           detalleDePelicula->horaInicio, detalleDePelicula->cine, detalleDePelicula->sala, detalleDePelicula->dia,
           detalleDePelicula->clasificacion);
}

// Esta función busca una película existente con los datos (usando la función "buscar" vista anteriormente
// En caso de que encuentre datos, invoca a "imprimirPelicula" vista anteriormente de igual modo
void desplegarInformacion(char horaInicio[MAXIMA_LONGITUD_CADENA], char cine[MAXIMA_LONGITUD_CADENA],
                          char sala[MAXIMA_LONGITUD_CADENA], char dia[MAXIMA_LONGITUD_CADENA]) {
    printf("\n--Resultados de busqueda por hora, cine, sala y dia --\n");
    struct detalleDePelicula *existente = buscar(horaInicio, cine, sala, dia);
    if (existente == NULL) {
        printf("No hay pelicula para los datos proporcionados");
    } else {
        imprimirPelicula(existente);
    }
}

// Recorre toda la pila de películas y en caso de que encuentre una en la que coincide el nombre, la imprime
void buscarPeliculaPorNombre(char nombre[MAXIMA_LONGITUD_CADENA]) {
    printf("\n--Resultados de busqueda por nombre --\n");
    struct detalleDePelicula *temporal = superior;
    while (temporal != NULL) {
        if (strcmp(nombre, temporal->nombre) == 0) {
            imprimirPelicula(temporal);
        }
        temporal = temporal->siguiente;
    }
}

// Lo mismo que "buscarPeliculaPorNombre" pero ahora también busca por día y clasificación
void buscarPeliculaPorDiaYClasificacion(char dia[MAXIMA_LONGITUD_CADENA], char clasificacion) {
    printf("\n--Resultados de busqueda por dia y clasificacion --\n");
    struct detalleDePelicula *temporal = superior;
    while (temporal != NULL) {
        if (strcmp(dia, temporal->dia) == 0 && temporal->clasificacion == clasificacion) {
            imprimirPelicula(temporal); // <-- Aquí reusamos la función "imprimirPelicula"
        }
        temporal = temporal->siguiente;
    }
}

int main() {
    // Declarar variables que vamos a reusar durante toda la ejecución
    int eleccion;
    char nombre[MAXIMA_LONGITUD_CADENA];
    char horaInicio[MAXIMA_LONGITUD_CADENA];
    char cine[MAXIMA_LONGITUD_CADENA];
    char sala[MAXIMA_LONGITUD_CADENA];
    char dia[MAXIMA_LONGITUD_CADENA];
    char clasificacion;
    // Ciclo infinito. Se termina cuando se hace un "return"
    while (1) {
        printf("\n1. Registrar pelicula\n2. Desplegar informacion que se proyecta en la sala de un cine\n3. Buscar pelicula\n4. Listar peliculas en cierto dia por clasificacion de edad\n5. Salir\nSeleccione:");
        scanf("%d", &eleccion);
        while (getchar() !=
               '\n'); // <-- Limpiar el búfer de entrada, esto es porque en ocasiones hay errores al usar scanf
        // Si la elección es 5, salimos inmediatamente
        if (eleccion == 5) {
            return 0;
        }
        // Si no, evaluamos la elección
        switch (eleccion) {
            // Caso 1: registrar película
            case 1:
                // Solicitar todos los datos
                printf("Ingresa el nombre: ");
                // Leer lo que el usuario ha escrito
                fgets(nombre, MAXIMA_LONGITUD_CADENA - 1, stdin);
                // Pero remover el salto de línea (Enter) que hay al final
                // (eso de remover y leer se repite varias veces)
                strtok(nombre, "\n");
                printf("Ingresa la hora de inicio:");
                fgets(horaInicio, MAXIMA_LONGITUD_CADENA - 1, stdin);
                strtok(horaInicio, "\n");
                printf("Ingresa el cine:");
                fgets(cine, MAXIMA_LONGITUD_CADENA - 1, stdin);
                strtok(cine, "\n");
                printf("Ingresa la sala:");
                fgets(sala, MAXIMA_LONGITUD_CADENA - 1, stdin);
                strtok(sala, "\n");
                printf("Ingresa el dia en formato YYYY-MM-DD:");
                fgets(dia, MAXIMA_LONGITUD_CADENA - 1, stdin);
                strtok(dia, "\n");
                // Aquí no usamos fgets porque es un solo caracter, no una cadena
                printf("Ingresa la clasificacion (A, B o C):");
                scanf("%c", &clasificacion);
                // Invocamos a la función agregarOActualizar con los datos definidos
                agregarOActualizar(nombre, horaInicio, cine, sala, dia, clasificacion);
                break;
            case 2:
                // De aquí en adelante son cosas similares
                printf("Ingresa la hora de inicio:");
                fgets(horaInicio, MAXIMA_LONGITUD_CADENA - 1, stdin);
                strtok(horaInicio, "\n");
                printf("Ingresa el cine:");
                fgets(cine, MAXIMA_LONGITUD_CADENA - 1, stdin);
                strtok(cine, "\n");
                printf("Ingresa la sala:");
                fgets(sala, MAXIMA_LONGITUD_CADENA - 1, stdin);
                strtok(sala, "\n");
                printf("Ingresa el dia en formato YYYY-MM-DD:");
                fgets(dia, MAXIMA_LONGITUD_CADENA - 1, stdin);
                strtok(dia, "\n");
                desplegarInformacion(horaInicio, cine, sala, dia);
                break;
            case 3:
                printf("Ingresa el nombre:");
                fgets(nombre, MAXIMA_LONGITUD_CADENA - 1, stdin);
                strtok(nombre, "\n");
                buscarPeliculaPorNombre(nombre);
                break;
            case 4:
                printf("Ingresa el dia en formato YYYY-MM-DD:");
                fgets(dia, MAXIMA_LONGITUD_CADENA - 1, stdin);
                strtok(dia, "\n");
                printf("Ingresa la clasificacion (A, B o C):");
                scanf("%c", &clasificacion);
                buscarPeliculaPorDiaYClasificacion(dia, clasificacion);
                break;
            default:
                printf("Opcion invalida");
                break;
        }
    }
}

Igualmente colocaré aquí una captura de pantalla para mostrarte el programa en ejecución:

Ejercicio resuelto en C – Gestión de películas en cines

Si quieres aprender más sobre C, haz clic aquí.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Entradas recientes

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

3 días hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

3 días hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

3 días hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

3 días hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

3 días hace

Solución: Apache – Server unable to read htaccess file

Ayer estaba editando unos archivos que son servidos con el servidor Apache y al visitarlos…

4 días hace

Esta web usa cookies.