Aplicació: Més rellotges
Aquesta lliçó tornar a explorar com descompondre un determinat nombre de segons en hores, minuts i segons, i com incrementar d’un segon l’hora d’un rellotge. En ambdós casos, s’utilitzen accions amb paràmetres per referència.
A partir d’aquests exemples, aquesta lliçó també desenvolupa una exposició sobre les diferents direccions dels paràmetres (d’entrada, de sortida o d’entrada-i-sortida) i els relaciona amb els passos per valor i per referència.
Descomposició horària
Considereu el problema següent: Donada una quantitat (positiva) de segons n
,
es vol saber quantes hores, minuts i segons representa. Per exemple, si n
val 3661,
cal dir que en 3661 segons hi ha una hora, un minut i un segon. També, si n
val 76234, cal dir que en 76234 segons hi ha 21 hores, 10 minuts i 34 segons.
Aquest problema ja l’havíem tractat però ara l’enfoquem des del punt de vista dels subprogrames.
Per tal d’abstreure la tasca de trobar quantes hores, minuts i segons representa un determinat nombre de segons, utilitzarem un subprograma. En aquest subprograma li haurem de proporcionar el nombre total de segons. Com a resultat, aquest subprograma ens calcularà el nombre d’hores, minuts i segons corresponents.
Aquesta feina sembla ideal per a ser codificada en una funció però, malauradament, les funcions de C++ només poden retornar un únic valor, i no tres com ens cal aquí. Per tant, recorrerem a una acció. Aquesta acció tindrà la capçalera següent:
void descomposicio_horaria(int n, int& h, int &m, int& s)
La seva especificació és que, donat un nombre de segons positius n
, aquesta
acció desa en h
, m
i s
el nombre d’hores, minuts i segons que representa
n
(amb m
i s
entre 0 i 59).
El seu cos no és altra cosa que la reiteració del que ja havíem escrit quan vam començar a programar, aquest cop, encapsulat dins d’una acció:
void descomposicio_horaria(int n, int& h, int &m, int& s) {
h = n/3600; // Càlcul del nombre d'hores
m = (n%3600)/60; // Càlcul del nombre de minuts
s = n%60; // Càlcul del nombre de segons
}
Fixeu-vos que l’acció no realitza operacions d’entrada ni de sortida. La seva
entrada conceptual n
es transmet a través d’un paràmetre per valor. Les
seves sortides conceptuals h
, m
i s
es transmeten a través de tres
paràmetres per referència.
El programa principal per provar aquesta acció sí que es podria encarregar de l’entrada-sortida:
int main() {
// llegir entrada
int n;
cin >> n;
// descompondre n en h, m i s
int h, m, s;
descomposicio_horaria(n, h, m, s);
// escriure la sortida
cout << h << ' ' << m << ' ' << s << endl;
}
Suma d’un segon
Considereu ara el problema següent: Donada un hora (amb el seu nombre d’hores,
de minuts i de segons), es vol sumar un segon a aquesta hora. Així, donada
l’hora 14 9 59
, es voldria obtenir l’hora 14 10 0
.
Aquest problema també l’havíem tractat però ara l’enfoquem de nou des del punt de vista dels subprogrames.
Per tal d’abstreure la tasca de sumar un segon, utilitzarem una acció. Aquesta acció rebrà tres paràmetres per referència que representen l’hora actual i els modificarà per tal que representin aquella hora un segon més tard. Aquesta acció tindrà doncs la capçalera següent:
void sumar_un_segon(int& h, int &m, int& s)
Com a precondició, aquesta acció pressuposa que els valors de h
, m
i s
són legals (és a dir, amb m
i s
entre 0 i 59 i h
entre 0 i 23).
El cos d’aquesta acció no és altra cosa que la reiteració del que ja havíem escrit quan vam començar a programar, aquest cop, encapsulat dins d’una acció:
void sumar_un_segon(int& h, int &m, int& s) {
++s;
if (s == 60) {
s = 0;
++m;
if (m == 60) {
m = 0;
++h;
if (h == 24) {
h = 0;
}
}
}
}
De nou, fixeu-vos que l’acció no realitza operacions d’entrada ni de sortida. El pas de paràmetres permet intercanviar la informació necessària al fer la crida.
El programa principal per provar aquesta acció sí que es podria encarregar de l’entrada-sortida:
int main() {
// lectura de l'hora
int h, m, s;
cin >> h >> m >> s;
// increment d'un segon
sumar_un_segon(h, m, s);
// escriptura del resultat
cout << h << ' ' << m << ' ' << s << endl;
}
Exercici
Als dos problemes anteriors hem escrit el resultat (una hora) sense cap tipus de format bonic. Definiu una acció per escriure una hora fent que els seus elements es separin amb ‘:’ i que els minuts i segons sempre s’escriguin amb dos dígits exactament.
Modes de pas de paràmetres: entrada, sortida i entrada-i-sortida
Tal com hem vist a la lliçó anterior, C++ ofereix dos modes per passar paràmetres:
- pas per valor
- pas per referència.
(Més endavant en veurem alguna variació menor.)
Per saber quan cal utilitzar l’un i l’altre és convenient pensar sobre el significat dels paràmetres i la direcció que tenen entre l’acció invocadora i l’acció invocada:
Quan l’acció invocadora ha de passar certa informació a l’acció invocada, aquella informació té una direcció d’entrada.
Quan l’acció invocada ha de passar certa informació a l’acció invocadora, aquella informació té una direcció de sortida.
Un informació té una direcció d’entrada-i-sortida si té direcció d’entrada i direcció de sortida.
El diagrama següent resumeix aquestes direccions:
Lliçons.jutge.org
Jordi Petit, Salvador Roura
Universitat Politècnica de Catalunya, 2023
Prohibit copiar. Tots els drets reservats.
No copy allowed. All rights reserved.