-
Ejercicio 0201r01.-
Construir un programa que muestre un menú y e indique la opción seleccionada, empleando una enumeración y una lista de cadenas.
La solución podría ser la siguente:
/*
Construir un programa que muestre un menú y e indique la
opción seleccionada, empleando una enumeración y una
lista de cadenas.
*/
#include<stdio.h>
#include<stdlib.h>
#define NUM_OPCIONES 5
int main(int argc, char * argv[])
{
enum {Nuevo, Abrir, Guardar, Cerrar, Salir};
char menu[][10] = {"Nuevo", "Abrir", "Guardar", "Cerrar", "Salir"};
char opcion;
int i, caso;
do
{
/* Visualizar menú y leer la opción */
printf("\nSeleccione una opción:\n\n");
for(i=0;i<NUM_OPCIONES;i++)
printf("%s (%d) ", menu[i], i);
printf(" : ");
scanf("%c", &opcion);
fpurge(stdin);
/* Mostrar en pantalla la opción seleccionada */
caso = opcion - '0';
switch(caso)
{
case Nuevo: printf("\nSe ha seleccionado la opción %s\n", menu[caso]);
break;
case Abrir: printf("\nSe ha seleccionado la opción %s\n", menu[caso]);
break;
case Guardar: printf("\nSe ha seleccionado la opción %s\n", menu[caso]);
break;
case Cerrar: printf("\nSe ha seleccionado la opción %s\n", menu[caso]);
break;
case Salir: printf("\nSe ha seleccionado la opción %s\n", menu[caso]);
break;
default: printf("\n\nOpción incorrecta\n\n");
break;
}
}
while(caso != Salir);
printf("\n\nFin del programa\n\n");
return 0;
}
/*
Seleccione una opción:
Nuevo (0) Abrir (1) Guardar (2) Cerrar (3) Salir (4) : 0
Se ha seleccionado la opción Nuevo
Seleccione una opción:
Nuevo (0) Abrir (1) Guardar (2) Cerrar (3) Salir (4) : 1
Se ha seleccionado la opción Abrir
Seleccione una opción:
Nuevo (0) Abrir (1) Guardar (2) Cerrar (3) Salir (4) : 2
Se ha seleccionado la opción Guardar
Seleccione una opción:
Nuevo (0) Abrir (1) Guardar (2) Cerrar (3) Salir (4) : 3
Se ha seleccionado la opción Cerrar
Seleccione una opción:
Nuevo (0) Abrir (1) Guardar (2) Cerrar (3) Salir (4) : 4
Se ha seleccionado la opción Salir
Fin del programa
*/
Comentarios
.- El uso paralelo de una enumeración y una lista de cadenas facilita notablemente la construcción del programa; además, se entiende claramente el sentido de las acciones desencadenadas por el programa principal. Obsérvese que hemos recurrido a leer un carácter, aun cuando la opción es numérica. Una vez leído el valor de opción, se traduce a un número restándole el valor de '0', de tal modo que el carácter '0' se convierte en el número 0, el carácter '1' se convierte en el número 1, y así sucesivamente. De este modo, no es preciso comparar
opcion
con '4' sino
caso
con
Salir
... y el método debe funcionar siempre, sin cambios. Obsérvese también que se capturan los posibles errores del usuario: si el valor de caso no aparece en la lista de sentencias case, se ejecuta el
default
correspondiente. Por último, el uso de
fpurge(stdin)
garantiza la eliminación de caracteres restantes en el búfer de teclado, quedando este limpio y preparado para nuevas lecturas. Esto tendrá importancia en aquellos programas en que la activación de una opción desencadene la lectura de datos a partir del teclado.
-
Ejercicio 0201r02.-
Construir una calculadora Euros (€)<->Pesetas (Ptas) empleando una enumeración.
La solución puede ser la siguiente:
/*
Construir una calculadora que permita convertir entre euros y
pesetas, empleando una enumeración.
*/
#include<stdio.h>
#include<stdlib.h>
#define NUM_OPCIONES 3
int main(int argc, char * argv[])
{
enum {Paso_a_Euros, Paso_a_Pesetas, Salir};
char menu[][20] = {"Pasar a Euros", "Pasar a Ptas", "Salir"};
char opcion;
int i, caso;
float numpesetas, numeuros;
do
{
/* Visualizar menú y leer la opción */
printf("\nSeleccione una opción:\n\n");
for(i=0;i<NUM_OPCIONES;i++)
printf("%s (%d) ", menu[i], i);
printf(" : ");
scanf("%c", &opcion);
fpurge(stdin);
/* Mostrar en pantalla la opción seleccionada */
caso = opcion - '0';
switch(caso)
{
case Paso_a_Euros: printf("\nEscriba el número de pesetas: ");
scanf("%f", &numpesetas);
numeuros = numpesetas / 166.386;
printf("\n%10.3f Pesetas equivalen a %10.2f€\n", numpesetas, numeuros);
fpurge(stdin);
break;
case Paso_a_Pesetas: printf("\nEscriba el número de euros: ");
scanf("%f", &numeuros);
numpesetas = numeuros * 166.386;
printf("\n%10.2f€ equivale a %10.3f Pesetas\n", numeuros, numpesetas);
fpurge(stdin);
break;
case Salir: printf("\nSaliendo...\n");
break;
default: printf("\n\nOpción incorrecta\n\n");
break;
}
}
while(caso != Salir);
printf("\n\nFin del programa\n\n");
return 0;
}
/*
Resultado de la ejecución:
Seleccione una opción:
Pasar a Euros (0) Pasar a Ptas (1) Salir (2) : 0
Escriba el número de pesetas: 166.386
166.386 Pesetas equivalen a 1.00€
Seleccione una opción:
Pasar a Euros (0) Pasar a Ptas (1) Salir (2) : 1
Escriba el número de euros: 1.0
1.00€ equivalen a 166.386 Pesetas
Seleccione una opción:
Pasar a Euros (0) Pasar a Ptas (1) Salir (2) : 2
Saliendo...
Fin del programa
*/
Notas
El programa se ha construido por simple modificación del anterior, con la intención de mostrar los beneficios que aporta la reutilización de código en menor o mayor grado. Se utilizan especificaciones de formato para números reales con objeto de visualizar un número de decimales adecuado a cada situación.
-
Ejercicio 0201r03.-
Construir un programa que aplique distintas desgravaciones fiscales en función del estado civil del usuario. El programa recibirá como datos la base imponible y el estado del usuario, proporcionando como resultado la cantidad liquidable, esto es, la base imponible menos la desgravación.
El programa podría ser el siguiente:
/*
Construir un programa que aplique distintas desgravaciones fiscales
en función del estado civil del usuario. El programa
recibirá como datos la base imponible y el estado del
usuario, proporcionando como resultado la cantidad desgravada.
*/
#include<stdio.h>
#include<stdlib.h>
#define NUM_OPCIONES 6
int main(int argc, char * argv[])
{
enum {Soltero, Casado, Viudo, Separado, Divorciado, Salir};
char menu[][20] = {"Soltero", "Casado", "Viudo", "Separado", "Divorciado", "Salir"};
float desgravacion[] = {1000.0, 2000.0, 3000.0, 4000.0, 5000.0};
float base_imponible, cantidad_final;
char opcion;
int i, caso;
system("clear"); /* Para limpiar la pantalla antes empezar la ejecución */
fpurge(stdin);
do
{
printf("\nEspecifique su estado civil (5 para salir):\n\n");
for(i=0;i<NUM_OPCIONES;i++)
printf("[%d] %s", i, menu[i]);
printf(" : ");
scanf("%c", &opcion);
fpurge(stdin);
caso = opcion - '0';
switch(caso)
{
case Soltero:
case Casado:
case Viudo:
case Separado:
case Divorciado:
{
do
{
printf("\n\nEspecifique su base imponible (> 5000€): ");
scanf("%f", &base_imponible);
fpurge(stdin);
} while (base_imponible < 5000.0);
cantidad_final = base_imponible - desgravacion[caso];
printf("La cantidad final a pagar es de %10.2f€.\n\n", cantidad_final);
break;
}
case Salir: printf("\nSaliendo...\n\n");
break;
default: printf("\n\nOpción incorrecta\n\n");
break;
}
} while(caso != Salir);
printf("\n\nFin del programa\n\n");
return 0;
}
/*
Resultado de la ejecución:
Especifique su estado civil (5 para salir):
[0] Soltero[1] Casado[2] Viudo[3] Separado[4] Divorciado[5] Salir : 0
Especifique su base imponible (> 5000€): 5000
La cantidad final a pagar es de 4000.00€.
Especifique su estado civil (5 para salir):
[0] Soltero[1] Casado[2] Viudo[3] Separado[4] Divorciado[5] Salir : 1
Especifique su base imponible (> 5000€): 5000
La cantidad final a pagar es de 3000.00€.
Especifique su estado civil (5 para salir):
[0] Soltero[1] Casado[2] Viudo[3] Separado[4] Divorciado[5] Salir : 2
Especifique su base imponible (> 5000€): 5000
La cantidad final a pagar es de 2000.00€.
Especifique su estado civil (5 para salir):
[0] Soltero[1] Casado[2] Viudo[3] Separado[4] Divorciado[5] Salir : 3
Especifique su base imponible (> 5000€): 5000
La cantidad final a pagar es de 1000.00€.
Especifique su estado civil (5 para salir):
[0] Soltero[1] Casado[2] Viudo[3] Separado[4] Divorciado[5] Salir : 4
Especifique su base imponible (> 5000€): 5000
La cantidad final a pagar es de 0.00€.
Especifique su estado civil (5 para salir):
[0] Soltero[1] Casado[2] Viudo[3] Separado[4] Divorciado[5] Salir : 5
Saliendo...
Fin del programa
*/
Notas
En el
switch()
que gobierna el programa se han agrupado varias todas las opciones que requieren indicar la base imponible. De este modo, si el usuario decide
Salir
, no se le pregunta más; si por el contrario decide calcular la cantidad final a ingresar (base imponible menos desgravación) entonces se le pregunta su estado civil y base imponible. No se admiten bases imponibles que dieran lugar a una cantidad a devolver.
-
Ejercicio 0201r04.-
Construir un programa dotado de un menú de Archivo, otro de Edición y otro de Texto. El menú Archivo ofrecerá las opciones Nuevo, Abrir, Guardar, Cerrar y Salir. El menú Edición ofrecerá las opciones Deshacer, Cortar, Copiar y Pegar. El menú Texto ofrecerá las opciones Menor, Medio y Mayor. El programa debe mostrar una barra con los menús Archivo, Edición y Texto; cuando el usuario seleccione uno de ellos, aparecerán las opciones correspondientes a ese menú y el usuario podrá seleccionar una de ellas. Hecho esto, el programa mostrará el menú y la opción seleccionados, en la forma siguiente:
Se ha seleccionado la opción Cortar del menú Edición.
La solución puede ser como sigue:
/*
Construir un programa dotado de un menú de Archivo, otro de
Edición y otro de Texto. El menú Archivo
ofrecerá las opciones Nuevo, Abrir, Guardar, Cerrar y Salir.
El menú Edición ofrecerá las opciones Deshacer,
Cortar, Copiar y Pegar. El menú Texto ofrecerá las
opciones Menor, Medio y Mayor. El programa debe mostrar una barra
con los menús Archivo, Edición y Texto; cuando el
usuario seleccione uno de ellos, aparecerán las opciones
correspondientes a ese menú y el usuario podrá
seleccionar una de ellas. Hecho esto, el programa mostrará el
menú y la opción seleccionados, en la forma siguiente:
Se ha seleccionado la opción Cortar del menú
Edición.
*/
#include<stdio.h>
#include<stdlib.h>
#define NUM_OPCIONES_BARRA 3
#define NUM_OPCIONES_ARCHIVO 5
#define NUM_OPCIONES_EDICION 5
#define NUM_OPCIONES_TEXTO 3
/*
Enumeraciones varias. Disponemos de identificadores
para todos los menús y todas las opciones de cada
uno de ellos.
*/
enum {Archivo, Edicion, Texto};
enum {Nuevo, Abrir, Guardar, Cerrar, Salir};
enum {Deshacer, Cortar, Copiar, Pegar, Borrar};
enum {Menor, Medio, Mayor};
/*
Listas de cadenas asociadas a las distintas enumeraciones.
Es imprescindible que coincida el nombre de los identificadores
y el orden en que aparecen estos en las enumeraciones.
*/
char barraMenus[][10] = { "Archivo", "Edicion", "Texto"};
char menuArchivo[][10] = { "Nuevo", "Abrir", "Guardar", "Cerrar", "Salir"};
char menuEdicion[][10] = { "Deshacer", "Cortar", "Copiar", "Pegar", "Borrar"};
char menuTexto[][10] = { "Menor", "Medio", "Mayor"};
int menu_seleccionado(void);
int opcion_seleccionada(int numero_menu);
int main(int argc, char * argv[])
{
int num_menu, num_opcion;
system("clear");
do
{
/* Visualizar menú y leer la opción */
num_menu = menu_seleccionado();
num_opcion = opcion_seleccionada(num_menu);
switch(num_menu)
{
case Archivo: printf("\nSeleccionada la opción %s del menú %s\n",
menuArchivo[num_opcion],
barraMenus[num_menu]);
break;
case Edicion: printf("\nSeleccionada la opción %s del menú %s\n",
menuEdicion[num_opcion],
barraMenus[num_menu]);
break;
case Texto: printf("\nSeleccionada la opción %s del menú %s\n",
menuTexto[num_opcion],
barraMenus[num_menu]);
break;
}
}
while(!(num_menu == Archivo && num_opcion == Salir));
printf("\n\nFin del programa\n\n");
return 0;
}
int menu_seleccionado(void) {
int i;
int n;
do
{
for(i=0;i<NUM_OPCIONES_BARRA;i++)
printf("[%d] %s ", i, barraMenus[i]);
scanf("%d", &n);
fpurge(stdin);
} while ( n< Archivo || n > Texto);
return n;
}
int opcion_seleccionada(int numero_menu){
int i,n;
switch(numero_menu)
{
case Archivo:
do
{
for(i=0;i<NUM_OPCIONES_ARCHIVO;i++)
printf("[%d] %s ", i, menuArchivo[i]);
scanf("%d", &n);
} while (n < Nuevo || n > Salir);
break;
case Edicion:
do
{
for(i=0;i<NUM_OPCIONES_EDICION;i++)
printf("[%d] %s ", i, menuEdicion[i]);
scanf("%d", &n);
} while (n < Deshacer || n > Borrar);
break;
case Texto:
do
{
for(i=0;i<NUM_OPCIONES_TEXTO;i++)
printf("[%d] %s ", i, menuTexto[i]);
scanf("%d", &n);
} while (n < Menor || n > Mayor);
break;
}
return n;
}
/*
Resultado de la ejecución del programa:
[0] Archivo [1] Edicion [2] Texto 0
[0] Nuevo [1] Abrir [2] Guardar [3] Cerrar [4] Salir 0
Seleccionada la opción Nuevo del menú Archivo
[0] Archivo [1] Edicion [2] Texto 0
[0] Nuevo [1] Abrir [2] Guardar [3] Cerrar [4] Salir 1
Seleccionada la opción Abrir del menú Archivo
[0] Archivo [1] Edicion [2] Texto 0
[0] Nuevo [1] Abrir [2] Guardar [3] Cerrar [4] Salir 2
Seleccionada la opción Guardar del menú Archivo
[0] Archivo [1] Edicion [2] Texto 0
[0] Nuevo [1] Abrir [2] Guardar [3] Cerrar [4] Salir 3
Seleccionada la opción Cerrar del menú Archivo
[0] Archivo [1] Edicion [2] Texto 0
[0] Nuevo [1] Abrir [2] Guardar [3] Cerrar [4] Salir 4
Seleccionada la opción Salir del menú Archivo
*/
Notas
Este programa muestra el denominado comportamiento modal, esto es, la funcionalidad del programa se limita a la ofrecida en el modo (menú) que se activa. Un comportamiento más sofisticado consistiría en admitir cualquier combinación de menú y opción sin necesidad de recurrir a modos para acceder a opciones específicas. Obsérvese también la presencia de un par de funciones,
menu_seleccionado()
y
opcion_seleccionada()
, que hacen más comprensible el programa. Otra posible solución sería construir una tabla de cadenas, en que cada fila correspondería a las opciones de un cierto menú; las columnas serían opciones homólogas de distintos menús. Esta organización se podría mantener en disco, con objeto de leerla en el momento del arranque y mostrar una u otra colección de menús y opciones en función de las preferencias del usuario. Podría ser algo así:
char tm[][6] = {
{"Archivo", "Nuevo", "Abrir", "Cerrar", "Guardar", "Salir"},
{"Edicion", "Deshacer", "Cortar", "Copiar", "Pegar", "Borrar"},
{"Texto", "Menor", "Medio", "Mayor"},
};
¿Sabría el lector adaptar este ejercicio a la nueva estructura de datos?
-
Ejercicio 0201r05.-
Construir un programa que admita el nombre de un usuario y lo muestre en mayúsculas o minúsculas a voluntad del usuario, que utilizará las opciones de un menú.
El programa podría ser como sigue:
/*
Construir un programa que admita el nombre de un usuario y lo
muestre en mayúsculas o minúsculas a voluntad del
usuario, que utilizará las opciones de un menú.
*/
#include<stdio.h>
#include<stdlib.h>
#include <ctype.h> /* Para poder efectuar el paso a mayúsculas o minúsculas */
#define NUM_OPCIONES 4
void pedir(char nombre[]);
void mostrar_en_mayusculas(char nombre[]);
void mostrar_en_minusculas(char nombre[]);
int main(int argc, char * argv[])
{
enum {Escribir, EnMayusculas, EnMinusculas, Salir};
char menu[][20] = {"Escribir nombre", "Ver en mayúsculas", "Ver en minúsculas", "Salir"};
int nombre_leido;
char nombre[80];
char opcion;
int i, caso;
system("clear"); /* Suponiendo una ejecución en Unix. En otras plataformas es "cls" */
do
{
/* Visualizar menú y leer la opción */
printf("\nSeleccione una opción:\n\n");
for(i=0;i<NUM_OPCIONES;i++)
printf("%s (%d) ", menu[i], i);
printf(" : ");
scanf("%c", &opcion);
fpurge(stdin);
/* Mostrar en pantalla la opción seleccionada */
caso = opcion - '0';
switch(caso)
{
case Escribir: pedir(nombre);
nombre_leido = 1;
break;
case EnMayusculas: if (nombre_leido)
mostrar_en_mayusculas(nombre);
else
printf("\n\nPor favor, escriba primero el nombre.\n");
break;
case EnMinusculas: if (nombre_leido)
mostrar_en_minusculas(nombre);
else
printf("\n\nPor favor, escriba primero el nombre.\n");
break;
case Salir: printf("\nSaliendo...\n");
break;
default: printf("\n\nOpción incorrecta\n\n");
break;
}
}
while(caso != Salir);
printf("\n\nFin del programa\n\n");
return 0;
}
void pedir(char nombre[])
{
int n = 80;
int i;
printf("\nPor favor, escriba su nombre: ");
fgets(nombre, n ,stdin);
printf("\nGracias, %s\n", nombre);
}
void mostrar_en_mayusculas(char nombre[])
{
int n = strlen(nombre);
int i;
printf("\n\nSu nombre en mayúsculas es: ");
for(i=0;i<n;i++)
printf("%c", toupper(nombre[i]));
printf("\n\n");
}
void mostrar_en_minusculas(char nombre[])
{
int n = strlen(nombre);
int i;
printf("\n\nSu nombre en minúsculas es: ");
for(i=0;i<n;i++)
printf("%c", tolower(nombre[i]));
printf("\n\n");
}
/*
Resultado de la ejecución del programa:
Seleccione una opción:
Escribir nombre (0) Ver en mayúsculas (1) Ver en minúsculas (2) Salir (3) : 0
Por favor, escriba su nombre: coti
Gracias, coti
Seleccione una opción:
Escribir nombre (0) Ver en mayúsculas (1) Ver en minúsculas (2) Salir (3) : 1
Su nombre en mayúsculas es: COTI
Seleccione una opción:
Escribir nombre (0) Ver en mayúsculas (1) Ver en minúsculas (2) Salir (3) : 2
Su nombre en minúsculas es: coti
Seleccione una opción:
Escribir nombre (0) Ver en mayúsculas (1) Ver en minúsculas (2) Salir (3) : 3
Saliendo...
Fin del programa
*/
Notas
En este programa se sigue la pauta habitual, consistente en crear enumeraciones y listas de cadenas coordinadas. Obsérvese la presencia del centinela
nombre_leido
, que impide que el usuario intente visualizar en mayúsculas o minúsculas un nombre antes de introducirlo. Las funciones
toupper()
y
tolower()
, declaradas en
ctype.h
, permiten efectuar la transformación deseada. Obsérvese tambien el uso de
fgets()
para garantizar que el número de caracteres leídos no supera las dimensiones del fragmento de memoria reservado al efecto. Se podría haber utilizado
gets()
, pero se deplora su uso por plantear precisamente este problema: la imposibilidad de asegurar que no se leerán más caracteres que los reservados al efecto. Otra solución consiste en determinar por anticipado el número de caracteres disponibles para su lectura, empleando la función
fgetln()
, descrita
aquí
, y de cuyo uso se muestra un ejemplo
aquí
.
-
Ejercicio 0201r06.-
Construir un programa que pida el nombre de un
archivo
de texto y muestre su contenido en pantalla o lo almacene en otro archivo, a voluntad del usuario.
La solución puede ser la siguiente:
/*
Construir un programa que pida el nombre de un archivo de texto y
muestre su contenido en pantalla o lo almacene en otro archivo, a
voluntad del usuario.
*/
#include<stdio.h>
#include<stdlib.h>
#define NUM_OPCIONES 4
#define MAX_CHARS_NOMBRE 80
char archivo[MAX_CHARS_NOMBRE];
void nombrar(char n[]);
void mostrar_en_pantalla(char n[]);
void guardar_en_disco(char n[]);
int main(int argc, char * argv[])
{
enum {Nombrar, Pantalla, Disco, Salir};
char menu[NUM_OPCIONES][30] = {"Nombrar archivo", "Mostrar en pantalla", "Guardar en disco", "Salir"};
char opcion;
int i, caso;
do
{
/* Visualizar menú y leer la opción */
printf("\nSeleccione una opción:\n\n");
for(i=0;i<NUM_OPCIONES;i++)
printf("%s (%d) ", menu[i], i);
printf(" : ");
scanf("%c", &opcion);
fpurge(stdin);
/* Ejecutar la opción seleccionada */
caso = opcion - '0';
switch(caso)
{
case Nombrar: nombrar(archivo);
break;
case Pantalla: mostrar_en_pantalla(archivo);
break;
case Disco: guardar_en_disco(archivo);
break;
case Salir: printf("\nSaliendo...\n", menu[caso]);
break;
default: printf("\n\nOpción incorrecta\n\n");
break;
}
}
while(caso != Salir);
printf("\n\nFin del programa\n\n");
return 0;
}
void nombrar(char n[]){
printf("\nPor favor, escriba el nombre del archivo que desea tratar (INTRO para salir): ");
fgets(n,MAX_CHARS_NOMBRE, stdin);
if (n[0] == '\n')
{
printf("\nPrograma interrumpido por el usuario... Saliendo.\n");
exit(1);
}
n[strlen(n)-1] = '\0';
printf("\nEl nombre del archivo seleccionado es : >%s<\n\n", n);
};
void mostrar_en_pantalla(char n[]){
FILE * fp;
char letra = 1;
if (!(fp = fopen(n,"r")))
printf("\nEl archivo indicado no existe en este directorio.\n");
else
{
printf("\nEl archivo %s comienza en la línea siguiente a la flecha:\n\n------>\n", n);
letra = fgetc(fp);
while (letra != -1)
{
putc(letra, stdout);
letra = fgetc(fp);
}
fclose(fp);
printf("\n<--------\n\nEl archivo %s acaba en la línea anterior a la flecha.\n\n", n);
}
}
void guardar_en_disco(char n[]){
char copia[MAX_CHARS_NOMBRE];
FILE * entrada, *salida;
char letra = 1;
printf("\nPor favor, escriba el nombre del archivo COPIA (INTRO para salir): ");
fgets(copia,MAX_CHARS_NOMBRE, stdin);
if (copia[0] == '\n')
{
printf("\nPrograma interrumpido por el usuario... Saliendo.\n");
exit(1);
}
copia[strlen(copia)-1] = '\0';
salida = fopen(copia, "a");
if (!salida)
{
printf("\nNo fue posible crear el archivo %s. Saliendo.\n\n", copia);
exit(2);
}
printf("\nEl nombre del archivo copia es : >%s<\n\n", copia);
if (!(entrada = fopen(n,"r")))
printf("\nEl archivo indicado no existe en este directorio.\n");
else
{
letra = fgetc(entrada);
while (letra != -1)
{
putc(letra, salida);
letra = fgetc(entrada);
}
fclose(entrada);
fclose(salida);
printf("\n\nEl proceso de copia en %s ha teminado.\n\n", copia);
}
}
/*
El resultado de la ejecución es como sigue:
Seleccione una opción:
Nombrar archivo (0) Mostrar en pantalla (1) Guardar en disco (2) Salir (3) : 0
Por favor, escriba el nombre del archivo que desea tratar (INTRO para salir): prueba.txt
El nombre del archivo seleccionado es : >prueba.txt<
Seleccione una opción:
Nombrar archivo (0) Mostrar en pantalla (1) Guardar en disco (2) Salir (3) : 1
El archivo prueba.txt comienza en la línea siguiente a la flecha:
------>
Esto
es
una
prueba.
<--------
El archivo prueba.txt acaba en la línea anterior a la flecha.
Seleccione una opción:
Nombrar archivo (0) Mostrar en pantalla (1) Guardar en disco (2) Salir (3) : 2
Por favor, escriba el nombre del archivo COPIA (INTRO para salir): copia.txt
El nombre del archivo copia es : >copia.txt<
El proceso de copia en copia.txt ha teminado.
Seleccione una opción:
Nombrar archivo (0) Mostrar en pantalla (1) Guardar en disco (2) Salir (3) : 3
Saliendo...
Fin del programa
*/
Notas
Este programa tiene la estructura habitual, basada en una enumeración y una lista de cadenas para el menú. Consta de tres funciones además del programa principal:
-
La función
nombrar()
tiene al misión de pedir al usuario el nombre del archivo que luego se mostrará en pantalla o se escribirá en disco. Si el usuario pulsa
INTRO
directamente, se entiende que desea salir de programa sin hacer nada. Esto se detecta comparando el primer carácter de n con '\n', que es lo que proporciona
fgets()
cuando se pulsa
INTRO
sin anteponer carácter alguno. Si se escribe algo que pudiera ser un nombre de archivo, se empieza por eliminar el '\n' que habrá proporcionado
fgets()
al final del nombre.
-
En la función
mostrar_en_pantalla()
se intenta abrir el archivo en modo de lectura; si no existe, se comunica este hecho al usuario y se abandona el programa. Si existe, se lee el archivo letra por letra y se va escribiendo en
stdin
, el flujo de pantalla. Finalmente, se cierra el flujo de entrada.
-
La función
guardar_en_disco()
es necesariamente la más compleja. Comienza por solicitar un nombre para el archivo de copia. Si el nombre es válido (si el usuario no pulsa
INTRO
cuando se solicita el nombre) entonces se abre el archivo en modo de adición, como precaución, para no destruir nunca información. Si no fuera posible abrir el archivo, se notifica al usuario y se abandona el programa. A continuación, se intenta abrir el archivo original. Si no existe, se comunica al usuario y se abandona el programa. Si existe, se lee el flujo
entrada
letra por letra y se va escribiendo en el flujo
salida
. Finalmente, se cierran ambos flujos.
Desde luego, el programa permite copiar y archivo en otro y visualizar en pantalla el resultado de la copia.
-
Ejercicio 0201r07.-
Construir un programa que muestre un menú adecuado para leer un fichero de texto y escribirlo en otro fichero en mayúsculas o en minúsculas.
La solución pueden ser la siguiente:
/*
Construir un programa que muestre un menú adecuado para leer
un fichero de texto y escribirlo en otro fichero en
mayúsculas o en minúsculas.*/
#include<stdio.h>
#include<stdlib.h>
#define NUM_OPCIONES 4
#define MAX_CHARS_NOMBRE 80
char archivo[MAX_CHARS_NOMBRE];
enum {Nombrar, Minusculas, Mayusculas, Salir};
void nombrar(char n[]);
void traducir(char n[], int paso);
int main(int argc, char * argv[])
{
char menu[NUM_OPCIONES][30] = {"Nombrar archivo", "Paso a minúsculas",
"Paso a mayúsculas", "Salir"};
char opcion;
int i, caso;
do
{
/* Visualizar menú y leer la opción */
printf("\nSeleccione una opción:\n\n");
for(i=0;i<NUM_OPCIONES;i++)
printf("%s (%d) ", menu[i], i);
printf(" : ");
scanf("%c", &opcion);
fpurge(stdin);
/* Ejecutar la opción seleccionada */
caso = opcion - '0';
switch(caso)
{
case Nombrar: nombrar(archivo);
break;
case Minusculas: traducir(archivo, Minusculas);
break;
case Mayusculas: traducir(archivo, Mayusculas);
break;
case Salir: printf("\nSaliendo...\n", menu[caso]);
break;
default: printf("\n\nOpción incorrecta\n\n");
break;
}
}
while(caso != Salir);
printf("\n\nFin del programa\n\n");
return 0;
}
void nombrar(char n[]){
printf("\nPor favor, escriba el nombre del archivo que desea tratar (INTRO para salir): ");
fgets(n,MAX_CHARS_NOMBRE, stdin);
if (n[0] == '\n')
{
printf("\nPrograma interrumpido por el usuario... Saliendo.\n");
exit(1);
}
n[strlen(n)-1] = '\0';
printf("\nEl nombre del archivo seleccionado es : >%s<\n\n", n);
};
void traducir(char n[], int paso){
char traduccion[MAX_CHARS_NOMBRE];
FILE * entrada, *salida;
char letra = 1;
printf("\nPor favor, escriba el nombre del archivo TRADUCIDO (INTRO para salir): ");
fgets(traduccion,MAX_CHARS_NOMBRE, stdin);
if (traduccion[0] == '\n')
{
printf("\nPrograma interrumpido por el usuario... Saliendo.\n");
exit(1);
}
traduccion[strlen(traduccion)-1] = '\0';
salida = fopen(traduccion, "a");
if (!salida)
{
printf("\nNo fue posible crear el archivo %s. Saliendo.\n\n", traduccion);
exit(2);
}
printf("\nEl nombre del archivo traducido es : >%s<\n\n", traduccion);
if (!(entrada = fopen(n,"r")))
printf("\nEl archivo indicado no existe en este directorio.\n");
else
{
letra = fgetc(entrada);
while (letra != -1)
{
if (paso == Minusculas)
letra = tolower(letra);
else
letra = toupper(letra);
putc(letra, salida);
letra = fgetc(entrada);
}
fclose(entrada);
fclose(salida);
printf("\n\nEl proceso de traducción a %s en %s ha teminado.\n\n",
paso==Minusculas ? "minúsculas":"mayúsculas", traduccion);
}
}
/*
Resultado de la ejecución
Seleccione una opción:
Nombrar archivo (0) Paso a minúsculas (1) Paso a mayúsculas (2) Salir (3) : 0
Por favor, escriba el nombre del archivo que desea tratar (INTRO para salir): prueba.txt
El nombre del archivo seleccionado es : >prueba.txt<
Seleccione una opción:
Nombrar archivo (0) Paso a minúsculas (1) Paso a mayúsculas (2) Salir (3) : 1
Por favor, escriba el nombre del archivo TRADUCIDO (INTRO para salir): pruebamin.txt
El nombre del archivo traducido es : >pruebamin.txt<
El archivo indicado no existe en este directorio.
Seleccione una opción:
Nombrar archivo (0) Paso a minúsculas (1) Paso a mayúsculas (2) Salir (3) : 0
Por favor, escriba el nombre del archivo que desea tratar (INTRO para salir): prueba.txt
El nombre del archivo seleccionado es : >prueba.txt<
Seleccione una opción:
Nombrar archivo (0) Paso a minúsculas (1) Paso a mayúsculas (2) Salir (3) : 1
Por favor, escriba el nombre del archivo TRADUCIDO (INTRO para salir): pruebamin.txt
El nombre del archivo traducido es : >pruebamin.txt<
El proceso de traducción a minúsculas en pruebamin.txt ha teminado.
Seleccione una opción:
Nombrar archivo (0) Paso a minúsculas (1) Paso a mayúsculas (2) Salir (3) : 2
Por favor, escriba el nombre del archivo TRADUCIDO (INTRO para salir): pruebamax.txt
El nombre del archivo traducido es : >pruebamax.txt<
El proceso de traducción a mayúsculas en pruebamax.txt ha teminado.
Seleccione una opción:
Nombrar archivo (0) Paso a minúsculas (1) Paso a mayúsculas (2) Salir (3) : 3
Saliendo...
Fin del programa
[maxus~:] coti% cat pruebamin.txt
esto
es
una
prueba.
[maxus~:] coti% cat pruebamax.txt
ESTO
ES
UNA
PRUEBA.
*/
Notas
Este programa es análogo al anterior, y plantea una posibilidad interesante, a saber, "filtrar" el contenido del archivo de entrada para después volcar el resultado en un archivo de salida. En este caso el filtro era trivial, pero es frecuente hallar situaciones en que las transfomaciones sean más complejos. Tal sería el caso de un programa que facilitase la traducción de textos entre distintas plataformas.
-
Ejercicio 0201r08.-
Construir un programa que muestre la trama de bits correspondiente a un valor enumerado (véase
0203
).
La solución puede ser la siguiente:
#include<stdio.h>
/*
Este programa muestra la estructura de bits de un valor enumerado.
*/
struct muchos_bits {
unsigned bit1:1;
unsigned bit2:1;
unsigned bit3:1;
unsigned bit4:1;
unsigned bit5:1;
unsigned bit6:1;
unsigned bit7:1;
unsigned bit8:1;
unsigned bit9:1;
unsigned bit10:1;
unsigned bit11:1;
unsigned bit12:1;
unsigned bit13:1;
unsigned bit14:1;
unsigned bit15:1;
unsigned bit16:1;
unsigned bit17:1;
unsigned bit18:1;
unsigned bit19:1;
unsigned bit20:1;
unsigned bit21:1;
unsigned bit22:1;
unsigned bit23:1;
unsigned bit24:1;
unsigned bit25:1;
unsigned bit26:1;
unsigned bit27:1;
unsigned bit28:1;
unsigned bit29:1;
unsigned bit30:1;
unsigned bit31:1;
unsigned bit32:1;
};
enum VariosValores { Primero, Segundo = -1, Tercero, Cuarto};
union Ejemplo_union {
enum VariosValores valor_enumerado;
struct muchos_bits bits_union;
} union_prueba;
enum VariosValores valor_estudiado;
void mostrar_valores(union Ejemplo_union eu);
int main(int argc, char * argv[])
{
printf("Programa de prueba para uniones y enumeraciones.\n\n");
printf("\nLo que sigue es la estructura de bits de los valores\
enumerados Primero, Segundo, Tercero y Cuarto:\n\n");
union_prueba.valor_enumerado = Primero;
mostrar_valores(union_prueba);
union_prueba.valor_enumerado = Segundo;
mostrar_valores(union_prueba);
union_prueba.valor_enumerado = Tercero;
mostrar_valores(union_prueba);
union_prueba.valor_enumerado = Cuarto;
mostrar_valores(union_prueba);
printf("\n\nTerminación normal del programa.\n");
}
void mostrar_valores(union Ejemplo_union eu){
printf("%d",eu.bits_union.bit1);
printf("%d",eu.bits_union.bit2);
printf("%d",eu.bits_union.bit3);
printf("%d",eu.bits_union.bit4);
printf("%d",eu.bits_union.bit5);
printf("%d",eu.bits_union.bit6);
printf("%d",eu.bits_union.bit7);
printf("%d",eu.bits_union.bit8);
printf("%d",eu.bits_union.bit9);
printf("%d",eu.bits_union.bit10);
printf("%d",eu.bits_union.bit11);
printf("%d",eu.bits_union.bit12);
printf("%d",eu.bits_union.bit13);
printf("%d",eu.bits_union.bit14);
printf("%d",eu.bits_union.bit15);
printf("%d",eu.bits_union.bit16);
printf("%d",eu.bits_union.bit17);
printf("%d",eu.bits_union.bit18);
printf("%d",eu.bits_union.bit19);
printf("%d",eu.bits_union.bit20);
printf("%d",eu.bits_union.bit21);
printf("%d",eu.bits_union.bit22);
printf("%d",eu.bits_union.bit23);
printf("%d",eu.bits_union.bit24);
printf("%d",eu.bits_union.bit25);
printf("%d",eu.bits_union.bit26);
printf("%d",eu.bits_union.bit27);
printf("%d",eu.bits_union.bit28);
printf("%d",eu.bits_union.bit29);
printf("%d",eu.bits_union.bit30);
printf("%d",eu.bits_union.bit31);
printf("%d\n",eu.bits_union.bit32);
}
/*
Resultados de la ejecución del programa:
Programa de prueba para uniones y enumeraciones.
Lo que sigue es la estructura de bits de los valores enumerados Primero, Segundo, Tercero y Cuarto:
00000000000000000000000000000000
11111111111111111111111111111111
00000000000000000000000000000000
00000000000000000000000000000001
*/
Notas
Como puede observarse, los valores de una enumeración se representan internamente mediante números enteros. Hemos asignado a
Segundo
el valor -1, lo cual da lugar a la oportuna codificación como número entero; el valor siguiente es el resultado de incrementarlo en 1 unidad, y por tanto es cero. El programa supone una mejora respecto al empleado en
0203
porque plantea el uso de una función, con una notable reducción del código necesario.