Ejemplo¶
Listado de notas¶
Descripción del programa¶
Con el programa se desea realizar una sencilla aplicación que permita a un profesor almacenar en un fichero el DNI de los alumnos y sus notas en un examen.
El formato del fichero es:
DNI1 Nota1 |
|
DNI2 Nota2 |
|
… |
El campo DNI será un string
, como por ejemplo 13132654A
y el campo Nota un double
, como por ejemplo 6.7
.
En definitiva, el formato consiste en una sucesión alternada de campos
string
y double
separados por espacios en blanco.
Como es lógico, la aplicación permitirá ser utilizada en diferentes instantes de tiempo. Por ello, cada vez que el profesor introduzca una nueva nota:
se abrirá el fichero con las notas ya introducidas
añadirá la nueva nota a las ya existentes
salvará a disco cerrando el fichero
Además de almacenar las notas, el programa permitirá calcular alguna propiedad estadística simple de las notas introducidas hasta ese momento. En el ejemplo, la peor nota, la mejor y la media.
El programa no verificará la validez del DNI. Una aplicación comercial lo haría. Tampoco comprueba si el DNI de un alumno ya se encuentra almacenado y, por tanto, o el profesor ha cometido un error o quizás desea alterar la nota.
La aplicación exigirá que la nota esté en el intervalo [0,10].
Diseño del programa¶
El programa comienza solicitando el nombre del fichero donde se almacenan alumnos y notas.
Un menú permitirá elegir entre 2 opciones:
Introducir nueva nota
Se abrirá el fichero para escritura usando el modo
ios::app
. Así podremos añadir la nueva nota al final del mismo.Calcular estadísticas
Se abrirá el fichero para lectura
Los prototipos de las funciones son los siguientes:
Introducción del nombre del fichero:
string introduce_nombre_fichero();
Menú con las opciones:
Salir del programa
Introducir nota
Listado y estadísticas
int menu();
Introducción de una nota
void introduce_nota(const string& nom_fich);
Listado y estadísticas
void calcula_estadisticas(const string& nom_fich);
Esta función invocará a otra que lee el fichero y carga en dos vectores los DNI y las notas. Para ello se usará una función con prototipo:
void lee_notas(const string& nom_fich, vector<string>& dnis, vector<double>& notas);
Para mostrar por pantalla los resultados, se utilizará una función con signatura:
void listado(const vector<string>& dnis, const vector<double>& notas, size_t indice_minima, size_t indice_maxima, double media);
La función introduce_nombre_fichero()
¶
Se limita a devolver un string
con el nombre del fichero.
string introduce_nombre_fichero()
{
cout << "Nombre con extension del fichero de notas: ";
string nombre_fichero;
cin >> nombre_fichero;
return nombre_fichero;
}
La función introduce_nota()
¶
La función abre el fichero en modo escritura y para añadir datos. Tras solicitar el DNI y la nota, estos añaden al final del fichero.
void introduce_nota(const string& nombre_fichero)
{
cout << "DNI con letra de control del alumno: ";
string dni;
cin >> dni;
double nota;
do
{
cout << "Nota(0 al 10): ";
cin >> nota;
if (nota < 0 || nota > 10)
cout << "\n\nERROR: La nota no es válida.\n\n";
}while (nota < 0 || nota > 10);
ofstream fichero(nombre_fichero, ios::app);
if (!fichero)
{
cout << "Error, "<< nombre_fichero
<< " no pudo abrirse para escritura.\n";
exit(EXIT_FAILURE);
}
fichero << dni << " " << nota << endl;
}
Nótese el uso del modo ios::app
. Para respetar el formato,
en la línea:
fichero << dni << " " << nota << endl;
se separan el DNI y la nota por un espacio en blanco, " "
y
se introduce una nueva línea, endl
.
La función lee_notas()
¶
La función pasa por referencia los vectores donde se almacenarán
los DNI y las notas. Dado que el formato no informa del número de
alumnos, se usa un bucle while
para la lectura.
void lee_notas(const string& nombre_fichero, vector<string>& dnis, vector<double>& notas)
{
ifstream fichero(nombre_fichero);
if (!fichero)
{
cout << "Error, "<< nombre_fichero
<< " no pudo abrirse para lectura.\n";
exit(EXIT_FAILURE);
}
string dni;
while (fichero >> dni)
{
dnis.push_back(dni);
double nota;
fichero >> nota;
notas.push_back(nota);
}
}
La condición de salida del bucle while
es fichero >> dni
,
dado que cuando se llegue al final del fichero es el primer dato
que al intentar ser leído dará error.
La función listado()
¶
Es la función encargada de mostrar los resultados. Se ha usado
el tipo size_t
pero hubiese sido perfectamente válido
utilizar int
.
void listado(const vector<string>& dnis, const vector<double>& notas,
size_t indice_minima, size_t indice_maxima, double media)
{
cout << "******************************************\n";
for (size_t i = 0; i < dnis.size(); ++i)
cout << dnis[i] << " " << notas[i] << endl;
cout << "******************************************\n";
cout << "Nota minima: " << dnis[indice_minima]
<< " con nota " << notas[indice_minima] << endl;
cout << "Nota maxima: " << dnis[indice_maxima]
<< " con nota " << notas[indice_maxima] << endl;
cout << "Nota media: " << media << endl;
cout << "******************************************\n";
}
La función calcula_estadisticas()
¶
Tras leer el fichero y crear los vectores de DNI y notas, se verifica que el fichero no estaba vacío. Posteriormente se calculan las estadísticas y, finalmente, se listan por pantalla.
void calcula_estadisticas(const string& nombre_fichero)
{
vector<string> dnis;
vector<double> notas;
lee_notas(nombre_fichero, dnis, notas);
if (dnis.empty())
{
cout << "\n\nEl fichero esta vacío.\n\n";
return;
}
size_t indice_minima = 0, indice_maxima = 0;
double nota_minima = notas[0];
double nota_maxima = notas[0];
double media = 0.;
for (size_t i = 0; i < dnis.size(); ++i)
{
if (notas[i] < nota_minima)
{
nota_minima = notas[i];
indice_minima = i;
}
else if (notas[i] > nota_maxima)
{
nota_maxima = notas[i];
indice_maxima = i;
}
media += notas[i];
}
media /= dnis.size();
listado(dnis, notas, indice_minima, indice_maxima, media);
}
La función main()
¶
Nótese como el uso de funciones hace que, con un simple vistazo,
la función main()
nos apunte claramente el objeto y la estructura
del programa.
int main()
{
string nombre_fichero = introduce_nombre_fichero();
while (int opcion = menu())
if(opcion == 1)
introduce_nota(nombre_fichero);
else
calcula_estadisticas(nombre_fichero);
}
Edita, compila y ejecuta el código
Sugerimos al alumno que incorpore al programa nuevas funcionalidades, tales como:
permitir alterar la nota de un alumno introduciendo su DNI
verificar que, al introducir una nueva nota, el DNI de un alumno no esté en el fichero. Esto evitará posibles despistes del profesor.
obtener un listado de los DNI y las notas, ordenado según las notas de menor a mayor
obtener un listado de los DNI y las notas, ordenado según los DNI de menor a mayor