7 PAC5
7.1 Quan utilitzar & dins de funcions/accions
De vegades quan fem crides a accions dins d’accions, veiem que si passem un paràmetre amb &
els resultats no són correctes, però en canvi passant el paràmetre sense l’&
tot funciona. I a l’inrevés.
Per tal d’aclarir aquests dubtes utilitzarem el següent exemple: és un programa senzill que treballa amb tipus tPac
. Un element tPac
conté dos atributs: un nom
(cadena de caràcters) i una nota
(decimal). El programa realitza la lectura de valors des de teclat amb l’acció pacRead(...)
, la modificació del nom de la PAC amb nomToUpperCase(...)
, i la seva posterior impressió per pantalla mitjançant pacWrite(...)
.
Amb l’objectiu de deixar-ho tot el més clar possible s’han afegit comentaris extensos dins del programa, explicant en cada situació què es fa i per quin motiu.
/* Exemple CA0701 */
#include <stdio.h>
#include <string.h>
/* Definició de constants */
#define MAX_NOM 5+1
/* Definició de la tupla tPac */
typedef struct {
char nom[MAX_NOM];
float nota;
} tPac;
/* Predeclaració de funcions i accions */
/* Acció que llegeix per teclat els atributs d'un
* tipus tPac i li assigna els valors. En aquest
* cas el paràmetre pac és de classe 'out', donat que
* el seu valor abans i després d'executar l'acció
* haurà canviat. A més, com que el valor inicial
* de pac no ens interessa per res (recordem que
* l'objectiu d'aquesta acció és llegir de teclat
* i donar valor a pac, per tant sobreescriurem
* qualsevol valor previ que tingui), podem
* descartar que sigui de classe 'inout'.
* Quan un paràmetre és de classe out/inout, el
* passem per referència o, el que és el mateix,
* passem un punter a un tipus d'element; com
* es pot veure, aquí pac és un punter a un
* element de tipus tPac, ja que va precedit per *.
* Utilitzem un punter perquè és l'única manera
* que tenim de modificar un element definit
* fora de l'àmbit de l'acció, des de dins de
* la pròpia acció.
*/
void pacRead(tPac *pac);
/* Acció que, donat un tipus tPac, mostra el seu
* contingut (nom i nota) per pantalla. Aquí el
* paràmetre pac és de classe 'in': el seu valor
* abans i després d'executar l'acció no variarà.
* Un paràmetre de classe 'in' el passem per valor:
* en aquest cas és un element de tipus tPac.
* Com es pot veure, no ha d'anar precedit per *.
*/
void pacWrite(tPac pac);
/* Acció que, donat un tipus tPac, agafa el seu
* nom i el passa a majúscules. Per exemple, si
* el nom és "pAc01" el modificarà a "PAC01".
* El paràmetre és de classe 'inout': el seu valor
* abans i després d'executar l'acció haurà canviat
* i a més a més, el valor inicial que té és
* important, ja que el necessitem per calcular el
* valor final ("pAc01" --> "PAC01"). En ser un
* paràmetre de classe 'inout', passarem el seu
* valor per referència: necessitem que pugui ser
* modificat des de dins de l'acció, amb el que
* és necessari treballar amb un punter a l'element
* pac, d'aquí que vagi precedit amb *.
*/
void nomToUpperCase(tPac *pac);
/* Programa principal */
int main(int argc, char **argv) {
/* Definim les variables */
tPac pac1, pac2, pac3;
/* Donem valor als atributs de cadascuna
* de les 3 PAC. Fixeu-vos que estem passant
* punters a elements de tipus tPac: el &
* previ indica que agafem la direcció de
* memòria on resideix l'element de tipus
* tPac. Com que passem punters a memòria,
* des de dins de l'acció podrem modificar
* el contingut de pac1, pac2 i pac3, tot
* i que aquestes tres variables han estat
* definides fora de l'àmbit de l'acció.
*/
pacRead(&pac1);
pacRead(&pac2);
pacRead(&pac3);
/* Mostrem per pantalla els atributs de
* cadascuna de les 3 PAC. En aquest cas
* el pas de paràmetres es fa per valor:
* passem directament els elements de tipus
* tPac, ja que aquests no seran modificats
* des de dins de l'acció (són de classe 'in').
*/
pacWrite(pac1);
pacWrite(pac2);
pacWrite(pac3);
return 0;
}
/* Implementació de funcions i accions */
void pacRead(tPac *pac) {
/* Llegim des de teclat el valor
* corresponent al nom de la PAC
*/
printf("Introdueix nom : ");
scanf("%s", pac->nom);
/* Llegim des de teclat el valor
* corresponent a la nota de la PAC
*/
printf("Introdueix nota: ");
scanf("%f", &pac->nota);
/* Ara arribem en un punt on, dins d'una
* acció, cridem a un altra acció. Hem de
* passar com a atribut pac? o bé &pac?.
* Davant d'aquest dubte, ens hem de
* preguntar quin tipus de valor conté ara
* mateix (abans d'executar la següent acció)
* el paràmetre pac. Si recordem com està
* definida l'acció pacRead(tPac *pac), pac
* és un punter a memòria, ja que va precedit
* per *. Això significa que en aquest precís
* moment pac continua sent un punter.
* D'altra banda, si ens fixem amb la definició
* de l'acció nomToUpperCase(tPac *pac), veiem
* que també espera rebre un punter. Així com
* que pac és un punter i nomToUpperCase(...)
* espera rebre un punter, simplement li passem
* pac com a paràmetre (i no pas &pac!)
*/
nomToUpperCase(pac);
printf("----------------------\n");
}
void pacWrite(tPac pac) {
/* Mostrem per pantalla els valors
* dels atributs de la PAC
*/
printf(">> %s amb nota %.1f \n", pac.nom, pac.nota);
}
void nomToUpperCase(tPac *pac) {
/* Hi ha llibreries que ja implementen els canvis
* a majúscules o minúscules. En aquest cas però
* hem optat per no utilitzar-ne cap, i implementar-la
* nosaltres mateixos, tractant l'string nom de pac
* com a un recorregut caràcter a caràcter.
*/
int i;
for (i = 0; pac->nom[i] != '\0'; i++) {
if (pac->nom[i] >= 'a' && pac->nom[i] <= 'z') {
pac->nom[i] = pac->nom[i] + ('A' - 'a');
}
}
}
7.2 Multiple definition of NOM_CONSTANT
Quan utilitzem constants definides amb const
en un programa modulat es pot obtenir l’error multiple definition of NOM_CONSTANT
.
Per exemple: tenim el següent programa modulat en tres arxius, dni.h
dni.c
main.c
, que calcula la lletra que li correspon a un DNI.
El contingut de dni.h
és:
const char CODI[] = "TRWAGMYFPDXBNJZSQVHLCKE";
const int DENOMINADOR = 23;
/* Predeclaració de les funcions/accions */
int llegeix();
char calculaLletra(int numero);
void mostrar(int numero, char lletra);
El contingut de dni.c
és:
#include <stdio.h>
#include "dni.h"
/* Implementació de les funcions/accions */
int llegir() {
int dni;
printf("Tecleja un DNI (sense lletra): ");
scanf("%d", &dni);
return dni;
}
char calcularLletra(int numero) {
int resultat;
resultat = numero % DENOMINADOR;
return CODI[resultat];
}
void mostrar(int numero, char lletra) {
printf("El DNI amb lletra és: %d-%c \n", numero, lletra);
}
El contingut de main.c
és:
/* Exemple CA0702 */
#include "dni.h"
/* Codi principal */
int main(int argc, char **argv) {
int dni;
char lletra;
dni = llegir();
lletra = calcularLletra(dni);
mostrar(dni, lletra);
return 0;
}
Si executem el programa, retornarà els següents errors:
#include "dni.h"
... dni.h:3: multiple definition of `CODI'
... dni.h:3: first definition here
... dni.h:4: multiple definition of `DENOMINADOR'
... dni.h:4: first definition here
L’error està causat perquè es fa l’include de dni.h
a dos punts diferents del programa:
- A l’arxiu
dni.c
, per poder utilitar les constants dedni.h
. - A l’arxiu
main.c
, per poder utilitzar les accions i funcions predeclarades adni.h
.
Aquest fet intenta definir en memòria dues vegades la constant CODI
i dues més la constant DENOMINADOR
, una situació que no és possible: no es permet tenir múltiples constants definides amb el mateix nom en un mateix àmbit.
Per solucionar l’error tenim dues opcions:
Opció 1:
Utilitzar #define
en comptes de const
. Canviant d’aquesta forma la definició de les constants a l’arxiu dni.h
se soluciona l’error:
/* Exemple CA0703 */
#define CODI "TRWAGMYFPDXBNJZSQVHLCKE"
#define DENOMINADOR 23
/* Predeclaració de les funcions/accions */
int llegeix();
char calculaLletra(int numero);
void mostrar(int numero, char lletra);
Opció 2:
L’opció static
permet modificar l’àmbit de la constant, passant de ser una constant de classe a una constant d’arxiu, impedint d’aquesta manera que hi hagin duplicats en l’àmbit global del programa. Per tant, podem solucionar l’error afegir static
a la definició de les constants amb const
dins de l’arxiu dni.h
.
/* Exemple CA0704 */
static const char CODI[] = "TRWAGMYFPDXBNJZSQVHLCKE";
static const int DENOMINADOR = 23;
/* Predeclaració de les funcions/accions */
int llegeix();
char calculaLletra(int numero);
void mostrar(int numero, char lletra);
7.3 Tipus de paràmetres en accions i funcions
En les accions els paràmetres poden ser de classe in
, out
o inout
. Cal especificar-ho en el moment de definir l’acció al nostre algorisme.
Exemple: tres formes d’implementar una suma de dos enters amb diferents accions segons els classes in
, out
o inout
dels paràmetres:
action suma1(in num1: integer, in num2: integer)
var
resultat: integer;
end var
resultat := num1 + num2;
writeString("Resultat de la suma = ");
writeInteger(resultat);
end action
action suma2(in num1: integer, in num2: integer, out resultat: integer)
resultat := num1 + num2;
end action
action suma3(inout num1: integer, in num2: integer)
num1 := num1 + num2;
end action
A les funcions, en canvi, tots els paràmetres són d’entrada i, per tant, no cal indicar l’in
.
Exemple:
function suma4(num1: integer, num2: integer): integer
var
resultat: integer;
end var
resultat := num1 + num2;
return resultat;
end function
7.4 Pas per valor vs pas per referència
El clàssic pas per valor correspon als paràmetres de tipus in
, en els quals passem la variable/valor.
D’altra banda, el pas per referència consisteix a passar com a paràmetre de tipus out
o inout
la direcció de memòria de la variable (punter).
7.5 Exemple: capgirarParaula
Imaginem que tenim una tupla tParaula
que té dos camps:
cadena
: conté l’string amb el valor de latParaula
.numeroCaractersCadena
: conté el número de caràcters de la cadena.
Implementem l’acció capgirar()
, que fa dues operacions:
- Capgira el camp cadena de la
tParaula
; per exemple, si entrem “Fonaments” el resultat serà “stnemanoF”. - Calcula el valor de
numeroCaractersCadena
; si tenim com a cadena “Fonaments”, el valor serà 9.
Volem que per teclat es demani el valor pel camp cadena
de dues tParaula
, i en totes dues volem aplicar l’acció capgirar()
. Una possible forma d’implementar-ho tot plegat seria la següent:
/* Exemple CA0705 */
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#define MAX_CHAR 20+1
#define MAX_PARAULES 2
typedef struct {
char cadena[MAX_CHAR];
int numeroCaractersCadena;
} tParaula;
/* Predeclaració de l'acció.
* Aquesta acció reb un paràmetre inout de tipus tParaula,
* el qual capgira el camp cadena, i calcula el valor
* corresponent pel camp numeroCaractersCadena
*/
void capgirar(tParaula *mot);
int main(int argc, char **argv) {
int i;
/* Introduim per teclat un total de MAX_PARAULES */
for (i = 0; i < MAX_PARAULES; i++) {
tParaula paraula;
printf("Introdueix una paraula : ");
scanf("%s", paraula.cadena);
capgirar(¶ula);
printf("La paraula capgirada és : %s, de %d lletres.\n",
paraula.cadena, paraula.numeroCaractersCadena);
}
}
/* Implementació de l'acció */
void capgirar(tParaula *mot) {
tParaula motCapgirat;
int midaMot;
int i;
midaMot = strlen(mot->cadena);
for (i=0; i<midaMot; i++ ) {
motCapgirat.cadena[(midaMot-1)-i] = mot->cadena[i];
}
/* Indiquem el finalitzador de l'string */
motCapgirat.cadena[midaMot] ='\0';
strcpy(mot->cadena, motCapgirat.cadena);
mot->numeroCaractersCadena = midaMot;
}
L’acció només rep un paràmetre tParaula
, ja que únicament s’executa sobre una tParaula
. Com que la volem executar per a cadascuna de les dues tParaula
, repetim la crida dues vegades dins del bucle, una per cadatParaula
.
7.6 Exemple: isParell
Exemple de funció que retorna un booleà:
/* Exemple CA0706 */
#include <stdio.h>
#include <stdbool.h>
/* Predeclaració de la funció isParell, la qual retorna un
* booleà que indica si el número passat per paràmetre és
* parell (true) o no (false).
*/
bool isParell(int numero);
int main(int argc, char **argv) {
int numero;
printf("Tecleja un número : ");
scanf("%d", &numero);
if (!isParell(numero)) {
printf("El número %d és senar.\n", numero);
} else {
printf("El número %d és parell.\n", numero);
}
}
/* Implementació de la funció */
bool isParell(int numero) {
bool resultat;
if (numero % 2 == 0) {
resultat = true;
} else {
resultat = false;
}
return resultat;
/* L'estructura condicional anterior es pot
* substituir per la següent expressió equivalent:
* return (numero % 2 == 0);
*/
}
7.7 Exemple: pivotDefensiuTirsLliures
S’afegeix a l’exemple previ pivotDefensiva un nou factor de comparació: en cas d’empat de les comparacions anteriors, escollirem la que tingui un millor percentatge de tirs lliures.
/* Exemple CA0707 */
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
/* Rebem una petició d'un equip femení de bàsquet,
* en el qual ens demanen un programa que els permeti
* seleccionar la millor pivot defensiu d'entre una
* sèrie de candidates.
* La millor pivot defensiu és aquella que captura
* més rebots; en cas d'empat, s'escollirà la que
* faci més taps. En cas d'empat ens interessarà
* escollir la que tingui millor percentatge
* de tirs lliures.
* Caldrà implementar 3 accions i 2 funcions:
* - acció llegirJugadora(j): llegeix de teclat i
* guarda tots els atributs de la jugadora a la
* tupla j.
* - acció mostrarJugadora(j): mostra per pantalla
* el valor dels atributs de la tupla j.
* - acció copiarJugadores(j1, j2): copia el valor
* de tots els atributs de j2 cap a j1.
* - funció compararJugadores(j1, j2): retorna -1 en
* cas que la millor pivot sigui j1, i 1 en cas
* que la millor sigui j2.
* - funció percentatgeTirsLliures(intentats, encertats):
* retorna el percentatge d'encert en tirs lliures
* en funció dels valors passats per paràmetre.
*/
#define MAX_NOM 20+1
#define MAX_COGNOM 20+1
#define MAX_JUGADORES 3
typedef struct {
char nom[MAX_NOM];
char cognom[MAX_COGNOM];
float rebots;
float taps;
float tirsLliures; /* en percentatge */
} tJugadora;
/* Predeclaracions */
void llegirJugadora(tJugadora *j);
void mostrarJugadora(tJugadora j);
void copiarJugadora(tJugadora *desti, tJugadora origen);
int compararJugadores(tJugadora j1, tJugadora j2);
float percentatgeTirsLliures(int intentats, int encertats);
/* Programa principal */
int main(int argc, char **argv) {
tJugadora vJugadores[MAX_JUGADORES];
int i, resultat;
/* Es crea la tJugadora fictícia
* millorPivot que ens ajudarà a trobar
* la millor opció d'entre totes les
* candidates
*/
tJugadora millorPivot;
millorPivot.rebots = 0;
millorPivot.taps = 0;
millorPivot.tirsLliures = 0.0;
/* Llegim totes les jugadores amb
* l'acció llegirJugadora(). Aquesta
* acció rep un paràmetre de sortida
* (out), el qual contindrà la
* jugadora llegit per teclat. Com que
* es tracta d'un paràmetre de tipus
* out, es realitzarà un pas per
* referència (= passarem un punter)
*/
for (i=0; i<MAX_JUGADORES; i++) {
llegirJugadora(&vJugadores[i]);
}
/* Mostrem per pantalla quina
* és la millor jugadora amb perfil
* pivot defensiu. La idea és anar
* recorrent una a una les jugadores
* del vector i comparar-les amb millorPivot:
* 1. Si la jugadora del vector és millor
* que millorPivot, copiarem les dades
* de la jugadora cap a millorPivot.
* 2. Si millorPivot és millor que la
* jugadora del vector, no farem res.
* En finalitzar el recorregut de totes
* les jugadores del vector, tindrem que
* millorPivot contindrà la jugadora
* que estem buscant.
* */
for (i=0; i<MAX_JUGADORES; i++) {
resultat = compararJugadores(millorPivot, vJugadores[i]);
if (resultat != -1) {
copiarJugadora(&millorPivot, vJugadores[i]);
}
}
printf("\nMillor opció com a pivot defensiu : ");
mostrarJugadora(millorPivot);
return 0;
}
/* Implementació de les accions */
void llegirJugadora(tJugadora *j) {
int intentats;
int encertats;
printf("Introdueix les dades de la nova jugadora: \n");
printf("\tNom: ");
scanf("%s", j->nom);
printf("\tCognom: ");
scanf("%s", j->cognom);
printf("\t>> Promigs per partit:\n");
printf("\tRebots: ");
scanf("%f", &j->rebots);
printf("\tTaps: ");
scanf("%f", &j->taps);
printf("\tTirs lliures intentats: ");
scanf("%d", &intentats);
printf("\tTirs lliures encertats: ");
scanf("%d", &encertats);
j->tirsLliures = percentatgeTirsLliures(intentats, encertats);
}
void mostrarJugadora(tJugadora j) {
printf("\n%s, %s: %.1f rebots, %.1f taps, %.1f%% tirs lliures \n",
j.cognom, j.nom, j.rebots, j.taps, j.tirsLliures);
}
void copiarJugadora(tJugadora *desti, tJugadora origen) {
/* Recordem:
* - si el paràmetre és un punter, accedirem als
* atributs amb '->'
* - si el paràmetre és un valor, accedirem als
* atributs amb '.'
*/
strcpy(desti->nom, origen.nom);
strcpy(desti->cognom, origen.cognom);
desti->rebots = origen.rebots;
desti->taps = origen.taps;
desti->tirsLliures = origen.tirsLliures;
}
int compararJugadores(tJugadora j1, tJugadora j2) {
/* Estem buscant una jugadora que
* tingui un perfil de pivot defensiu,
* amb el que agafarem:
* 1. Aquella que tingui més rebots per partit
* 2. En cas d'empat de rebots, aquella que
* faci més taps per partit
* 3. En cas d'empat, la que tingui millor
* percentatge de tirs lliures
*/
int resultat;
resultat = 0;
if (j1.rebots > j2.rebots) {
resultat = -1;
} else {
if (j1.rebots < j2.rebots) {
resultat = 1;
} else {
/* En aquest punt tenim que
* j1.rebots == j2.rebots,
* amb el que anem a comparar el següent
* atribut segons la prioritat definida
* del perfil pivot defensiu
*/
if (j1.taps > j2.taps) {
resultat = -1;
} else {
if (j1.taps < j2.taps) {
resultat = 1;
} else {
/* Afegim la variant de valorar
* el percentatge de tirs lliures
*/
if (j1.tirsLliures >= j2.tirsLliures) {
resultat = -1;
} else {
resultat = 1;
}
}
}
}
}
return resultat;
}
float percentatgeTirsLliures(int intentats, int encertats) {
return ((float)encertats/intentats)*100.0;
}
7.8 Exemple: IMC
Imaginem que volem fer un programa que ens calculi l’IMC (índex de massa corporal) d’una persona. El programa tindrà dues accions i una funció:
- llegirDades(): acció que rebrà 2 paràmetres de classe
out
, el pes i l’alçada de la persona. - calcularIMC(): funció que rebrà 2 paràmetres de classe
in
, el pes i l’alçada, i retornarà un valor decimal. - mostrarIMC(): acció que rebrà 1 paràmetre de classe
in
, el valor de l’IMC, i el mostrarà per pantalla.
En primer lloc, dissenyem l’algorisme:
action llegirDades(out pes: real, out alcada: real)
writeString("Introdueix el pes (kg): ");
pes := readReal();
writeString("Introdueix l'alçada (m): ");
alcada := readReal();
end action
function calcularIMC(pes: real, alcada: real): real
var
imc: real;
end var
imc := pes / (alcada * alcada);
return imc;
end function
action mostrarIMC(in imc: real)
writeString("IMC = ");
writeReal(imc);
end action
algorithm IMC
var
pes: real;
alcada: real;
resultat: real;
end var
llegirDades(pes, alcada);
resultat := calcularIMC(pes, alcada);
mostrarIMC(resultat);
end algorithm
A continuació fem la conversió de l’algorisme a llenguatge C. S’han afegit explicacions com a comentaris perquè es vegi clarament el tipus de paràmetres passats (punter o valor) segons la seva classe:
/* Exemple CA0708 */
#include <stdio.h>
/* Predeclaració de funcions i accions */
/* Els paràmetres pes i alcada de l'acció
* llegirDades són de classe out, amb el que
* els precedim amb * (ens indica que són
* punters).
*/
void llegirDades(float *pes, float *alcada);
/* Els paràmetres pes i alcada de la funció
* calcularIMC són de classe in, com tots
* els paràmetres de les funcions.
*/
float calcularIMC(float pes, float alcada);
/* El paràmetre imc de l'acció mostrarIMC
* és de classe in.
*/
void mostrarIMC(float imc);
int main(int argc, char **argv) {
/* Definició de les variables */
float pes;
float alcada;
float resultat;
/* A l'acció llegirDades() li passem els punters
* de les variables pes i alcada,
* per tal que el seu valor pugui ser modificat
* des de dins de l'acció. Són paràmetres de
* classe out.
*/
llegirDades(&pes, &alcada);
/* En el cas de la funció calcularIMC() i l'acció
* mostrarIMC(), en ser tots els paràmetres de
* classe in, els passem per valor.
*/
resultat = calcularIMC(pes, alcada);
mostrarIMC(resultat);
return 0;
}
/* Implementació de funcions i accions */
/* L'acció llegirDades s'encarrega de llegir
* des de teclat el pes i l'alçada d'una
* persona, i assigna el valor als paràmetres
* pes i alcada. Fixeu-vos que tant pes com
* alcada són punters (van precedits amb *),
* amb el que quan fem l'scanf ja no cal
* afegir el prefix &.
*/
void llegirDades(float *pes, float *alcada) {
printf("Introdueix el pes (kg): ");
scanf("%f", pes);
printf("Introdueix l'alçada (m): ");
scanf("%f", alcada);
}
/* Funció que realitza el càlcul de l'IMC */
float calcularIMC(float pes, float alcada) {
float imc;
imc = pes / (alcada*alcada);
return imc;
}
/* Acció que mostra per pantalla el valor
* que conté el paràmetre imc, de classe in.
*/
void mostrarIMC(float imc) {
printf("IMC = %.1f \n", imc);
}
A continuació es mostra un exemple d’execució del programa:
Introdueix el pes (kg): 56
Introdueix l'alçada (m): 1.69
IMC = 19.6
7.9 Exemple: mitjanaNotes
Volem un programa que ens calculi la nota mitjana de 3 PAC. La nota de cada PAC l’anem entrant per teclat i ha de ser un valor entre [0..10]. En cas que alguna de les notes no pertanyi a aquest rang, volem que el programa mostri un missatge d’error i finalitzi.
En aquest cas no volem que el bucle es limiti a fer les n-iteracions corresponents: volem que, donada una situació concreta, puguem sortir del bucle. Ho podem aconseguir afegint una variable booleana a la condició d’entrada del bucle (en el cas d’aquest exemple, isValorCorrecte
).
Una possible implementació del programa en llenguatge C és la següent:
/* Exemple CA0709 */
#include <stdio.h>
#include <stdbool.h>
#define NUM_PACS 3
int main(int argc, char **argv) {
float nota;
float sumaNotes;
bool isValorCorrecte;
int i;
isValorCorrecte = true;
sumaNotes = 0.0;
i = 0;
/* S'utilitza un bucle while que té dues
* condicions de finalització:
* - que hagi fet totes les iteracions
* possibles (valor indicar per NUM_PACS).
* - que detecti que la nota teclejada
* no pertanyi al rang [0..10].
*/
while (i<NUM_PACS && isValorCorrecte) {
printf("Nota PAC%d: ", i + 1);
scanf("%f", ¬a);
/* Si la nota introduïda està fora del
* rang [0..10], modifiquem el valor
* de la variable booleana isValorCorrecte
* a false. Això provocarà que la condició
* d'entrada al bucle sigui false i, per
* tant, sortirem d'ell.
*/
if (nota < 0.0 || nota > 10.0) {
isValorCorrecte = false;
/* Si el valor de la nota és correcte,
* continuem fent les operacions corresponents.
*/
} else {
sumaNotes = sumaNotes + nota;
i = i + 1;
}
}
/* Si no s'ha detectat cap error en les notes
* significarà que el valor de isValorCorrecte continua
* sent true, amb el que mostrarem el resultat de la
* mitjana per pantalla.
*/
if (isValorCorrecte) {
printf("Mitjana = %.2f \n", sumaNotes / (float)NUM_PACS);
/* En cas contrari, mostrem el missatge d'error. */
} else {
printf("Error: el valor de la nota és incorrecte! \n");
}
return 0;
}
Un exemple d’execució sense errors:
Nota PAC1: 9.0
Nota PAC2: 10.0
Nota PAC3: 8.4
Mitjana = 9.13
Un exemple d’execució amb error:
Nota PAC1: 9.3
Nota PAC2: 12
Error: el valor de la nota és incorrecte!