8 PR3
8.1 Com inicialitzar una taula
Per inicialitzar/esborrar una taula únicament ens cal indicar que el nombre d’elements que conté és 0.
La pregunta que ens podem fer és “simplement inicialitzant a 0 aquest atribut és suficient?”. La resposta és afirmativa: l’atribut que conté el nombre d’elements d’una taula sempre és l’utilitzat a l’hora de recórrer una taula, ja que ens indica quin és l’últim element de la taula. De la mateixa manera, quan inserim un element incrementarem en 1 el seu valor.
Què passa quan li donem valor 0? Estem indicant que la taula té 0 elements, amb la qual cosa quan n’hi afegim un de nou ho farem a la primera posició, sobreescrivint tot el que prèviament hi pogués haver en memòria.
8.2 Exemple: calcularNota
S’ha d’entendre una taula com un conjunt d’elements dels quals sabem en tot moment quants en tenim.
Imaginem que volem fer un programa que calculi la nota mitjana de les PAC d’una assignatura. Podríem plantejar-ho com un simple array d’enters, però com que ens agrada poder donar més funcionalitats en un futur al nostre programa, tindrem el següent escenari:
tPac
: serà el tipus de dades bàsic que tractarà el nostre programa. Aquesta tupla estarà formada d’una banda per un nom descriptiu de la PAC, i d’altra banda per la seva nota numèrica amb decimals.tAssignatura
: taula que contindrà elements de tipustPac
. A part d’aquest array detPac
, també tindrà un comptador intern d’elements:numPacs
.
Sobre aquesta base realitzarem dues accions:
afegirPac()
: es tracta d’una acció que inclou un element de tipustPac
dins de la taulatAssignatura
. És una operació similar a l’acció d’omplir una taula dels exemples de la xWiki.calcularNota()
: és una funció que revisa tots els elementstPac
de la taulatAssignatura
i en calcula la nota mitjana. Es tracta d’una operació equivalent a la dels recorreguts de taula dels exemples de la xWiki, ja que estem recorrent un a un tots els elementstPac
per obtenir la seva nota.
Una possible forma d’implementar-ho seria la següent:
/* Exemple CA0801 */
#include <stdio.h>
#include <string.h>
/* Definició de constants */
#define MAX_PACS 5
#define MAX_NOM 5+1
/* Definició de la tupla tPac */
typedef struct {
char nom[MAX_NOM];
float nota;
} tPac;
/* Definició de taula tAssignatura */
typedef struct {
tPac pac[MAX_PACS];
int numPacs;
} tAssignatura;
/* Predeclaració de funcions/accions */
/* Acció que afegeix un element de tipus tPac a la taula tAssignatura */
void afegirPac(tAssignatura *assignatura, tPac pac);
/* Funció que calcula la mitjana de totes les tPac que conté la taula
* tAssignatura
*/
float calcularNota(tAssignatura assignatura);
/* Programa principal */
int main(int argc, char **argv) {
/* Definim les variables */
tAssignatura fp;
tPac pac1, pac2, pac3;
float nota;
/* Inicialitzem les variables */
nota = 0;
strcpy(pac1.nom,"PAC01");
pac1.nota = 10;
strcpy(pac2.nom,"PAC02");
pac2.nota = 8.5;
strcpy(pac3.nom,"PAC03");
pac3.nota = 7.5;
/* La inicialització de la taula es fa simplement
* posant a 0 el seu comptador
*/
fp.numPacs = 0;
/* Afegim les pacs a l'assignatura, que és una taula
* d'elements de tipus tPac
*/
afegirPac(&fp, pac1);
afegirPac(&fp, pac2);
afegirPac(&fp, pac3);
/* Calculem la nota amb la funció calcularNota */
nota = calcularNota(fp);
printf("La nota mitjana de les %d PAC és %f\n", fp.numPacs, nota);
return 0;
}
/* Implementació funcions/accions */
void afegirPac(tAssignatura *assignatura, tPac pac) {
/* numPacs conté el número d'elements de tipus tPac
* de la taula
*/
assignatura->pac[assignatura->numPacs] = pac;
/* Una vegada hem assignat un element nou tPac a la taula,
* incrementem el valor de numPacs
*/
assignatura->numPacs = assignatura->numPacs + 1;
}
float calcularNota(tAssignatura assignatura) {
/* La variable suma conté el sumatori de totes
* les notes de les tPac que estan dins de la taula
* tAssignatura
*/
float suma;
int i;
suma = 0.0;
/* Es recorren tots els elements tPac de tAssignatura
* per tal d'obtenir la seva nota i acumular-les a la
* variable suma
*/
for (i = 0; i < assignatura.numPacs; i++) {
suma = suma + assignatura.pac[i].nota;
}
/* Per calcular la mitjana es divideix el sumatori de
* notes pel total d'elements de la taula tAssignatura
*/
return suma/assignatura.numPacs;
}
Per facilitar-ne la lectura s’ha unit tot el programa en un únic bloc de codi (un únic arxiu).
8.3 Exemple: calcularNota amb iteració
Adaptem l’exemple anterior per tal que demani els valors iterativament:
/* Exemple CA0802 */
#include <stdio.h>
#include <string.h>
/* Definició de constants */
#define MAX_PACS 10
#define MAX_NOM 10+1
/* Definició de la tupla tPac */
typedef struct {
char nom[MAX_NOM];
float nota;
} tPac;
/* Definició de taula tAssignatura */
typedef struct {
tPac pac[MAX_PACS];
int numPacs;
} tAssignatura;
/* Definició funcions/accions */
/* Acció que afegeix un element de tipus tPac a la taula tAssignatura */
void afegirPac(tAssignatura *assignatura, tPac pac);
/* Funció que calcula la mitjana de totes les tPac que conté la taula
* tAssignatura
*/
float calcularNota(tAssignatura assignatura);
/* Programa principal */
int main(int argc, char **argv) {
/* Definim les variables */
tAssignatura fp;
float nota;
int numPacs, i;
/* Inicialitzem les variables */
nota = 0;
numPacs = 0;
i = 0;
/* Inicialitzem la taula */
fp.numPacs = 0;
/* Introduim ara les dades de les PAC des de teclat */
printf("Número de PACs a introduir (<%d): ", MAX_PACS);
scanf("%d", &numPacs);
for (i = 0; i < numPacs; i++) {
tPac pacAux;
printf("Dades de la PAC0%d : \n", i+1);
printf("\tNom : ");
scanf("%s", pacAux.nom);
printf("\tNota : ");
scanf("%f", &pacAux.nota);
/* Afegim a la taula la tPac auxiliar utilitzada
* dins del bucle. En cada iteració es construirà
* i s'afegirà una tPac diferent
*/
afegirPac(&fp, pacAux);
}
/* Calculem la nota amb la funció calcularNota */
nota = calcularNota(fp);
printf("La nota mitjana de les %d PAC és %f\n", fp.numPacs, nota);
return 0;
}
/* Implementació funcions/accions */
void afegirPac(tAssignatura *assignatura, tPac pac) {
/* numPacs conté el número d'elements de tipus tPac
* que conté la taula en cada moment
*/
assignatura->pac[assignatura->numPacs] = pac;
/* Una vegada hem assignat un element nou tPac a la taula
* incrementem el valor de numPacs
*/
assignatura->numPacs = assignatura->numPacs + 1;
}
float calcularNota(tAssignatura assignatura) {
/* La variable suma conté el sumatori de totes
* les notes de les tPac que estan dins de la taula
* tAssignatura
*/
float suma;
int i;
suma = 0.0;
/* Es recorren tots els elements tPac de tAssignatura
* per tal d'obtenir la seva nota i acumular-les a la
* variable suma
*/
for (i = 0; i < assignatura.numPacs; i++) {
suma = suma + assignatura.pac[i].nota;
}
/* Per calcular la mitjana es divideix el sumatori de
* notes pel total d'elements de la taula tAssignatura
*/
return suma/assignatura.numPacs;
}
8.4 Exemple: recorregut vs cerca
Al següent exemple es tracten els conceptes de recorregut i de cerca dels elements d’una taula. Dins del codi s’han afegit comentaris detallats per tal que cada pas quedi explicat.
/* Exemple CA0803 */
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
/* Ens demanen un programa que permeti registrar
* jugadores de bàsquet dins d'una taula. En una
* mateixa taula tindrem tant les jugadores locals
* com les visitants. Sobre elles hi realitzarem
* un recorregut, consistent en mostrar-les totes
* per pantalla, i també una cerca, on a partir
* de l'equip i el dorsal mostrarem per pantalla
* la jugadora en cas d'existir.
* Ens caldrà implementar les següents accions:
* - inicialitzarTaula(...): per inicialitzar la
* taula de jugadores.
* - afegirJugadora(...) : per afegir una
* jugadora a una taula.
* - mostrarJugadores(...) : per mostrar per
* pantalla totes les jugadores de la taula.
* - cercarJugadora(...) : per buscar dins de la
* taula la jugadora que tingui un equip i
* un dorsal determinat.
*/
#define MAX_NOM 20+1
#define MAX_COGNOM 20+1
#define MAX_JUGADORES 10
typedef enum {LOCAL, VISITANT} tEquip;
typedef struct {
char nom[MAX_NOM];
char cognom[MAX_COGNOM];
int dorsal;
tEquip equip;
} tJugadora;
/* Definició del tipus taula de
* jugadores; com es pot veure, tal i
* com s'indica a les xWiki, únicament
* està formada per un vector i un
* comptador de les jugadores que conté.
*/
typedef struct {
tJugadora jugadores[MAX_JUGADORES];
int nJugadores;
} tTaulaJugadores;
/* Predeclaracions */
void llegirJugadora(tJugadora *j);
void mostrarJugadora(tJugadora j);
void copiarJugadora(tJugadora *desti, tJugadora origen);
void inicialitzarTaula(tTaulaJugadores *taula);
void afegirJugadora(tTaulaJugadores *taula, tJugadora j);
void mostrarJugadores(tTaulaJugadores taula);
void cercarJugadora(tTaulaJugadores taula, int dorsal, tEquip equip);
/* Programa principal */
int main(int argc, char **argv) {
tJugadora jugadora;
tTaulaJugadores taula;
tEquip equip;
int dorsal, i;
/* Per inicialitzar una taula simplement
* posem el comptador d'elements a 0. Com
* que la inserció de jugadores a la taula
* té present aquest comptador, sobreescriurà
* qualsevol altre valor que existís en
* aquesta mateixa posició.
*/
inicialitzarTaula(&taula);
/* Demanem les jugadores per teclat i tot
* seguit les anem afegint a la taula.
*/
for (i=0; i<MAX_JUGADORES; i++) {
llegirJugadora(&jugadora);
afegirJugadora(&taula, jugadora);
}
/* Es recorren tots els elements
* de la taula de jugadores per
* tal d'imprimir les dades per
* pantalla
*/
mostrarJugadores(taula);
printf("\nQuina jugadora vols cercar? : ");
printf("\n>> Equip (0=LOCAL, 1=VISITANT) : ");
scanf("%u", &equip);
printf(">> Dorsal : ");
scanf("%d", &dorsal);
/* Es fa una cerca entre totes les
* jugadores de la taula, de forma que
* mostrarà per pantalla el resultat
* obtingut; si no se'n troba cap,
* retorna un missatge informatiu.
*/
cercarJugadora(taula, dorsal, equip);
return 0;
}
/* Implementació de les accions */
void llegirJugadora(tJugadora *j) {
printf("Introdueix les dades de la nova jugadora: \n");
printf("\tNom: ");
scanf("%s", j->nom);
printf("\tCognom: ");
scanf("%s", j->cognom);
printf("\tEquip (0=LOCAL, 1=VISITANT): ");
scanf("%u", &j->equip);
printf("\tDorsal: ");
scanf("%d", &j->dorsal);
}
void mostrarJugadora(tJugadora j) {
if (j.equip == LOCAL) {
printf("LOCAL : %d %s,%s\n", j.dorsal, j.cognom, j.nom);
} else {
printf("VISITANT: %d %s,%s\n", j.dorsal, j.cognom, j.nom);
}
}
void copiarJugadora(tJugadora *desti, tJugadora origen) {
strcpy(desti->nom, origen.nom);
strcpy(desti->cognom, origen.cognom);
desti->dorsal = origen.dorsal;
desti->equip = origen.equip;
}
void inicialitzarTaula(tTaulaJugadores *taula) {
taula->nJugadores= 0;
}
void afegirJugadora(tTaulaJugadores *taula, tJugadora j) {
/* Es comprova primer que la taula no estigui plena! */
if(taula->nJugadores >= MAX_JUGADORES) {
printf("Error en afegir jugadora a la taula\n");
} else {
/* S'afegeix la jugadora a la taula, i s'incrementa
el comptador d'elements de la taula */
copiarJugadora(&taula->jugadores[taula->nJugadores], j);
/* Important! després d'afegir una jugadora, no hem
* d'oblidar incrementar el comptador! */
taula->nJugadores++;
}
}
void mostrarJugadores(tTaulaJugadores taula) {
int i;
i = 0;
printf("\nRecorregut: jugadores entrades a la taula ...\n");
while (i < taula.nJugadores) {
mostrarJugadora(taula.jugadores[i]);
i = i+1;
}
}
void cercarJugadora(tTaulaJugadores taula, int dorsal, tEquip equip) {
int i;
bool isTrobada;
/* El booleà 'isTrobada' s'utilitzarà
* per sortir del bucle que recorre totes
* les jugadores de la taula: quan en trobi
* una, isTrobada = true, i la condició d'entrada
* del bucle ja no es complirà, amb el que
* la cerca haurà finalitzat.
*/
isTrobada = false;
if (equip == LOCAL) {
printf("\nCerca: jugadora local amb dorsal núm. %d ...", dorsal);
} else {
printf("\nCerca: jugadora visitant amb dorsal núm. %d ...", dorsal);
}
for (i=0; i<taula.nJugadores && !isTrobada; i++) {
if (taula.jugadores[i].dorsal == dorsal &&
taula.jugadores[i].equip == equip) {
isTrobada = true;
}
}
/* Es mostra per pantalla els resultats
* obtinguts
*/
if (!isTrobada) {
printf("\n>> No s'ha trobat cap jugadora. \n");
} else {
printf("\n>> Jugadora trobada : \n");
mostrarJugadora(taula.jugadores[i-1]);
}
}