Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Ejercicios Programacion Largos
Ejercicios Programacion Largos
"PROGRAMACIÓN"
INDICE
Todos los programas han sido comprobados y compilados con el compilador Quick-C 2.5 de
Microsoft bajo sistema operativo Windows de 32 bits. Puede descargar este compilador AQUÍ.
Una vez descargado y descomprimido en la carpeta C:\QC25, abra la ventana de comandos del
sistema operativo, sitúese en la carpeta C:\QC25\PROGRAMS y ejecute el compilador CL.BAT.
Ejemplo: CL BASEDAT.C (el ejecutable se llamará BASEDAT.EXE).
Apartado 2)
Introduce el número de aparatos montados mensualmente:
Aparato 0: 100
Aparato 1: 1000
Aparato 2: 200
...
Aparato 9: 300
Apartado 3)
Número de unidades de cada componente utilizados mensualmente:
Componente 0: 100
Componente 1: 300
Componente 2: 500
...
Componente 99: 100
Apartado 4)
El componente electrónico 7 es el más utilizado, se necesitan 10000 unidades.
ANÁLISIS DEL PROBLEMA
4. Necesitaremos un array montajes de NumAparatos posiciones para almacenar por cada aparato el
número de montajes que se hacen del mismo cada mes.
3. Leer por cada aparato cuántos aparatos se van a montar en un mes, registrando dichos valores en el array
montajes.
4. Calcular en el array totales por cada tipo de componente cuántos componentes se van a emplear entre
todos los montajes de todos los aparatos, combinando para ello los datos del array desglose y el array
montajes.
Para determinar el número de componentes de tipo c que se necesitarán en un mes y registrarlo en
totales[c]:
a. Se inicializa a 0 el acumulador totales[c].
b. Por cada tipo de aparato a se calcula el número de componentes de tipo c que se emplearán en un mes
para montar todos los aparatos a: desglose[a][c]*montajes[a], ya que si el aparato a no contiene el
componente c entonces desglose[a][c] tendrá el valor 0. El número calculado de componentes c que se
emplearán en los montajes de los aparatos se acumula en totales[c].
Los dos pasos anteriores se repiten por cada tipo de componente c y se muestra en pantalla.
5. Para calcular el componente más empleado, basta con determinar en qué posición está el valor máximo
del array totales:
a. Inicialmente considerar que el primer valor del array totales es el máximo hasta el momento (posMax).
b. Con el resto de componentes (sea c el índice para denotar cada uno de ellos), se repite una y otra vez:
I. Se comprueba si el número de componentes totales de tipo c es mayor que el máximo hasta el
momento: totales[c]>totales[posMax].
II. Si es mayor, se actualiza la posición en la que se ubica el nuevo máximo, es decir, la variable
posMax con el componente actual c.
c. Se imprime un mensaje en pantalla indicando que el componente posMax es el componente más
empleado, utilizándose un total de totales[posMax] unidades.
CÓDIGO C
#include <stdio.h>
#include <stdlib.h>
#define NumAparatos 10
#define NumComponentes 20
main()
{
int desglose[NumAparatos][NumComponentes];
int montajes[NumAparatos], totales[NumComponentes];
int a, c, totalComp, nc, posMax, num;
// Inicializar desglose: ningún componente por aparato
for (a = 0; a<NumAparatos; a++)
{ for(c = 0; c<NumComponentes; c++)
{ desglose[a][c]=0; }
}
// Lectura de los componentes de cada uno de los aparatos
system("CLS"); //borrar pantalla
printf("Introduce los componentes de cada aparato:\n");
for (a = 0; a<NumAparatos; a++)
{ printf("\nNumero de componentes del aparato %d: ",a); scanf("%d", &totalComp); fflush(stdin);
for (nc = 1; nc<=totalComp; nc++)
{ printf("Codigo del Componente %d (0 a %d): ", nc, NumComponentes-1); scanf ("%d", &c); fflush(stdin);
printf(" Numero de unidades del componente %d: "); scanf("%d", &num); fflush(stdin);
desglose[a][c]=num; //El aparato a tiene num unidades del componente c.
}
}
// Lectura de los aparatos montados mensualmente
printf("\nIntroduce el numero de aparatos montados mensualmente:\n");
for (a = 0; a<NumAparatos; a++)
{ printf("Aparato %d: ",a); scanf("%d", &montajes[a]); fflush(stdin); }
// Cálculo del número de componentes mensuales
printf("\nNumero de componentes utilizados mensualmente:\n ");
for (c = 0; c<NumComponentes; c++)
{ totales[c]=0;
for (a=0; a<NumAparatos; a++)
{ totales[c] = totales[c] + desglose[a][c] * montajes[a]; }
printf("Componente %d: %d\n", c, totales[c]);
}
// El componente más empleado entre todos los montajes del mes.
posMax = 0; //posicion donde se encuentra el valor máximo del array hasta el momento
for (c=1; c<NumComponentes; c++)
{ if (totales[c]>totales[posMax]) posMax=c; } //nueva posicion de un Nuevo máximo encontrado
printf("\nEl componente electronico %d es el mas utilizado, se necesitan %d unidades.\n\n", posMax,
totales[posMax]);
system ("PAUSE"); //mensaje "Pulse una tecla para continuar"
}
AMPLIACIONES PROPUESTAS
2. Si al entrar al programa existen en el disco los ficheros anteriores, cargarlos en los arrays, mostrarlos en
pantalla y preguntar si se desea modificar alguno de sus datos (ya no es necesario introducirlos todos de
nuevo).
3. Realizar la introducción de componentes de cada aparato mediante una función específica leeAparato().
que reciba como argumento de entrada el array bidimensional desglose.
CÓDIGO C AMPLIADO
(Las ampliaciones están marcadas en color rojo)
#include <stdio.h>
#include <stdlib.h>
#define NumAparatos 10
#define NumComponentes 20
// Declaraciones prototipo de funciones auxiliares
void leeAparato(int a, int desglose[][NumComponentes]);
char sino(char *mensaje);
main()
{
int desglose[NumAparatos][NumComponentes];
int montajes[NumAparatos], totales[NumComponentes];
int a=-1, c, nc, posMax;
char resp;
FILE *pf; //puntero de control de un fichero
system("CLS");
if ((pf=fopen("compon1.dat","rb"))==NULL) //intentamos abrir el fichero de desglose en modo lectura
{ //No existe fichero desglose, inicializar a 0 el array desglose
for (a = 0; a<NumAparatos; a++)
for (c = 0; c<NumComponentes; c++) desglose[a][c]=0;
//Lectura de los componentes de cada uno de los aparatos
printf("Introduce los componentes de cada aparato:\n");
for (a = 0; a<NumAparatos; a++)
{ leeAparato(a, desglose); } //llamada a la función de lectura de los componentes de cada aparato
}
else
{ //Existe el fichero desglose, cargarlo en el array desglose y mostrarlo en pantalla
fread(desglose,sizeof(desglose),1,pf); //leemos todo el array con una única instrucción
fclose(pf); //cerramos el fichero
printf("Desglose de aparatos:"); //Mostrar el desglose de todos los aparatos actuales
for (a = 0; a<NumAparatos; a++)
{ printf("\nAparato %d, Componente/Cantidad: ", a);
for (c = 0; c<NumComponentes; c++)
if (desglose[a][c]>0) printf("%d/%d ", c, desglose[a][c]);
}
//Posible modificación de los datos del desglose de uno o más aparatos
while (1) //bucle infinito, se termina con "break"
{ if (sino("\nDesea modificar los datos de desglose de algun aparato?")=='N') //pide respuesta S/N
break; //salir del bucle
do
{ printf("Indique codigo del Aparato (0 a %d): ", NumAparatos-1); //pedimos aparato a modificar
scanf("%d", &a); fflush(stdin);
} while (a<0 || a>=NumAparatos);
leeAparato(a, desglose); //llamada a la función de lectura de componentes del aparato
}
}
if ((pf=fopen("compon2.dat","rb"))==NULL) //intentamos abrir el fichero de montajes en modo lectura
resp = 'S'; //No existe fichero montajes
else
{ //Existe el fichero montajes, cargarlo en el array montajes
fread(montajes,sizeof(montajes),1,pf); fclose(pf); //leemos todo el array en una única operación
printf("\nMontajes mensuales de los aparatos:"); //Mostrar los montajes actuales
for (a = 0; a<NumAparatos; a++)
printf("\nAparato %d: %d", a, montajes[a]);
resp = sino("\nDesea modificar los datos de montajes mensuales de los aparatos?");
}
if (resp=='S') //si respondimos que sí o si no existía fichero montajes
{ //Introducción del número de montajes mensuales en el array montajes
printf("\nIntroduce el numero de aparatos montados mensualmente:\n");
for (a = 0; a<NumAparatos; a++)
{ printf("Aparato %d: ",a); scanf("%d", &montajes[a]); fflush(stdin); }
}
//Cálculo del número de componentes mensuales
if ((pf = fopen("listado.txt","w"))==NULL) //abrimos el fichero de texto para listado en disco
printf("\nNo se puede generar listado de componentes en el disco.\n");
else
{ printf("\nNumero de componentes utilizados mensualmente:\n");
fprintf(pf, "Numero de componentes utilizados mensualmente:\n"); //repetimos el texto hacia el fichero
for (c=0; c<NumComponentes; c++)
{ for (totales[c]=a=0; a<NumAparatos; a++)
totales[c] += desglose[a][c]*montajes[a];
if (totales[c]>0)
{ printf("Componente %d: %d\n", c, totales[c]);
fprintf(pf, "Componente %d: %d\n", c, totales[c]); //repetimos el texto hacia el fichero
}
}
fclose(pf); //cerramos fichero de listado en disco
}
//El componente más empleado entre todos los montajes del mes.
for (c=1,posMax=0; c<NumComponentes; c++)
{ if (totales[c]>totales[posMax]) posMax=c; }
printf("\nEl componente electronico %d es el mas utilizado, se necesitan %d unidades.\n\n", posMax,
totales[posMax]);
//Grabar ficheros en disco
if ((pf = fopen("compon1.dat","wb"))==NULL) printf("\nERROR al grabar ficheros.\n");
else { fwrite(desglose,sizeof(desglose),1,pf); fclose(pf); }
if ((pf = fopen("compon2.dat","wb"))==NULL) printf("\nERROR al grabar ficheros.\n");
else { fwrite(montajes,sizeof(montajes),1,pf); fclose(pf); }
system ("PAUSE");
}
Tipos De Bebidas:
0. Naturales: agua, leche, zumos, mostos, infusiones, ...
1. Gaseosos: Refrescos
2. Vinos
3. Cervezas
4. Whisky
5. Licores
6. Energéticos: Aquarius, Red Bull,...
7. Combinados: Cubatas, GinTonics,..
Mediante un programa en C, se pide realizar un estudio que estará compuesto por los siguientes pasos:
1. Recoger y almacenar la información, para cada pueblo, sobre los litros consumidos de los tipos de bebidas
mencionados. Recuerda que 20 pueblos aportarán información a tu estudio. No obstante, la información no te
la tienen por qué dar ordenada por tipo de bebida o número de litros y puede que de algún tipo de bebida no
se tenga información. Así, será preciso introducir pares de datos (tipo de bebida y litros) y para indicar que no
hay más datos de un pueblo, bastará con introducir como tipo de bebida el texto FIN. Ver ejemplo para cada
uno de los apartados al final del enunciado.
2. Recoger y almacenar cuáles de las clases de bebidas tienen alcohol. Para ello, te dan únicamente la lista
de los tipos de bebidas que contienen alcohol, lista acabada con un texto FIN para indicar que no hay más
tipos de bebida que tengan alcohol. Por ejemplo: 7 2 5 4 3 FIN
3. Determinar el tipo de bebida más consumida entre todos los pueblos, es decir, el tipo de bebida del que
más litros se hayan bebido.
Ejemplo: (En letra normal lo que el programa imprime y en negrita lo que el usuario teclea)
Para comenzar el estudio recogemos los datos por pueblos.
Por cada pueblo: Introduce pares (tipoBebida y litros). Para acabar teclea FIN.
Pueblo 0:
08
47
20
3 50
1 10
FIN
Pueblo 1:
0 18
1 15
40
26
3 36
FIN
Pueblo 2:
5 16
FIN
...
Pueblo 19:
35
1 12
FIN
Ahora necesitamos que enumeres SÓLO los tipos de bebida CON alcohol, teclea FIN para acabar:
7 2 5 4 3 FIN
6. Necesitaremos un array consumoXPueblo de NumPueblos posiciones para almacenar, por cada pueblo,
el número total de litros alcohólicos consumidos entre todos los tipos de bebidas.
2. Leer ordenadamente por pueblos, los pares que indican tipo de bebida y litros de la misma consumidos. En
el supuesto de que se repita un par (pueblo y tipo de bebida), los litros consumidos del último par serán los
que prevalezcan (es decir, no se hace acumulación de litros consumidos por tipo de bebida).
Para ello, por cada pueblo p:
a. Leer un par de valores de tipo de "bebida y litros consumidos" (tb y lt).
b. Mientras el tipo de bebida no sea FIN: asignar al pueblo p en el tipo de bebida tb los lt litros consumidos
(consumo[p][tb]=lt) y leer otro par de valores de tipo de "bebida y litros consumidos".
c. Si el tipo de bebida es FIN, indica que los datos de consumo del pueblo p ya han sido proporcionados.
3. Leer los tipos de bebidas que tienen alcohol. Las operaciones a realizar para ello son:
a. Se inicializa a 0 el array conAlcohol, indicando que inicialmente se consideran todas las bebidas no
alcohólicas.
b. Se lee un tipo de bebida tb.
c. Mientras que el tipo de bebida no sea FIN: se actualiza la bebida tb como alcohólica (conAlcohol[tb]=1)
y se lee otro tipo de bebida.
d. Cuando el tipo de bebida es FIN, la identificación de bebidas alcohólicas ha finalizado y con ello la
lectura de los tipos de bebida con alcohol.
4. Calcular por cada tipo de bebida los litros consumidos entre todos los pueblos y determinar la bebida más
consumida. Por cada tipo de bebida b:
a. Inicializar a 0 los litros consumidos en su acumulador (consumoXTipo[b]=0).
b. Incrementar el contador de bebida tipo b con los litros consumidos en todos los pueblos
(consumoXTipo[b]=consumo[p][b] + consumoXTipo[b], por cada pueblo p).
Una vez que se tienen calculados los litros consumidos por tipos de bebidas y recogidos en el array
consumoXTipo, se determina la bebida (índice del array) con mayor contenido (mayor consumo de litros) y
se imprime en pantalla. El proceso consiste en:
c. Inicialmente se considera que el mayor consumo de litros lo tiene la bebida 0 (maxTB).
d. Para el resto de bebidas se comprueba si los litros consumidos de la bebida actual b, supera los litros
consumidos por la bebida líder hasta el momento maxTB (determinado mediante la comparación
consumoXTipo[b]>consumoXTipo[maxTB]); en cuyo caso se registra la nueva bebida líder en consumo.
En caso contrario, la bebida líder hasta el momento sigue manteniéndose líder, y no hay que hacer nada
más.
e. Se imprime en pantalla un mensaje indicando cuál es la bebida de mayor consumo.
5. Calcular la bebida alcohólica más consumida. Ello se hace combinando los datos de los arrays
consumoXTipo y conAlcohol.
a. Se inicializa a 0 los litros máximos de alcohol consumidos (maxAlcohol).
b. Así, por cada bebida b, y sólo si ésta tiene alcohol (conAlcohol[b]==1) se comprueba si los litros
consumidos de la misma (consumoXTipo[b]) superan el mayor consumo hasta el momento (maxAlcohol)
(ambas condiciones se comprueban mediante la comparación (conAlcohol[b]==1 and
consumoXTipo[b]>=maxAlcohol)). Si la comparación es cierta, se actualiza el nuevo máximo: la bebida
alcohólica líder en consumo (identificada por la posición del array) y los litros consumidos de la misma
(posMaxAlcohol=b y maxAlcohol=consumoXTipo[b]).
c. Se imprime en pantalla un mensaje indicando cuál es la bebida alcohólica con mayor consumo
(posMaxAlcohol).
6. Calcular el pueblo con mayor consumo de alcohol. Se calcula de forma análoga pero, en lugar de por tipos
de bebidas, por pueblos. Es decir, por cada pueblo p:
a. Inicializar a 0 los litros con alcohol consumidos en su acumulador (consumoXPueblo[p]=0).
b. Incrementar dicho contador con los litros consumidos en el pueblo p de todas los tipos de bebidas
alcohólicas (consumoXPueblo[p]= consumo[p][b] + consumoXPueblo[p], por cada tipo de bebida b siendo
b con alcohol (conAlcohol[b]==1)).
c. Una vez que se tienen calculados los litros con alcohol consumidos por pueblos y recogidos en el array
consumo, se determina el pueblo (índice del array) con mayor contenido (mayor consumo de litros
alcohólicos) y se imprime en pantalla. El cálculo es análogo al recogido en el paso anterior pero ahora con
el array consumoXPueblo, en lugar de consumoXTipo).
CÓDIGO C
#include <stdio.h>
#include <stdlib.h>
#define NumPueblos 20
#define NumTipoBebidas 8
main ()
{
int consumo[NumPueblos][NumTipoBebidas], consumoXPueblo[NumPueblos];
int consumoXTipo[NumTipoBebidas], conAlcohol[NumTipoBebidas];
int p, b, lt, tb, tp, sc, maxP, maxTB, maxAlcohol;
int posMaxAlcohol, posPMaxAlcohol;
AMPLIACIONES PROPUESTAS
1. Al comienzo de la primera ejecución del programa, preguntar el número de pueblos a procesar. Esto
permitirá utilizar la aplicación en otras provincias o comarcas. El programa creará entonces un "array
bidimensional dinámico" de nombre consumo para el número de pueblos especificado.
2. Si al entrar al programa existe ya en el disco el fichero anterior, medir su tamaño para determinar el
número de pueblos que contiene, crear el array dinámico consumo y cargarlo con los datos del fichero.
3. Inicializar el array conAlcohol al principio del programa de forma fija, no es necesario cargarlo desde el
teclado.
4. En la toma inicial de datos de consumo, pedir por teclado primero el código del pueblo y luego sus parejas
TipoBebida y Litros. Teclear FIN como código de pueblo para terminar la toma de datos y mostrar las
estadísticas finales. Esto permite ir introduciendo los consumos de los pueblos en sucesivas sesiones del
programa, y con cualquier orden de entrada de los pueblos.
5. Al introducir un código de pueblo, averiguar y notificar si ya han sido introducidos los datos de bebidas del
mismo.
6. Al terminar la introducción de datos, mostar en pantalla en forma tabular el contenido del array consumo.
7. Mostrar el nombre de las bebidas anotadas en las estadísticas finales del programa, mediante una función
auxiliar nombreBebida.
8. Al finalizar el programa, indicar en pantalla cuántos y cuáles pueblos faltan aún por introducir.
CÓDIGO C AMPLIADO
(Las ampliaciones están marcadas en color rojo)
#include <stdio.h>
#include <stdlib.h>
#define NumTipoBebidas 8
//Declaraciones prototipo de las funciones auxiliares
int **crearArrayBidimensional(int filas, int columnas);
char *nombreBebida(int n);
main ()
{
int consumoXTipo[NumTipoBebidas];
int conAlcohol[NumTipoBebidas] = {0,0,1,1,1,1,0,1}; //array ya cargado con valores fijos conocidos
int NumPueblos=0; //numero de pueblos, a introducir por teclado
int **consumo; //puntero doble necesario para crear un array bidimensional dinámico
int *consumoXPueblo; //puntero simple necesario para crear un array unidimensional dinámico
int p, b, lt, tb, tp, sc, maxP, maxTB, maxAlcohol, posMaxAlcohol, posPMaxAlcohol;
FILE *pf; //puntero de control de un fichero
system("CLS");
1. Leer y almacenar los votos emitidos por cada oyente, suponemos que como máximo pueden concursar
100 oyentes. A medida que llaman los concursantes se les asigna un número interno de forma correlativa del
0 al 99 (del 1 al 100 de cara al público). La entrada de datos se realizará en forma de tríos, con los números
de las canciones que vota cada oyente. Para finalizar se introducirá el valor 0 en el primer dato del trio.
Ejemplo:
Oyente 1: canciones 7 3 2 (internamente es Oyente 0, canciones 6 2 1)
Oyente 2: canciones 4 8 6 (internamente es Oyente 1, canciones 3 7 5)
Oyente 3: canciones 4 1 2 (internamente es Oyente 2, canciones 3 0 1)
Oyente 4: canciones 1 6 3 (internamente es Oyente 3, canciones 0 5 2)
Oyente 5: 0
2. Calcular los votos obtenidos por cada canción e indicar cuáles son la 1ª y 2ª canción más votada.
Según el ejemplo anterior:
Canción 1: 5 votos (internamente es la canción 0)
Canción 2: 2 votos (internamente es la canción 1)
Canción 3: 3 votos (internamente es la canción 2)
Canción 4: 6 votos (internamente es la canción 3)
Canción 5: 0 votos (internamente es la canción 4)
Canción 6: 3 votos (internamente es la canción 5)
Canción 7: 3 votos (internamente es la canción 6)
Canción 8: 2 votos (internamente es la canción 7)
Canción 9: 0 votos (internamente es la canción 8)
Canción 10: 0 votos (internamente es la canción 9)
La 1ª canción es: 4
La 2ª canción es: 1
3. Al final de la emisión se reparten puntos entre los oyentes que han concursado de la siguiente manera: 30
puntos si entre las 3 canciones votadas está la 1ª, 20 puntos si está la 2ª y 10 puntos suplementarios si han
acertado los dos títulos más votados. Se desea obtener el número del oyente que más puntos ha obtenido,
ya que se le dará un premio.
En el ejemplo:
Oyente 1: 0 puntos
Oyente 2: 30 puntos
Oyente 3: 60 puntos
Oyente 4: 20 puntos
Ganador: el oyente número 3
CÓDIGO C
#include <stdio.h>
#include <stdlib.h>
#define NumOyentes 100
#define NumCanciones 10
#define NumVotos 3
main ()
{
int votosOyentes[NumOyentes][NumVotos], votosXcancion[NumCanciones];
int p=0, numParticipantes, sc, c, v, v1, v2, v3, primera, segunda;
int votosP, maxPuntos, oyenteGanador;
AMPLIACIONES PROPUESTAS
1. En la primera ejecución del programa, pedir por teclado los dos datos fundamentales de número máximo
de oyentes (NumOyentes) y número de canciones (NumCanciones), y grabarlos en un fichero
"oyentes1.dat". En futuras entradas al programa, estos dos datos se tomarán desde este fichero y ya no
desde el teclado.
2. Tomar los datos de los oyentes en un "array dinámico bidimensional de tamaño creciente" de nombre
votosOyentes cuyo tamaño vaya creciendo en memoria a medida que tomamos nuevos datos de oyentes
desde el teclado.
4. Al presentar en pantalla las canciones 1ª y 2ª más votadas, considerar la posibilidad de que haya varias
canciones empatadas a puntos en cada categoría, y en tal caso mostrarlas todas.
5. Al presentar en pantalla el participante ganador, considerar la posibilidad de que haya varios empatados a
puntos, y en tal caso mostrarlos todos.
6. Al finalizar el programa, indicar en pantalla cuántos participantes tenemos y cuántos faltan aún por
introducir hasta llegar al límite máximo NumOyentes.
CÓDIGO C AMPLIADO
(Las ampliaciones están marcadas en color rojo)
#include <stdio.h>
#include <stdlib.h>
#define NumVotos 3
//Declaraciones prototipo de funciones auxiliares
int **crearArrayBidimensional(int filas, int columnas);
void sinMemoria(void);
main ()
{
int NumOyentes=0, NumCanciones=0; //valores a introducir por teclado
int **votosOyentes=NULL, **aux; //punteros dobles para manipular el array bidimensional dinamico
int *votosXcancion, *puntosXoyente; //punteros simples necesarios para los arrays unidimensionales
int p, numParticipantes=0, sc, c, v, v1, v2, v3, primera, segunda, maxPuntos, salir=0;
FILE *pf;
system("CLS");
if ((pf=fopen("oyentes1.dat","rb"))==NULL) //intentamos abrir el fichero en modo lectura
{ //No existe el fichero oyentes1.dat, pedimos los valores por teclado
do
{ printf("Indica el numero maximo de oyentes a procesar: "); sc=scanf("%d", &NumOyentes);
} while (NumOyentes<=0 || NumOyentes>1000 || sc!=1);
do
{ printf("Indica el numero de canciones a votar: "); sc=scanf("%d", &NumCanciones);
} while (NumCanciones<=0 || NumCanciones>100 || sc!=1);
//grabamos estos dos valores en el fichero
if ((pf=fopen("oyentes1.dat","wb"))==NULL)
{ printf("ERROR al grabar fichero. "); system("PAUSE"); exit(1); }
fwrite(&NumOyentes, sizeof(int), 1, pf); fwrite(&NumCanciones, sizeof(int), 1, pf); fclose(pf);
}
else
//el fichero oyentes1.dat existe, cargamos sus valores y cerramos el fichero
{ fread(&NumOyentes, sizeof(int), 1, pf); fread(&NumCanciones, sizeof(int), 1, pf); fclose(pf); }
Ejemplo:
Día 0 (lunes):
Surtidor, litros: 1 40
Surtidor, litros: 11 300
Surtidor, litros: 11 400
Surtidor, litros: 0 36
...
Surtidor, litros: 11 400
Se llenará con 100 litros
Surtidor, litros: 0 27
Surtidor, litros: 11 300
Se llenará con 0 litros
Surtidor, litros: 2 57
Surtidor, litros: FIN
Día 1 (martes):
...
Día 6 (domingo):
...
Además de los datos recogidos diariamente, al principio de la semana se solicitará la siguiente información:
1. Para cada surtidor se pedirá el tipo de combustible que almacena, sabiendo que hay cinco tipos distintos
de combustible codificados de la siguiente manera:
0) EuroSuper’95 1) Extra’98 2) Star’97 3) ExtraDiesel 4) Gasoleo-A
Ejemplo:
Introduce el tipo de combustible de cada surtidor:
Surtidor 0: 0
Surtidor 1: 1
Surtidor 2: 0
…
Surtidor 11: 4
2. Se pedirá también, por cada tipo de combustible, la ganancia por litro (en Euros) y se almacenará en otra
tabla.
Ejemplo:
Dame la ganancia por litro de cada tipo de combustible:
Tipo 0: 0.02
Tipo 1: 0.03
…
Tipo 4: 0.02
2. Al principio de la semana, para cada tipo de combustible leer la ganancia que nos da cada litro vendido y
almacenarlo en el array tipoGanancias.
5. Al finalizar la semana, recorrer el array litros y detectar las posiciones dónde encontramos un 0, ya que
esto indicará el día y el surtidor que ha vendido todo el combustible.
6. Para cada día de la semana, sumar lo que se ha vendido entre todos los surtidores. Para calcular lo que
ha vendido un surtidor habrá que restarle a 5000 el valor almacenado en el array litros para ese día y surtidor.
Los valores obtenidos se almacenarán en la array ventasDia. Finalmente, buscar y escribir la posición del
valor máximo en el array ventasDia.
8. Para cada tipo de combustible, multiplicar el valor almacenado en el array ganancias con el valor
acumulado en el array tipoGanancias y dejarlo en el vector ganancias.
9. Calcular el combustible que ha dado mayor ganancia, es decir, calcular la posición del valor máximo en el
array ganancias.
CÓDIGO C
#include <stdio.h>
#include <stdlib.h>
#define DiasSemana 7
#define NumSurtidores 12
#define NumCombustibles 5
char *diaSemana(int d);
char *nombreCombustible(int c);
main()
{
int litros[DiasSemana][NumSurtidores], tipoSurtidor[NumSurtidores], ventasDia[DiasSemana];
float tipoGanancias[NumCombustibles], ganancias[NumCombustibles];
int g, s, sc, sur, lit, d, dMax, dMaxLitros, gMax, combustible, diario,surtidor;
system("CLS");
printf("DATOS FIJOS DE LA SEMANA:\n\n");
// Comienzo de semana, lectura del tipo de combustible que tiene cada surtidor:
printf("Introduce el tipo de combustible que tiene cada surtidor:\n");
for (g=0; g<NumCombustibles; g++)
printf("%d=%s ", g, nombreCombustible(g));
printf("\n\n");
for (s=0; s<NumSurtidores; s++)
{ printf(" Surtidor %d: ", s); sc=scanf("%d", &tipoSurtidor[s]); fflush(stdin);
if (sc!=1 || tipoSurtidor[s]<0 || tipoSurtidor[s]>=NumCombustibles)
{ printf("Tipo incorrecto.\n"); s--; }
}
// Es final de semana, indicar qué días y qué surtidores se han vaciado completamente:
system("CLS");
printf("ESTADISTICAS SEMANALES:\n\n");
for (d=0; d<DiasSemana; d++)
for (s=0; s<NumSurtidores; s++)
if (litros[d][s]==0)
printf("El dia %d (%s) el surtidor %d (%s) se ha quedado sin combustible.\n ", d+1, diaSemana(d), s,
nombreCombustible(tipoSurtidor[s]));
// Indicar qué tipo de gasolina ha dado más beneficio esta semana, y cuánto ha sido:
// Inicializar a cero el array de ganancias
for (g=0; g<NumCombustibles; g++) ganancias[g]=0;
for (s=0; s<NumSurtidores; s++)
{ // Calcular los litros que ha vendido el surtidor s
surtidor=0;
for (d=0; d<DiasSemana; d++)
surtidor = surtidor+(5000-litros[d][s]);
combustible=tipoSurtidor[s]; // Calcular el tipo de gasolina que vende el surtidor s
ganancias[combustible]=ganancias[combustible]+surtidor; // Acumular litros vendidos por tipo de combustible
}
// Calcular ganancias de cada tipo de combustible
for (g=0; g<NumCombustibles; g++)
ganancias[g] = tipoGanancias[g] * ganancias[g];
// Calcular el combustible que ha dado mayor ganancia
gMax=0;
for (g=1; g<NumCombustibles; g++)
if (ganancias[g]>ganancias[gMax]) gMax=g;
printf("El tipo de combustible que ha dado mayor ganancia es %d (%s) con una ganancia de %.2f
euros.\n", gMax, nombreCombustible(gMax), ganancias[gMax]);
system ("PAUSE");
}
char *diaSemana(int d)
{
char *dia[] = {"lunes","martes","miercoles","jueves","viernes","sabado","domingo"};
return dia[d];
}
char *nombreCombustible(int c)
{
char *nombre[] = {"EuroSuper-95","Extra-98","Star-97","ExtraDiesel","Gasoleo-A"};
return nombre[c];
}
AMPLIACIONES PROPUESTAS
1. Al principio de semana introducir, además del tipo de ganancia de cada combustible, también su precio en
euros. Ambos datos se almacenarán en un array de estructuras.
2. En las ventas semanales, introducir cada venta bien en litros o bien en euros. Para ello se pedirán tres
datos (ya no dos): nº surtidor, la letra L (litros) o la E (euros), y la cantidad vendida en litros o en euros.
3. Acumular la cantidad de euros recibidos cada día e imprimirla al finalizar la toma de datos de cada día,
para facilitar la comprobación de la caja diaria. También se imprimirá el total de ventas semanal en euros al
final de la semana.
4. Se podrá cerrar el programa en mitad de la semana, guardando antes todos los datos semanales
registrados hasta el momento en dos ficheros en disco: uno "gasolin1.dat" para los datos más estables de
tipos de surtidores y precio+ganancia de combustibles, y otro "gasolin2.dat" para los datos variables de
ventas semanales. Al comenzar la siguiente sesión del día siguiente, si existen esos ficheros en disco se
cargarán en los diversos arrays de memoria, para continuar con el proceso normal. Al finalizar la semana, el
fichero "gasolin2.dat" se elimina para comenzar la siguiente semana desde cero.
5. Al finalizar la semana, las estadísticas finales obtenidas se guardarán también en el disco, en un archivo
de texto cuyo nombre de fichero sea coincidente con la fecha del día actual de emisión de las estadísticas
(dd-mm-aa.txt). Esto permitirá revisar los datos de semanas pasadas.
CÓDIGO C AMPLIADO
(Las ampliaciones están marcadas en color rojo)
#include <stdio.h>
#include <stdlib.h>
#define DiasSemana 7
#define NumSurtidores 12
#define NumCombustibles 5
//Prototipos de funciones auxiliares
char *diaSemana(int d);
char *nombreCombustible(int c);
char sino(char *mensaje);
char *fechaActual(void);
main()
{
struct tipoCombus
{ float precio, tipoGanancia; } combus[NumCombustibles]; //array de estructuras
float litros[DiasSemana][NumSurtidores];
float ventasDia[DiasSemana], ganancias[NumCombustibles], ventasEuros[DiasSemana];
int tipoSurtidor[NumSurtidores];
int g, s, sc, sur, d, dini=0, dMax, dMaxLitros, gMax, combustible, diario, surtidor, hayFich1=0;
char le, resp, fecha[15]="";
float lit, pvp, totVentas;
FILE *pf;
system("CLS");
printf("DATOS FIJOS DE LA SEMANA:\n\n");
if ((pf=fopen("gasolin1.dat","rb"))!=NULL)
//Existe el fichero gasolin1.dat, lo cargamos en los arrays de surtidores y combustibles
{ fread(tipoSurtidor,sizeof(tipoSurtidor),1,pf); fread(combus,sizeof(combus),1,pf);
fclose(pf); hayFich1=1;
resp=sino("Desea modificar los datos de tipo de combustible por surtidor?");
}
if (!hayFich1 || resp=='S')
{ //Comienzo de semana, lectura del tipo de combustible que tiene cada surtidor:
printf("Introduce el tipo de combustible que tiene cada surtidor:\n");
for (g=0; g<NumCombustibles; g++) printf("%d=%s ", g, nombreCombustible(g));
printf("\n");
for (s=0; s<NumSurtidores; s++)
{ printf(" Surtidor %d: ", s); sc=scanf("%d", &tipoSurtidor[s]); fflush(stdin);
if (sc!=1 || tipoSurtidor[s]<0 || tipoSurtidor[s]>=NumCombustibles)
{ printf("Tipo incorrecto.\n"); s--; }
}
}
if (hayFich1)
resp=sino("\nDesea modificar los datos de precio y ganancia por combustible?");
if (!hayFich1 || resp=='S')
{ //Lectura de los precios y las ganancias por cada litro de combustible vendido
printf("\nIntroduce el precio y la ganancia en Euros de cada litro de combustible:\n");
for (g=0; g<NumCombustibles; g++)
{ printf(" Tipo %d (%s): Precio, ganancia: ", g, nombreCombustible(g));
sc=scanf("%f %f", &combus[g].precio, &combus[g].tipoGanancia); fflush(stdin);
if (sc!=2 || combus[g].precio<0 || combus[g].precio>10 || combus[g].tipoGanancia<0 ||
combus[g].tipoGanancia>10)
{ printf("Datos incorrectos.\n"); g--; }
}
}
if (d<DiasSemana-1)
{ //Grabación de ficheros entre semana
if ((pf=fopen("gasolin1.dat","wb"))==NULL) printf("ERROR de grabacion de fichero gasolin1.dat.\n");
else //Grabar el fichero gasolin1.dat con los datos fijos de surtidores y combustibles
{ fwrite(tipoSurtidor,sizeof(tipoSurtidor),1,pf); fwrite(combus,sizeof(combus),1,pf);
fclose(pf);
printf("Datos fijos de surtidores y combustibles guardados.\n");
}
//Indicar qué tipo de gasolina ha dado más beneficio esta semana, y cuánto ha sido
//Inicializar a cero el array de ganancias
for (g=0; g<NumCombustibles; g++) ganancias[g]=0;
for (s=0; s<NumSurtidores; s++)
{ // Calcular los litros que ha vendido el surtidor s
for (surtidor=d=0; d<DiasSemana; d++) surtidor += (5000-litros[d][s]);
combustible=tipoSurtidor[s]; //Calcular el tipo de gasolina que vende el surtidor s
ganancias[combustible]+=surtidor; //Acumular litros vendidos por tipo de combustible
}
//Calcular ganancias de cada tipo de combustible
for (g=0; g<NumCombustibles; g++) ganancias[g] *= combus[g].tipoGanancia;
for (gMax=g=0; g<NumCombustibles; g++) //Calcular el combustible que ha dado mayor ganancia
if (ganancias[g]>ganancias[gMax]) gMax=g;
printf("El tipo de combustible que ha dado mayor ganancia es %d (%s) con una ganancia de %.2f
Euros.\n", gMax, nombreCombustible(gMax), ganancias[gMax]);
if (pf!=NULL) fprintf(pf, "El tipo de combustible que ha dado mayor ganancia es %d (%s) con una
ganancia de %.2f Euros.\n", gMax, nombreCombustible(gMax), ganancias[gMax]);
fclose(pf);
remove("gasolin2.dat"); //Borrar fichero de ventas y litros para comenzar la siguiente semana
}
system ("PAUSE");
}
char *diaSemana(int d) //devuelve el nombre del dia de la semana en función del nº de día
{ char *dia[] = {"lunes","martes","miercoles","jueves","viernes","sabado","domingo"};
return dia[d];
}
char sino(char *mensaje) //Presenta una pregunta en pantalla y lee una respuesta de tipo S/N
{ char resp;
fflush(stdin);
do
{ printf("%s (S/N): ", mensaje); resp=toupper(getchar()); fflush(stdin);
} while (resp!='N' && resp!='S');
return resp;
}
1. La entrada de datos se deberá programar de forma que, para cada semana, se introduzcan las energías
suministradas durante los 7 días. Cuando se desee finalizar la entrada de datos (por ejemplo, en el caso de
realizar el estudio para un periodo inferior a las 52 semanas) se tecleará FIN como dato de energía en el
primer día de la semana.
Ejemplo de entrada de datos:
Semana 1:
Energía suministrada del día 1: 207
Energía suministrada del día 2: 301
Energía suministrada del día 3: 222
Energía suministrada del día 4: 302
Energía suministrada del día 5: 22
Energía suministrada del día 6: 167
Energía suministrada del día 7: 125
Semana 2:
Energía suministrada del día 1: 367
Energía suministrada del día 2: 60
Energía suministrada del día 3: 120
Energía suministrada del día 4: 111
Energía suministrada del día 5: 301
Energía suministrada del día 6: 400
Energía suministrada del día 7: 434
Semana 3:
Energía suministrada del día 1: 211
Energía suministrada del día 2: 72
Energía suministrada del día 3: 441
Energía suministrada del día 4: 102
Energía suministrada del día 5: 21
Energía suministrada del día 6: 203
Energía suministrada del día 7: 317
Semana 4:
Energía suministrada del día 1: 401
Energía suministrada del día 2: 340
Energía suministrada del día 3: 161
Energía suministrada del día 4: 297
Energía suministrada del día 5: 441
Energía suministrada del día 6: 117
Energía suministrada del día 7: 206
Semana 5:
Energía suministrada del día 1: FIN
2. Para cada día de la semana, calcular y escribir la energía media e indicar cuál ha sido el día de mayor
energía media.
4. Calcular y escribir el número de días en los que la energía suministrada ha sido superior a la energía
media de todo el periodo (calculado en el apartado anterior).
5. Debido al libre mercado, semanalmente se establecen los precios de ganancia por megavatio-hora.
Introducir en un array la ganancia (€/megavatio) para cada semana del periodo estudiado, y calcular y
escribir la ganancia semanal y total de la central.
3. Mientras la energía leída (valorLunes) sea distinta de FIN y el contador de semanas (semanas) sea menor
a NumSemanas, hacer:
a. Almacenar la energía leída en la matriz potencias, en la fila semana y columna 0 (lunes).
b. Para el resto de los días de la semana (dia), leer la energía y almacenarla en la matriz potencias, en la
fila semana y columna dia.
c. Incrementar el contador semanas.
d. Leer la energía correspondiente al primer día de la semana (valorLunes).
4. Concluida la introducción semanal, decrementar en 1 el contador semanas para que indique el número de
la última semana hasta la que se han introducido datos.
5. Calcular la energía media de la semana y, para cada día, la energía media consumida y almacenarlo en el
array mediaD, de la siguiente forma:
a. Inicializar la energía media de la semana a 0 (enerMedia).
b. Para cada día de la semana:
I) Inicializar la suma de energías del día a 0 (mediaD[dia]=0).
II) Para cada semana tratada, acumular la energía gastada ese día de esa semana en la suma de
energías (mediaD).
III) Dividir la suma de las energías consumidas entre las semanas tratadas.
IV) Acumular la energía del día a la energía media de la semana.
6. Calcular la energía media de la semana. Para ello dividir la suma de las energías medias diarias
(enerMedia) entre el número de días. Escribir el resultado por pantalla.
7. Calcular el día de mayor consumo de la semana. Para ello hay que buscar la posición del valor máximo en
el array mediaD.
9. Para cada día de la semana, si la energía consumida esa semana y ese día ( energias[sem][dia]) es mayor
a la energía media (enerMedia) entonces incrementar el contador (diasPM).
11. Calcular la ganancia semanal y la ganancia de todo el periodo. Para ello, inicializar a 0 la ganancia total
(gananciaTotal), y luego para cada semana:
a. Poner a 0 la ganancia de la semana (gananciaSemanal).
b. Para cada día acumular la energía consumida y almacenarlo en la variable gananciaSemanal.
c. Multiplicar la ganancia semanal (gananciaSemanal) con el precio del megavatio por cada semana
(almacenado en el array gananciaPS), y escribir por pantalla el resultado obtenido.
d. Acumular la ganancia semanal (gananciaSemanal) a la ganancia total (gananciaTotal).
CÓDIGO C
#include <stdio.h>
#include <stdlib.h>
#define NumDias 7
#define NumSemanas 52
char *diaSemana(int d);
main()
{
int energias[NumSemanas][NumDias];
float mediaD[NumDias], gananciaPS[NumSemanas];
float enerMedia, gananciaTotal, gananciaSemanal;
int semanas, diasPM, valor, dia, sem, dMax, sc;
// Calculo de ganancias
printf("\nLas ganancias semanales son:\n");
gananciaTotal=0;
for (sem=0; sem<semanas; sem++)
{ gananciaSemanal=0;
for (dia=0; dia<NumDias; dia++)
gananciaSemanal = gananciaSemanal+energias[sem][dia];
gananciaSemanal = gananciaSemanal*gananciaPS[sem];
printf("Semana %d - Ganancia: %.2f Euros\n", sem, gananciaSemanal);
gananciaTotal = gananciaTotal+gananciaSemanal;
}
printf("\nLa ganancia total conseguida es: %.2f Euros\n\n", gananciaTotal);
system("PAUSE");
}
char *diaSemana(int d)
{
char *dia[] = {"lunes","martes","miercoles","jueves","viernes","sabado","domingo"};
return dia[d];
}
AMPLIACIONES PROPUESTAS
1. Hacer que el programa solicite por teclado el número máximo de semanas a procesar (ya no será fijo 52
semanas), cuando se ejecute por primera vez. Luego se crearán y utilizarán "arrays dinámicos" del tamaño
indicado por este número de semanas.
2. Permitir la terminación prematura del programa sin haber introducido todos los datos, guardando en un
fichero en disco de nombre "central.dat" todos los datos de energías y precios introducidos hasta el momento.
Esto permitirá introducir los datos en varias sesiones del programa, cargando los datos del fichero al empezar
cada sesión.
3. Controlar los valores introducidos por teclado y emitir pitidos (\a) si son incorrectos, para volverlos a
introducir.
CÓDIGO C AMPLIADO
(Las ampliaciones están marcadas en color rojo)
#include <stdio.h>
#include <stdlib.h>
#define NumDias 7
char *diaSemana(int d);
int **crearArrayBidimensional(int filas, int columnas);
main()
{
int NumSemanas=0, **energias;
float mediaD[NumDias], *gananciaPS;
float enerMedia, gananciaTotal, gananciaSemanal;
int semanas, diasPM, valor, dia, sem=0, semini=0, seminiG=0, dMax, sc;
FILE *pf;
system("CLS");
//Calculo de ganancias
printf("\nLas ganancias semanales son:\n");
gananciaTotal=0;
for (sem=0; sem<semanas; sem++)
{ gananciaSemanal=0;
for (dia=0; dia<NumDias; dia++)
gananciaSemanal = gananciaSemanal+energias[sem][dia];
gananciaSemanal = gananciaSemanal*gananciaPS[sem];
printf("Semana %d - Ganancia: %.2f Euros\n", sem, gananciaSemanal);
gananciaTotal = gananciaTotal+gananciaSemanal;
}
printf("\nLa ganancia total conseguida es: %.2f Euros\n\n", gananciaTotal);
//Grabar los ficheros
if ((pf=fopen("central1.dat", "wb"))==NULL) printf("ERROR al grabar fichero central1.dat.\a\a\n");
else { fwrite(gananciaPS, NumSemanas*sizeof(float), 1, pf); fclose(pf); }
if ((pf=fopen("central2.dat", "wb"))==NULL) printf("ERROR al grabar fichero central2.dat.\a\a\n");
else
{ for (sem=0; sem<NumSemanas; sem++) fwrite(energias[sem], NumDias*sizeof(int), 1, pf);
fclose(pf);
}
system("PAUSE");
}
1. Leer las ventas de los artículos (en unidades) a lo largo de los 12 meses del año 2015.
Ejemplo de ejecución:
Introduce las ventas de los artículos de la siguiente forma (en negrita los datos tecleados por el usuario):
Artículo, mes, unidades vendidas: 1 5 800
Artículo, mes, unidades vendidas: 0 4 700
Artículo, mes, unidades vendidas: 4 5 100
Artículo, mes, unidades vendidas: 6 5 800
Artículo, mes, unidades vendidas: 6 11 800
..............
Artículo, mes, unidades vendidas: 1 0 800
Artículo, mes, unidades vendidas: FIN
Los datos se introducen a través de tríos desordenados (Artículo, mes, unidades vendidas). Sólo se
introducen los datos de los meses y artículos que han tenido ventas. Las ventas indicarán el total de
unidades vendidas de ese artículo en ese mes.
2. Leer la lista de precios por artículo y obtener el mes que más ventas en euros ha tenido.
Ejemplo de ejecución:
Introduce los precios de los artículos (en negrita los datos tecleados por el usuario):
Precio del artículo 0: 123,50
Precio del artículo 1: 12,03
Precio del artículo 2: 1,73
............
Precio del artículo 9: 129
El mes 3 es el mes que más ventas ha tenido: 1000,50 euros.
3. Por cada artículo leer el total de ventas en euros del periodo comprendido entre los meses de julio y
diciembre del año 2014.
Ejemplo de ejecución:
Introduce las ventas en euros realizadas entre los meses de Julio y Diciembre del 2014:
Ventas del artículo 0: 970,52
Ventas del artículo 1: 8870,75
Ventas del artículo 2: 1170
...................
Ventas del artículo 9: 909870
4. Obtener estadísticas finales comparando estos datos de 2014 con los del mismo periodo del 2015 (leídos
en el apartado 1) e indicando cuántos artículos han superado las ventas en euros en el año 2015 y cuáles
son estos artículos.
Ejemplo de ejecución:
Los artículos que han superado las ventas, en el periodo comprendido entre los meses de Julio a Diciembre,
respecto al año 2014 son: 2, 5, 6, 9
Total artículos: 4
6. Calcular y escribir el mes de mayor ganancia, es decir, calcular la posición del valor máximo del array
ventasMes (calculado en el apartado 5).
7. Leer las ventas en euros de cada artículo correspondiente a los meses de Julio-Diciembre del año 2014 y
almacenarlo en el array ventas2014.
8. Calcular las ventas en euros de cada artículo correspondientes a los meses de Julio-diciembre del año
2015. Para ello, realizaremos para cada artículo los siguientes pasos:
a. Inicializar ventas del artículo a 0 (ventas2015)
b. Para cada mes entre los meses de Julio a Diciembre sumar la cantidad de artículos vendidos ese mes
(almacenada en la matriz ventas) a los ya acumulados.
c. Multiplicar la cantidad de artículos vendidos por el precio del artículo (almacenado en el array precio).
10. Para cada artículo (art), si las ventas del año 2015 (ventas2015[art]) son mayores que las del año 2014
(ventas2014[art]) entonces escribir el número del artículo e incrementar contador (num) en 1.
CÓDIGO C
#include <stdio.h>
#include <stdlib.h>
#define NumArticulos 10
#define NumMeses 12
#define Julio 7
main()
{
int ventas[NumArticulos][NumMeses];
float ventas2014[NumArticulos], ventas2015[NumArticulos], ventasMes[NumMeses];
float precio[NumArticulos];
int mVentaMax, art, mes, vent, num, sc;
// Inicializar a 0 la matriz Ventas para que todas las posiciones tengan valores válidos tras la lectura
for (art=0; art<NumArticulos; art++)
for (mes=0; mes<NumMeses; mes++)
ventas[art][mes]=0;
// Comparar las ventas del periodo de Julio-Diciembre del año 2014 y 2015
printf("\nLos articulos que han superado las ventas en el periodo comprendido entre los meses de Julio y
Diciembre de 2015, respecto al año 2014, son: ");
num=0;
for (art=0; art<NumArticulos; art++)
if (ventas2014[art]<ventas2015[art])
{ printf("%d ", art); num++; }
printf("\nTotal articulos: %d\n\n", num);
system ("PAUSE");
}
AMPLIACIONES PROPUESTAS
1. Manejar el programa mediante un Menú principal con las siguientes opciones: "1-Leer Ventas 2015", "2-
Leer Precios 2015", "3-Leer Ventas 2014", "4-Mostrar Estadísticas", "0-Salir".
2. Controlar los valores introducidos por teclado y emitir pitidos si son incorrectos, para volverlos a introducir.
3. Permitir la terminación prematura del programa sin haber introducido todos los datos y precios de artículos,
guardando en un fichero en disco de nombre "tienda.dat" todos los datos introducidos hasta el momento. Esto
permitirá introducir los datos en varias sesiones del programa, cargando los datos del fichero al empezar
cada sesión.
4. Las estadísticas finales sólo se emitirán cuando estén introducidos todos los precios de los 10 artículos.
5. Escribir el nombre del mes en el mensaje de salida del mes con mayor ganancia.
CÓDIGO C AMPLIADO
(Las ampliaciones están marcadas en color rojo)
#include <stdio.h>
#include <stdlib.h>
#include <graph.h> //necesario para la función _settextposition
#define cursor(a,b) _settextposition(a,b) //Macro para posicionar el cursor de texto en la pantalla
#define NumArticulos 10
#define NumMeses 12
#define Julio 7
//declaraciones prototipo de funciones auxiliares
char *nombreMes(int d);
char menu(void);
void marco(int fil1, int col1, int fil2, int col2);
main()
{
int ventas[NumArticulos][NumMeses];
float ventas2014[NumArticulos], ventas2015[NumArticulos], ventasMes[NumMeses];
float precio[NumArticulos];
int mVentaMax, art, mes, vent, num, sc, leido;
FILE *pf; char opc=' ';
if ((pf=fopen("tienda.dat","rb"))!=NULL) //Cargar fichero de datos en los arrays
{ fread(ventas, sizeof(ventas), 1, pf); fread(precio, sizeof(precio), 1, pf); fclose(pf); }
else //Inicializar a 0 los arrays
{ for (art=0; art<NumArticulos; art++)
for (mes=0; mes<NumMeses; mes++)
ventas[art][mes]=0;
for (art=0; art<NumArticulos; art++) precio[art]=0;
}
void marco(int fil1, int col1, int fil2, int col2) //Pintar un marco de asteriscos
{ int i;
cursor(fil1,col1); for (i=0; i<col2-col1+1; i++) printf("*");
for (i=fil1+1; i<fil2; i++)
{ cursor(i,col1); printf("*"); cursor(i,col2); printf("*"); }
cursor(fil2,col1); for (i=0; i<col2-col1+1; i++) printf("*");
}
CONTROL DE PEAJES EN AUTOPISTA
Una autopista desea un programa informático que recoja mensualmente datos sobre los consumos de sus
clientes habituales y realice los cálculos que abajo se enumeran. El programa recogerá el número de veces
que pasan los clientes habituales por los distintos peajes de la autopista, todo ello con vistas a poder
realizarles una serie de descuentos y poder realizar también un estudio estadístico.
Esta autopista tiene actualmente 1000 clientes reconocidos como habituales a través de un contrato, y el
número de peajes en este trayecto es de 15. En un array tendremos que introducir los precios de cada uno
de los 15 peajes. Para ello el programa le pedirá al usuario el precio de cada peaje de forma secuencial.
Después se introducirán los datos de los clientes mediante pares de datos que indiquen número de cliente y
número de peaje por el que ha pasado. Tenemos que tener en cuenta que puede haber más de una entrada
para el mismo cliente y número de peaje, con lo que habrá que acumular el número de veces que ha pasado
por el mismo peaje.
Además, a la vez que introducimos estos datos, habrá que calcular en dos arrays el número total de viajes
que lleva realizados el cliente y el importe que va acumulando por todos sus tránsitos, teniendo en cuenta
que al precio del peaje se le aplica un descuento en función del siguiente criterio:
• a los 8 primeros viajes un 25% sobre el precio del peaje.
• del 9º al 20º viaje un 55% sobre el precio del peaje.
• a partir del 20º un 75% sobre el precio del peaje.
6. Necesitaremos un array debePagar de NumClientes posiciones para almacenar los euros que tiene que
pagar cada uno de los clientes habituales.
debePagar: 0 1 2 ….. NumClientes-1 <= CLIENTE
7. Necesitamos un array pasoPeajes de NumPeajes posiciones para almacenar el número de veces que se
ha pasado por cada uno de los peajes.
pasoPeajes: 0 1 2 ….. NumPeajes-1 <= PEAJE
9. Necesitamos un array ahorro de NumClientes posiciones para almacenar la cantidad de euros que ahorra
cada uno de los clientes habituales.
ahorro: 0 1 2 ….. NumClientes-1 <= CLIENTE
7. Para cada peaje, calcular el número de veces que han pasado el conjunto de los clientes habituales por él.
8. Calcular el mayor valor del array pasoPeajes para saber cuál ha sido el peaje por el que han pasado más
clientes habituales.
9. Para cada cliente, buscar cuál es el peaje por donde ha pasado más veces.
11. Para cada cliente, calcular cuánto deberían haber pagado sin descuentos.
CODIGO C
#include <stdio.h>
#include <stdlib.h>
#define NumPeajes 15
#define NumClientes 10
main()
{
int viajes[NumClientes][NumPeajes];
float precioPeajes[NumPeajes], debePagar[NumClientes];
int viajesTotales[NumClientes], pasoPeajes[NumPeajes];
float deberiaHaberPagado[NumClientes], ahorro[NumClientes];
int c, p, maxPeaje, sc;
system("CLS");
AMPLIACIONES PROPUESTAS
1. Manejar el programa mediante un Menú principal con las siguientes opciones: "P-Leer precios de Peajes",
"C-Leer datos de Clientes", "M-Mostrar peajes más utilizados", "L-Listar resultados de clientes", "S-Salir". El
menú se podrá utilizar mediante las teclas de cursor-arriba, cursor-abajo y Enter, además de poder utilizar las
letras identificativas de cada opción (PCMLS).
2. Al terminar el programa, guardar en un fichero el array de precios de los peajes y la matriz de viajes
realizados. En la siguiente sesión del programa, si tal fichero existe, cargarlo en los arrays de memoria para
continuar leyendo nuevos datos de viajes realizados.
CÓDIGO C AMPLIADO
(Las ampliaciones están marcadas en color rojo)
#include <stdio.h>
#include <stdlib.h>
#include <graph.h> //necesario para la función _settextposition
#define cursor(a,b) _settextposition(a,b) //Macro para posicionar el cursor de texto en la pantalla
#define NumPeajes 15
#define NumClientes 10
//declaraciones prototipo de funciones auxiliares
char sino(char *msg);
char menu(void);
void marco(int fil1, int col1, int fil2, int col2);
void marcoDoble(int fil1, int col1, int fil2, int col2);
int incluido(char car, char *cars);
main()
{
int viajes[NumClientes][NumPeajes];
float precioPeajes[NumPeajes], debePagar[NumClientes];
int viajesTotales[NumClientes], pasoPeajes[NumPeajes];
float deberiaHaberPagado[NumClientes], ahorro[NumClientes];
int c, p, maxPeaje, sc;
FILE *pf; char opc=' ';
system("CLS");
if ((pf=fopen("autopis.dat","rb"))!=NULL)
{ fread(precioPeajes,sizeof(precioPeajes),1,pf);
fread(viajes,sizeof(viajes),1,pf); fread(viajesTotales,sizeof(viajesTotales),1,pf);
fclose(pf);
}
char sino(char *mensaje) //muestra pregunta en pantalla y acepta respuesta de tipo S/N
{ char resp;
fflush(stdin);
do
{ printf("%s (S/N): ", mensaje); resp=toupper(getchar()); fflush(stdin);
} while (resp!='N' && resp!='S');
return resp;
}
void marco(int fil1, int col1, int fil2, int col2) //Pinta un marco con linea simple
{ int i;
cursor(fil1,col1); printf("\xDA");
for (i=0; i<col2-col1-1; i++) printf("\xC4");
printf("\xBF");
for (i=fil1+1; i<fil2; i++)
{ cursor(i,col1); printf("\xB3"); cursor(i,col2); printf("\xB3"); }
cursor(fil2,col1); printf("\xC0");
for (i=0; i<col2-col1-1; i++) printf("\xC4");
printf("\xD9");
}
void marcoDoble(int fil1, int col1, int fil2, int col2) //Pinta un marco con linea doble
{ int i;
cursor(fil1,col1); printf("\xC9");
for (i=0; i<col2-col1-1; i++) printf("\xCD");
printf("\xBB");
for (i=fil1+1; i<fil2; i++)
{ cursor(i,col1); printf("\xBA"); cursor(i,col2); printf("\xBA"); }
cursor(fil2,col1); printf("\xC8");
for (i=0; i<col2-col1-1; i++) printf("\xCD");
printf("\xBC");
}
#define NumOpciones 5
char menu(void) //MENU CONTROLADO POR LAS TECLAS DE CURSOR
{
char menus[NumOpciones][40]={" P. Leer precios de Peajes. "," C. Leer datos de Clientes. "," M.
Mostrar peajes mas utilizados. "," L. Listar resultados de clientes. "," S. Salir del programa. "};
char letras[ ]="PCMLS", op;
int i, actual=0;
system("cls");
marco(1,1,24,80); marcoDoble(8,22,14,58);
do
{ for (i=0; i<NumOpciones; i++) { cursor(i+9,23); _outtext(menus[i]); }
_settextcolor(0); _setbkcolor(7); //activar video inverso
cursor(actual+9,23); _outtext(menus[actual]); //imprime texto con atributos de colores
_settextcolor(7); _setbkcolor(0); //desactivar video inverso
cursor(16,22); printf("Seleccione la operacion a realizar: "); op = toupper(getch());
if (op==0x0D) { op=letras[actual]; break; } //Tecla ENTER
else if (op==0x1B) { op='S'; break; } //Tecla ESC = Salir
else if (op==0) //Teclas especiales
{ op=getch();
if (op==0x50) //Cursor abajo
{ if (actual==NumOpciones-1) actual=0; else actual++; }
else if (op==0x48) //Cursor arriba
{ if (actual==0) actual=NumOpciones-1; else actual--; }
op=' ';
}
} while (!incluido(op,letras));
system("cls");
return (op);
}
int incluido(char car, char *cars) //devuelve cierto si el caracter car está incluido en la cadena cars
{ int i, n=strlen(cars);
for (i=0; i<n; i++)
if (car==cars[i]) return 1;
return 0;
}
APLICACIÓN DE BASE DE DATOS
Programa de base de datos para un fichero con número de registros ilimitado, registros compuestos por los
siguientes campos:
* Nombre (hasta 40 caracteres, formato "Apellidos, Nombre")
* DNI (8 dígitos y letra final calculada automáticamente)
* Fecha nacimiento (dd/mm/aaaa)
* Direccion (hasta 40 caracteres)
* Código Postal (5 dígitos)
* Poblacion (hasta 30 caracteres)
* Teléfono fijo (9 dígitos)
* Teléfono móvil (9 dígitos)
* Email (hasta 30 caracteres)
* Cuenta bancaria IBAN (XX99-9999-9999-99-9999999999, Pais-Banco-Sucursal-Control-Cuenta, con
verificación automática de los dígitos de Control)
El programa mostrará el registro actual en la parte superior de la pantalla (utilizando colores en pantalla) y
debajo el menú principal de mantenimiento de datos y navegación en el fichero, con las siguientes opciones:
- Añadir nuevos registros
- Modificar el registro actual
- Eliminar el registro actual
- Listar los registros en pantalla
- Ordenar los registros por nombre o por DNI
- Buscar registros por nombre o por DNI
- Ir al siguiente registro
- Ir al anterior registro
- Ir al primer registro del fichero
- Ir al último registro del fichero
- Saltar un número de registros adelante o atrás
- Ir a un registro por su número
- Ver u ocultar los registros eliminados
- Borrar definitivamente todos los registros eliminados
- Exportar fichero a formato Excel CSV
- Salir de la aplicación
La eliminación de registros se realiza de forma rápida mediante un campo adicional en el registro (campo
"Eliminado"), que es puesto a valor "S" cuando el registro es eliminado y eso ocultará el registro en el resto
del programa. Existe también una operación especial para eliminar definitivamente todos los registros
marcados como "eliminados", creando un nuevo fichero sin registros basura.
CÓDIGO C
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <graph.h>
#define cursor(a,b) _settextposition(a,b) //Macro para posicionar el cursor de texto
struct tipocuenta
{ char pais[5];
short banco, sucursal;
char control;
double cuenta; };
struct registro
{ char nombre[41], dni[10], direccion[41], poblacion[31], email[31];
long codpostal, telefono, movil;
struct tipofecha fechanac;
struct tipocuenta cuentaiban;
char eliminado;
};
void verregistro(void); //Prototipos de funciones auxiliares
void nuevoreg(void);
void limpiarReg(void);
int introducir(int esModif);
int oknombre(char *cad);
int okdni(char *cad);
int okfecha(struct tipofecha fecha);
int oktelefono(long tfno);
int okmovil(long tfno);
int okcuenta(struct tipocuenta cta);
char digControl(short banco, short sucursal, double cuenta);
void modireg(void);
void elimreg(void);
void listareg(void);
void siguiente(void);
void anterior(void);
void primero(void);
void ultimo(void);
void saltar(void);
void iranumero(void);
void ordenar(int esnombre);
void buscarnom(void);
void buscardni(void);
void verelim(void);
void borraelim(void);
void aexcel(void);
char sino(char *cad);
void leecad(char *cad, int n);
char *conAcentos(char *cad);
int incluido(char c, char *cad);
void marco(int fil1, int col1, int fil2, int col2);
void marcoDoble(int fil1, int col1, int fil2, int col2);
void color(char lapiz, char fondo);
void caja(int fil1, int col1, int fil2, int col2, char fondo);
//Variables globales:
int numregs=0; // Nº total de registros (incluyendo eliminados)
int regnum=0; // Nº del registro activo actual
int tamreg=sizeof(struct registro); // Tamaño en bytes de un registro
struct registro dato; // Registro auxiliar en memoria
char *nomfile="datos.dat"; // Nombre del fichero en disco
char *msg="Pulse una tecla para continuar..."; // Mensaje habitual
FILE *pf; // Puntero controlador del fichero
int verelims=0; // Valor 1 = Permite ver los registros eliminados
switch (menu) //Llamadas a las diversas funciones dependiendo del menu elegido
{ case 'A': nuevoreg(); break;
case 'M': modireg(); break;
case 'E': elimreg(); break;
case 'L': listareg(); break;
case '+': siguiente(); break;
case '-': anterior(); break;
case 'T': saltar(); break;
case 'P': primero(); break;
case 'U': ultimo(); break;
case 'N': iranumero(); break;
case 'O': ordenar(1); break;
case 'D': ordenar(0); break;
case 'B': buscarnom(); break;
case 'V': buscardni(); break;
case 'R': verelim(); break;
case 'Z': borraelim(); break;
case 'X': aexcel(); break;
case 'S': salir=1; break;
}
}
fclose(pf); //Cerrar fichero y terminar
}
void limpiarReg(void) // Poner a cero todos los campos del registro 'dato'
{
int i;
for (i=0; i<41; i++) { dato.nombre[i]=' '; dato.direccion[i]=' '; } //Rellenamos con blancos
for (i=0; i<31; i++) { dato.poblacion[i]=' '; dato.email[i]=' '; }
for (i=0; i<10; i++) dato.dni[i]=' ';
dato.eliminado=' ';
dato.codpostal=dato.telefono=dato.movil=0; //Rellenamos con ceros
dato.fechanac.dia=dato.fechanac.mes=dato.fechanac.anyo=0;
dato.cuentaiban.banco=dato.cuentaiban.sucursal=dato.cuentaiban.control=dato.cuentaiban.cuenta=0;
for (i=0; i<5; i++) dato.cuentaiban.pais[i]=' ';
}
// Introducción de datos por teclado en el registro 'dato', esModif=1 si viene desde 'Modificar Registro'
int introducir(int esModif)
{
char *txt = esModif ? " (Vacio=Sin Modificar)" : ""; // Mensaje de texto auxiliar
char cad[50];
printf("\nIntroduzca los%s datos del registro:\n", esModif ? " nuevos" : "");
int oknombre(char *cad) // Verifica el formato correcto del nombre (Apellidos, Nombre)
{
int count=0;
if (*cad==0) return 1; //Si el campo se deja vacío
while (*cad!=0)
if (*cad++==',') count++; //Contar el número de caracteres 'coma'
if (count!=1) { printf("Error, el formato debe ser: Apellidos, Nombre\n"); return 0; }
return 1; //Retorna 1 si OK, retorna 0 si error
}
int okdni(char *cad) // Verifica el formato correcto del DNI (8 dígitos y una letra), calcula la letra correcta
{
int i=0; //Aquí se implementa el algoritmo de cálculo de la letra final de DNI
char letras[]=" RWAGMYFPDXBNJZSQVHLCKET", letra;
if (cad[0]==0) return 1;
while (cad[i]>='0' && cad[i]<='9') i++;
if (i!=8) { printf(conAcentos("Error: deben ser 8 dígitos\n")); return 0; }
i=atol(cad)%23; if (i==0) i=23;
letra=letras[i];
if (cad[8]!=0 && cad[8]!=letra) { printf("Error en la letra final.\n"); return 0; }
if (cad[8]==0) { printf("Anotamos la letra final %c\n", letra); cad[8]=letra; cad[9]=0; }
return 1; //Retorna 1 si OK, retorna 0 si error
}
char digControl(short banco, short sucursal, double cuenta) //Calcula los dígitos de control de la cuenta
{ //Aquí se implementa el algoritmo de cálculo de los dígitos de control
int tot, i, n;
char pesos[]="6379058421", cad[11], resul;
sprintf(cad, "%04d%04d", banco, sucursal); n=strlen(cad);
for (tot=i=0; i<n; i++) tot += (cad[n-i-1]-'0')*(pesos[i]=='0'?10:pesos[i]-'0');
tot = 11-tot%11;
if (tot==10) tot=1;
else if (tot==11) tot=0;
resul = tot*10;
sprintf(cad, "%10.0f", cuenta); n=strlen(cad);
for (tot=i=0; i<n; i++) tot += (cad[n-i-1]-'0')*( pesos[i]=='0'?10:pesos[i]-'0');
tot = 11-tot%11;
if (tot==10) tot=1;
else if (tot==11) tot=0;
resul += tot;
return resul;
}
void ordenar(int esnombre) // Ordenar el fichero por Nombre o DNI (por Nombre si esnombre==1)
{
int x,j,cambio; char cad[60];
struct registro aux, aux2;
verregistro();
printf("ORDENAR POR %s:\n", esnombre?"NOMBRE":"DNI");
printf("Ordenando...\n");
for (x=numregs-1; x>0; x--) //metodo de ordenación de "la burbuja"
{
cambio=0; //indicador de "intercambio realizado"
for (j=0; j<x; j++) //j indica el nº de registro actual del fichero
{
fseek(pf,j*tamreg,SEEK_SET); //colocar L/E del fichero al principio del registro j
fread(&aux,tamreg,1,pf); //leemos en aux el registro j, y en aux2 el j+1
fread(&aux2,tamreg,1,pf);
if ((esnombre ? strcmp(aux.nombre,aux2.nombre) : strcmp(aux.dni,aux2.dni)) > 0)
{ //Si están en orden incorrecto
cambio=1;
fseek(pf,j*tamreg,SEEK_SET); //volver a colocar L/E del fichero en el registro j
fwrite(&aux2,tamreg,1,pf); //grabamos los dos registros intercambiados (aux2+aux)
fwrite(&aux,tamreg,1,pf);
}
}
if (!cambio) break; //si no ha habido ningún cambio, terminamos
}
rewind(pf); regnum=0;
printf("%s. %s", conAcentos("Ordenación realizada"), msg); getch();
}
void verelim(void) // Cambia el modo de visualizar los registros eliminados (visibles o no visibles)
{
verelims = !verelims;
}
void aexcel(void) // Exportar a fichero Excel CSV (campos de texto separados por ';')
{
FILE *pf2;
int nreg=0;
verregistro();
printf("EXPORTAR A EXCEL:\n");
if ((pf2=fopen("datos.csv","w"))==NULL) { printf("Error de apertura en DATOS.CSV\n"); return; }
rewind(pf);
fprintf(pf2,"Reg.;Nombre;DNI;FechaNacim;Dirección;Cod.Postal;Población;Teléfono;Móvil;Email;Cuenta Bancaria\n");
fread(&dato, tamreg, 1, pf);
while (!feof(pf) && !ferror(pf) && !ferror(pf2)) //Bucle de lectura secuencial del fichero
{
if (verelims || dato.eliminado!='S')
{ fprintf(pf2,"\n%d;%s;%s;%d/%d/%d;%s;%5ld;%s;%ld;%ld;%s;%s-%04d-%04d-%02d-%10.0lf", nreg+1, dato.nombre,
dato.dni, dato.fechanac.dia, dato.fechanac.mes, dato.fechanac.anyo, dato.direccion, dato.codpostal, dato.poblacion,
dato.telefono, dato.movil, dato.email, dato.cuentaiban.pais, dato.cuentaiban.banco, dato.cuentaiban.sucursal,
dato.cuentaiban.control, dato.cuentaiban.cuenta);
if (dato.eliminado=='S') fprintf(pf2,";ELIMINADO");
}
nreg++; fread(&dato, tamreg, 1, pf);
}
if (ferror(pf)) { printf("Error de lectura en %s\n",nomfile); clearerr(pf); }
if (ferror(pf2)) printf("Error de escritura en datos.csv\n");
printf("Fichero Excel DATOS.CSV generado. %s\n",msg); getch();
fclose(pf2);
fseek(pf,regnum*tamreg,SEEK_SET); //Apuntador L/E al registro Nº regnum
}
void leecad(char *cad, int n) //Lee una cadena desde el teclado con número máximo de caracteres 'n' a leer
{
fgets(cad,n,stdin); fflush(stdin); n=strlen(cad)-1;
if (cad[n]=='\n') cad[n]=0;
}
char *conAcentos(char *cad) //Devuelve la cadena cad con los acentos y Ññ corregidos para una correcta impresión
{
int i=strlen(cad);
while (--i>=0)
{ switch (cad[i])
{ case 'á': cad[i]='\xA0'; break;
case 'é': cad[i]='\x82'; break;
case 'í': cad[i]='\xA1'; break;
case 'ó': cad[i]='\xA2'; break;
case 'ú': cad[i]='\xA3'; break;
case 'ñ': cad[i]='\xA4'; break;
case 'Ñ': cad[i]='\xA5'; break;
case 'ü': cad[i]='\x81'; break;
case '¿': cad[i]='\xA8'; break;
}
}
return cad;
}
int incluido(char c, char *cad) // Verifica si el caracter c está incluido en la cadena cad
{
while (*cad!=c && *cad!=0) cad++;
return *cad==c;
}
void marco(int fil1, int col1, int fil2, int col2) //Pinta un marco con linea simple
{ int i;
cursor(fil1,col1); _outtext("\xDA");
for (i=0; i<col2-col1-1; i++) _outtext("\xC4");
_outtext("\xBF");
for (i=fil1+1; i<fil2; i++)
{ cursor(i,col1); _outtext("\xB3"); cursor(i,col2); _outtext("\xB3"); }
cursor(fil2,col1); _outtext("\xC0");
for (i=0; i<col2-col1-1; i++) _outtext("\xC4");
_outtext("\xD9");
}
void marcoDoble(int fil1, int col1, int fil2, int col2) //Pinta un marco con linea doble
{ int i;
cursor(fil1,col1); _outtext("\xC9");
for (i=0; i<col2-col1-1; i++) _outtext("\xCD");
_outtext("\xBB");
for (i=fil1+1; i<fil2; i++)
{ cursor(i,col1); _outtext("\xBA"); cursor(i,col2); _outtext("\xBA"); }
cursor(fil2,col1); _outtext("\xC8");
for (i=0; i<col2-col1-1; i++) _outtext("\xCD");
_outtext("\xBC");
}
void caja(int fil1, int col1, int fil2, int col2, char fondo)
{ /* Pinta una caja rellena desde la esquina superior izquierda fil1,col1
hasta la esquina inferior derecha fil2,col2, con el color de fondo especificado
Ejemplo de uso: caja(1,1,10,20,'Z');
*/
int i,j,f;
char colores[]="NZVCRGMB";
for (f=0; f<8; f++)
if (fondo==colores[f]) break;
if (f<8) _setbkcolor((long)f);
for (i=0; i<fil2-fil1+1; i++)
{ cursor(fil1+i,col1); for (j=0; j<col2-col1+1; j++) _outtext(" "); }
}