8 PR3
8.1 Cómo inicializar una tabla
Para inicializar/borrar una tabla únicamente necesitamos indicar que el número de elementos que contiene es 0.
La pregunta que nos podemos hacer es “¿simplemente inicializando a 0 este atributo es suficiente?”. La respuesta es afirmativa: el atributo que contiene el número de elementos de una tabla siempre es el utilizado a la hora de recorrer una tabla, ya que nos indica cuál es el último elemento de la tabla. Del mismo modo, cuando insertamos un elemento incrementaremos en 1 su valor.
¿Qué pasa cuando le damos valor 0? Estamos indicando que la tabla tiene 0 elementos, de forma que cuando añadimos uno nuevo lo haremos en la primera posición, sobreescribiendo todo lo que previamente pudiera haber en memoria.
8.2 Ejemplo: calcularNota
Se debe entender una tabla como un conjunto de elementos de los que sabemos en todo momento cuántos tenemos.
Imaginemos que queremos un programa que calcule la nota media de las PEC de una asignatura. Podríamos plantearlo como un simple array de enteros, pero como nos gusta poder ofrecer más funcionalidades en un futuro en nuestro programa, tendremos el siguiente escenario:
tPec
: será el tipo de datos básico que tratará nuestro programa. Esta tupla estará formada por un lado por un número descriptivo de la PEC, y por otro lado por su nota numérica con decimales.tAsignatura
: tabla que contendrá elementos de tipo tPec. Aparte del array de tPec, también tendrá un contador interno de elementos: numPecs.
Sobre esta base realizaremos dos acciones:
insertarPec()
: se trata de una acción que incluye un elemento de tipotPec
dentro de la tablatAsignatura
. Es una operación similar a la acción de llenar una tabla de los ejemplos de la xWiki.calcularNota()
: es una función que revisa todos los elementostPec
de la tablatAsignatura
y calcula su nota promedio. Se trata de una operación equivalente a la de los recorridos de tabla de los ejemplos de la xWiki, ya que estamos recorriendo uno a uno todos los elementostPec
para obtener su nota.
Una posible forma de implementarlo sería la siguiente:
/* Ejemplo ES0801 */
#include <stdio.h>
#include <string.h>
/* Definición de constantes */
#define MAX_PECS 5
#define MAX_NOMBRE 5+1
/* Definición de la tupla tPec */
typedef struct {
char nombre[MAX_NOMBRE];
float nota;
} tPec;
/* Definición de la tabla tAsignatura */
typedef struct {
tPec pec[MAX_PECS];
int numPecs;
} tAsignatura;
/* Predeclaración de funciones/acciones */
/* Acción que añade un elemento de tipo tPec en la tabla tAsignatura */
void insertarPec(tAsignatura *asignatura, tPec pec);
/* Función que calcula la media de todas las tPec que contiene la tabla
* tAsignatura
*/
float calcularNota(tAsignatura asignatura);
/* Programa principal */
int main(int argc, char **argv) {
/* Definimos las variables */
tAsignatura fp;
tPec pec1, pec2, pec3;
float nota;
/* Inicializamos las variables */
nota = 0;
strcpy(pec1.nombre,"PEC01");
pec1.nota = 10;
strcpy(pec2.nombre,"PEC02");
pec2.nota = 8.5;
strcpy(pec3.nombre,"PEC03");
pec3.nota = 7.5;
/* La inicialización de la tabla se hace simplemente
* poniendo a 0 su contador
*/
fp.numPecs = 0;
/* Añadimos ahora las pec a la asignatura, que es una tabla
* de elementos de tipo tPec
*/
insertarPec(&fp, pec1);
insertarPec(&fp, pec2);
insertarPec(&fp, pec3);
/* Calculamos la nota con la función calcularNota */
nota = calcularNota(fp);
printf("La nota promedio de las %d PEC es %f\n", fp.numPecs, nota);
return 0;
}
/* Implementación funciones/acciones */
void insertarPec(tAsignatura *asignatura, tPec pec) {
/* numPecs contiene el número de elementos de tipo tPec
* de la tabla
*/
asignatura->pec[asignatura->numPecs] = pec;
/* Una vez hemos asignado un elemento nuevo tPec en la tabla,
* incrementamos el valor de numPecs
*/
asignatura->numPecs = asignatura->numPecs + 1;
}
float calcularNota(tAsignatura asignatura) {
/* La variable suma contiene el sumatorio de todas
* las notas de las tPec que están dentro de la tabla
* tAsignatura
*/
float suma = 0;
int i;
suma = 0.0;
/* Se recorren todos los elementos tPec de tAsignatura
* para obtener su nota y acumularlas a la
* variable suma
*/
for (i = 0; i < asignatura.numPecs; i++) {
suma = suma + asignatura.pec[i].nota;
}
/* Para calcular la media se divide el sumatorio de
* notas por el total de elementos de la tabla tAsignatura
*/
return suma/asignatura.numPecs;
}
Para facilitar la lectura se ha unido todo el programa en un único bloque de código (un único archivo).
8.3 Ejemplo: calcularNota con iteración
El siguiente ejemplo adapta el caso anterior para que pida los valores iterativamente:
/* Ejemplo ES0802 */
#include <stdio.h>
#include <string.h>
/* Definición de constantes */
#define MAX_PECS 5
#define MAX_NOMBRE 5+1
/* Definición de la tupla tPec */
typedef struct {
char nombre[MAX_NOMBRE];
float nota;
} tPec;
/* Definición de la tabla tAsignatura */
typedef struct {
tPec pec[MAX_PECS];
int numPecs;
} tAsignatura;
/* Definición funciones/acciones */
/* Acción que añade un elemento de tipo tPec en la tabla tAsignatura */
void insertarPec(tAsignatura *asignatura, tPec pec);
/* Función que calcula la media de todas las tPec que contiene la tabla
* tAsignatura
*/
float calcularNota(tAsignatura asignatura);
/* Programa principal */
int main(int argc, char **argv) {
/* Definimos las variables */
tAsignatura fp;
float nota;
int numPecs, i;
/* Inicializamos las variables */
nota = 0;
numPecs = 0;
i = 0;
/* Inicializamos la tabla */
fp.numPecs=0;
/* Introducimos los datos de las PEC desde teclado */
printf("Número de PECs que hay que introduir (<%d): ", MAX_PECS);
scanf("%d", &numPecs);
for (i = 0; i < numPecs; i++) {
tPec pecAux;
printf("Datos de la PEC0%d : \n", i+1);
printf("\tNombre : ");
scanf("%s", pecAux.nombre);
printf("\tNota : ");
scanf("%f", &pecAux.nota);
/* Añadimos a la tabla la tPec auxiliar utilizada
* dentro del bucle. En cada iteración se construirá
* y se añadirá una tPec diferente
*/
insertarPec(&fp, pecAux);
}
/* Calculamos la nota con la función calcularNota */
nota = calcularNota(fp);
printf("La nota promedio de las %d PEC es %f\n", fp.numPecs, nota);
return 0;
}
/* Implementación funciones/acciones */
void insertarPec(tAsignatura *asignatura, tPec pec) {
/* numPecs contiene el número de elementos de tipo tPec
* que contiene la tabla en cada momento
*/
asignatura->pec[asignatura->numPecs] = pec;
/* Una vez que hemos asignado un elemento nuevo tPec en la tabla
* incrementamos el valor de numPecs
*/
asignatura->numPecs = asignatura->numPecs + 1;
}
float calcularNota(tAsignatura asignatura) {
/* La variable suma contiene el sumatorio de todas
* las notas de las tPec que están dentro de la tabla
* tAsignatura
*/
float suma;
int i;
suma = 0.0;
/* Se recorren todos los elementos tPec de tAsignatura
* para obtener su nota y acumularlas a la
* variable suma
*/
for (i = 0; i < asignatura.numPecs; i++) {
suma = suma + asignatura.pec[i].nota;
}
/* Para calcular la media se divide el sumatorio de
* notas por el total de elementos de la tabla tAsignatura
*/
return suma/asignatura.numPecs;
}
8.4 Ejemplo: recorrido vs búsqueda
En el siguiente ejemplo se tratan los conceptos de recorrido y de búsqueda de los elementos de una tabla. Dentro del código se han añadido comentarios detallados para que cada paso quede explicado.
/* Ejemplo ES0803 */
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
/* Nos piden un programa que permita registrar
* jugadoras de baloncesto dentro de una tabla. En una
* misma tabla tendremos tanto a las jugadoras locales
* como a las visitantes. Sobre ellas realizaremos
* un recorrido, consistente en mostrarlas todas
* por pantalla, y también una búsqueda, donde a partir
* del equipo y el dorsal mostraremos por pantalla
* la jugadora en caso de que exista.
* Necesitaremos implementar las siguientes acciones:
* - inicializarTabla(...): para inicializar la
* tabla de jugadoras.
* - insertarJugadora(...): para añadir una
* jugadora a una tabla.
* - mostrarJugadoras(...): para mostrar por
* pantalla todas las jugadoras de la tabla.
* - buscarJugadora(...): para buscar dentro de la
* tabla la jugadora que tenga un equipo y
* un dorsal determinado.
*/
#define MAX_NOMBRE 20+1
#define MAX_APELLIDO 20+1
#define MAX_JUGADORAS 10
typedef enum {LOCAL, VISITANTE} tEquipo;
typedef struct {
char nombre[MAX_NOMBRE];
char apellido[MAX_APELLIDO];
int dorsal;
tEquipo equipo;
} tJugadora;
/* Definición del tipo tabla de
* jugadoras; como se puede ver, según
* se indica en las xWiki, únicamente
* está formada por un vector y un
* contador con las jugadoras que contiene.
*/
typedef struct {
tJugadora jugadoras[MAX_JUGADORAS];
int nJugadoras;
} tTablaJugadoras;
/* Predeclaraciones */
void leerJugadora(tJugadora *j);
void mostrarJugadora(tJugadora j);
void copiarJugadora(tJugadora *destino, tJugadora origen);
void inicializarTabla(tTablaJugadoras *tabla);
void insertarJugadora(tTablaJugadoras *tabla, tJugadora j);
void mostrarJugadoras(tTablaJugadoras tabla);
void buscarJugadora(tTablaJugadoras tabla, int dorsal, tEquipo equipo);
/* Programa principal */
int main(int argc, char **argv) {
tJugadora jugadora;
tTablaJugadoras tabla;
tEquipo equipo;
int dorsal, i;
/* Para inicializar una tabla simplemente
* ponemos el contador de elementos a 0.
* La inserción de jugadoras en la tabla
* tiene presente este contador, y sobrescribirá
* cualquier otro valor que existiera en
* esta misma posición.
*/
inicializarTabla(&tabla);
/* Pedimos las jugadoras por teclado y
* a continuación las vamos añadiendo a la tabla
*/
for (i=0; i<MAX_JUGADORAS; i++) {
leerJugadora(&jugadora);
insertarJugadora(&tabla, jugadora);
}
/* Se recorren todos los elementos
* de la tabla de jugadoras para
* imprimir los datos por pantalla
*/
mostrarJugadoras(tabla);
printf("\n¿Qué jugadora quieres buscar? : ");
printf("\n>> Equipo (0=LOCAL, 1=VISITANTE) : ");
scanf("%u", &equipo);
printf(">> Dorsal : ");
scanf("%d", &dorsal);
/* Se hace una búsqueda entre todas las
* jugadoras de la tabla, de forma que
* mostrará por pantalla el resultado
* obtenido; si no se encuentra ninguna,
* devuelve un mensaje informativo.
*/
buscarJugadora(tabla, dorsal, equipo);
return 0;
}
/* Implementación de las acciones */
void leerJugadora(tJugadora *j) {
printf("Introduce los datos de la nueva jugadora: \n");
printf("\tNombre: ");
scanf("%s", j->nombre);
printf("\tApellido: ");
scanf("%s", j->apellido);
printf("\tEquipo (0=LOCAL, 1=VISITANTE): ");
scanf("%u", &j->equipo);
printf("\tDorsal: ");
scanf("%d", &j->dorsal);
}
void mostrarJugadora(tJugadora j) {
if (j.equipo == LOCAL) {
printf("LOCAL : %d %s,%s\n", j.dorsal, j.apellido, j.nombre);
} else {
printf("VISITANTE: %d %s,%s\n", j.dorsal, j.apellido, j.nombre);
}
}
void copiarJugadora(tJugadora *destino, tJugadora origen) {
strcpy(destino->nombre, origen.nombre);
strcpy(destino->apellido, origen.apellido);
destino->dorsal = origen.dorsal;
destino->equipo = origen.equipo;
}
void inicializarTabla(tTablaJugadoras *tabla) {
tabla->nJugadoras= 0;
}
void insertarJugadora(tTablaJugadoras *tabla, tJugadora j) {
/* ¡Se comprueba primero que la tabla no esté llena! */
if(tabla->nJugadoras >= MAX_JUGADORAS) {
printf("Error al insertar jugadora en la tabla\n");
} else {
/* Se añade la jugadora en la tabla y se incrementa
el contador de elementos de la tabla */
copiarJugadora(&tabla->jugadoras[tabla->nJugadoras], j);
/* ¡Importante! ¡después de añadir una jugadora no nos
* tenemos que olvidar de incrementar el contador! */
tabla->nJugadoras++;
}
}
void mostrarJugadoras(tTablaJugadoras tabla) {
int i;
i = 0;
printf("\nRecorrido: jugadoras insertadas en la tabla ...\n");
while (i < tabla.nJugadoras) {
mostrarJugadora(tabla.jugadoras[i]);
i = i+1;
}
}
void buscarJugadora(tTablaJugadoras tabla, int dorsal, tEquipo equipo) {
int i;
bool isEncontrada;
/* El booleano 'isEncontrada' se utilizará
* para salir del bucle que recorre todas
* las jugadoras de la tabla: cuando encuentre
* una, isEncontrada = true, la condición de entrada
* del bucle ya no se cumplirá, con lo
* la búsqueda habrá finalizado.
*/
isEncontrada = false;
if (equipo == LOCAL) {
printf("\nBúsqueda: jugadora local con dorsal núm. %d ...", dorsal);
} else {
printf("\nBúsqueda: jugadora visitante con dorsal núm. %d ...", dorsal);
}
for (i=0; i<tabla.nJugadoras && !isEncontrada; i++) {
if (tabla.jugadoras[i].dorsal == dorsal &&
tabla.jugadoras[i].equipo == equipo) {
isEncontrada = true;
}
}
/* Se muestra por pantalla los resultados
* obtenidos
*/
if (!isEncontrada) {
printf("\n>> No se ha encontrado ninguna jugadora. \n");
} else {
printf("\n>> Jugadora encontrada : \n");
mostrarJugadora(tabla.jugadoras[i-1]);
}
}