Estructura i operacions per a un rellotge

Més rellotges! Aquesta lliçó mostra com utilitzar una estructura per reunir en una sola variable els tres components hora, minuts, segons de l’hora del dia d’un rellotge.

Definició del tipus

Considereu un rellotge digital, que marca les hores, minuts i segons de l’hora del dia. Tal vegada voldríem desar aquesta informació en un sol lloc i, fer-ho en una estructura com la següent seria una idea ben adient:

struct Hora {
    int h;      // hora  (0..23)
    int m;      // minut (0..59)
    int s;      // segon (0..59)
};

És a dir, l’hora del dia té tres camps: h, m i s que representen, respectivament, les seves hores, minuts i segons. Cada camps és un enter, però als comentaris hem emfatitzat els valors legals que poden tenir cadascun d’ells.

Fixeu-vos que també haguéssim pogut definir una Hora com un vector amb tres enters, però haver-ho fet amb una estructura ho fa molt més segur i explícit, ja que no hi haurà mai errors amb les posicions ni dubtes sobre quin valor hi ha a cada posició.

Operacions

Una primera operació que ens podria ser útil tenir és la d’escriure una hora donada. Per això, escriurem una acció que, donada una Hora, l’escriu en format estàndard, amb dos dígits per camp:

void escriure_hora(const Hora& hora)
{
    if (hora.h < 10) cout << 0;
    cout << hora.h << ':';
    if (hora.m < 10) cout << 0;
    cout << hora.m << ':';
    if (hora.s < 10) cout << 0;
    cout << hora.s << endl;
}

Fixeu-vos que, com que estem passant una estructura com a paràmetre d’entrada, preferim passar-la per referència constant que per valor.

A continuació, podríem tenir una operació que, donada un hora, li afegís un segon. Hi ha dues maneres de fer-ho: amb una acció que té un paràmetre d’entrada-sortida que és modificat o amb una funció que, donada una hora, en retorna una altra. Totes dues són opcions vàlides i la preferència de l’una sobre l’altra depèn del context.

Comencem amb l’acció amb paràmetre d’entrada-sortida:

void incrementar_un_segon(Hora& hora)
{
    ++hora.s;
    if (hora.s == 60) {
        hora.s = 0;
        ++hora.m;
        if (hora.m == 60) {
            hora.m = 0;
            ++hora.h;
            if (hora.h == 24) {
                hora.h = 0;
            }
        }
    }
}

I ara, fem-ho amb una funció:

Hora increment_un_segon(Hora hora)
{
    ++hora.s;
    if (hora.s == 60) {
        hora.s = 0;
        ++hora.m;
        if (hora.m == 60) {
            hora.m = 0;
            ++hora.h;
            if (hora.h == 24) {
                hora.h = 0;
            }
        }
    }
    return hora;
}

Aquesta vegada, hem triat que hora fós un paràmetre per valor, de forma que ja disposem d’una còpia del paràmetre real que podem modificar lliurament sense modificar l’original. Al final, retornem l’hora incrementada.

Així, hem vist com, segons l’ús que en fem, és millor passar una Hora per valor, per referència o per referència constant.

Programa principal

Per acabar, fem un programa que simuli el rellotge, escrivint l’hora corresponent cada segon. Per a fer-ho, utilitzarem els subprogrames anteriors i la funció sleep() disponible a la llibreria <unistd.h> que suspèn l’execució del programa durant tants segons com se li passi per paràmetre.

#include <unistd.h>
...

int main()
{
    Hora hora = {23, 59, 55};
    while (true) {
        escriure_hora(hora);
        sleep(1);                       // esperar un segon
        incrementar_un_segon(hora);
    }
}

El bucle while (true) és un bucle infinit: el programa no acabarà mai. Normalment no volem programes que mai acabin, però, en aquest cas… jo no voldria que el meu rellotge acabés! Piqueu control+c per aturar la seva execució.




Lliçons.jutge.org
Jordi Petit
Universitat Politècnica de Catalunya, 2023

Prohibit copiar. Tots els drets reservats.
No copy allowed. All rights reserved.