INTRODUCCIÓN A LA PROGRAMACIÓN 1 PRÁCTICA 7: ESTRUCTURAS TRANSFORMACIÓN DE LEA A C LEA C DEFINICIÓN DE UN REGISTRO (ESTRUCTURA) typedef struct { T1 c1; T2 c2; ... Tn cn; } Tr; Tipos Tr: registro cl: T1 c2: T2 ... cn: Tn fregistro typedef Tr * PTr; variables r: Tr Tr r; PTr pr; Tr r={v1, v2, ..., vn}; Typedef struct { Cadena nombre, apellido1, apellido2; int edad; long dni; char sexo; } Tpersona; tipos Tpersona: registro nombre, apellido1, apellido2: cadena edad, dni: entero sexo: caracter fregistro variables empleado: Tpersona Tpersona empleado; Tpersona empleado={"Alicia", "Gómez", "Cruz", 21, 12345678, 'm'}; ACCESO A LOS CAMPOS DE UN REGISTRO r.ci r.ci (acceso a través de una variable estructura) pr->ci (acceso a través de un puntero a estructura) empleado.nombre := "Alicia" escribir empleado.edad strcpy (empleado.nombre, "Alicia"); printf ("%d", empleado.edad); TABLAS DE REGISTROS tipos Ttabla: tabla [dim] de Tr variables nombre: Ttabla typedef Tr Ttabla[dim]; constantes N: 200 tipos Ttpersona: tabla [N] de Tpersona variables clase: Ttpersona #define N 200 Acceso a un elemento de la tabla: elemento i-ésimo: clase[i] nombre del elemento i-ésimo: clase[i].nombre Acceso a un elemento de la tabla: Elemento i-ésimo: clase[i-1] nombre del elemento i-ésimo: clase[i-1].nombre Ttabla nombre; typedef Tpersona Ttpersona[N]; Ttpersona clase; Práctica 7: Estructuras 2 LEA C PASO DE REGISTROS COMO PARÁMETROS a) El registro es un parámetro de entrada: a) El registro es un parámetro de entrada: Llamada: empleado: Tpersona escribe_datos_empleado (empleado) Prototipo: void escribe_datos_empleado (Tpersona); Definición: proc escribe_datos_empleado (ent e: Tpersona) prin escribir e.nombre, e.apellido1, e.apellido2 escribir e.edad, e.dni, e.sexo fin Llamada: Tpersona empleado; escribe_datos_empleado (empleado); Definición: void escribe_datos_empleado (Tpersona e) { printf ("%s %s, %s\n", e.nombre, e.apellido1, e.apellido2); printf ("%ld %ld %c", e.edad, e.dni, e.sexo); } b) El registro es un parámetro de salida: b) El registro es un parámetro de salida: Llamada: empleado: Tpersona lee_datos_empleado (empleado) Prototipo: typedef Tpersona * PTpersona; void lee_datos_empleado (PTpersona); Definición: proc lee_datos_empleado (sal e: Tpersona) prin leer e.nombre, e.apellido1, e.apellido2 leer e.edad, e.dni, e.sexo fin Llamada: Tpersona empleado; lee_datos_empleado (&empleado); Definición: void lee_datos_empleado (PTpersona e) { gets (e->nombre); gets (e->apellido1); gets (e->apellido2); scanf ("%ld%ld%c", &e->edad, &e->dni, &e->sexo); } Práctica 7: Estructuras EXPERIMENTOS E.7.1 En el siguiente programa se definen dos estructuras, una para almacenar una fecha y otra para almacenar el nombre y la fecha de nacimiento de una persona, de forma que para la fecha de nacimiento se hace uso de la estructura anterior. La definición de estas estructuras es la siguiente: typedef struct { int dia; int mes; int anio; } Fecha; typedef struct { Cadena nombre; Fecha nacimiento; } Persona; Además, hemos definido un procedimiento (no devuelve nada) que dada una persona nos imprime sus datos por pantalla con el siguiente prototipo: void escribe(Persona); Complete el siguiente programa para que funcione de manera correcta: #include <stdio.h> #include "f:\asigna\ip1\public\lea.h" typedef struct { int dia; int mes; int anio; } Fecha; typedef struct { Cadena nombre; Fecha nacimiento; } Persona; void escribe(Persona); void main (void) { Persona empleado; printf("\nDame el nombre: "); scanf("%s",_____); printf("\nDame la fecha de nacimiento: "); scanf("%d%d%d",_____,_____,_____); escribe(empleado); } void escribe(Persona per) { printf("\nEl nombre es: %s ",_____); printf("\nNació el: %d/%d/%d",_____,_____,_____); } 3 Práctica 7: Estructuras 4 E.7.2 En el siguiente programa se define un nuevo tipo Cadena que denominamos Cadena2 basado en una estructura y se implementa un procedimiento para concatenar dos cadenas. Este procedimiento tiene el prototipo: void concatena (PCadena2 cad1, Cadena2 cad2); y concatena la cadena cad2 a la cadena cad1, devolviendo como parámetro de E/S la propia cadena cad1. Complete el código para que el programa realice su tarea. #include <stdio.h> #include "f:\asigna\ip1\public\lea.h" typedef struct { Cadena texto; int longitud; } Cadena2; typedef Cadena2* PCadena2; void concatena (PCadena2, Cadena2); void main (void) { Cadena2 c1={"hola",4}, c2={"adios",5}; concatena (&c1, c2); printf ("\nCadena 1. c1.longitud); printf ("\nCadena 2. c2.longitud); Texto= %10s, Longitud= %3d", c1.texto, Texto= %10s, Longitud= %3d", c2.texto, } void concatena (PCadena2 p, Cadena2 c) { p->longitud = __________ + __________; strcat (__________, __________); } El resultado en pantalla debe ser el siguiente: Cadena 1. Texto= Cadena 2. Texto= holaadios, Longitud= adios, Longitud= 9 5 E.7.3 El siguiente programa crea una tabla de registros con una serie de números y sus respectivos factoriales. Complete el código para que el programa funcione correctamente. Utilice la función factorial que desarrolló en una práctica anterior (disponible también en la biblioteca f:\asigna\ip1\public\mates.lib). #include <stdio.h> #include <assert.h> #include "f:\asigna\ip1\public\mates.h" #define MAX 20 typedef struct { int num; long fac; } RFac; typedef RFac TRFac[MAX]; int rellenatabla (TRFac); void muestratabla (const TRFac, int); void main (void) { TRFac tablafac; Práctica 7: Estructuras int n; n = rellenatabla (tablafac); muestratabla (tablafac, n); } int rellenatabla (TRFac t) { int i, tam; printf ("\n¿Cuántos factoriales desea calcular? "); scanf ("%d", &tam); assert (tam <= MAX); for (i=0; i<tam; i++) { __________=i+1; __________=factorial(i+1); } return tam; } void muestratabla (const TRFac t, int m) { int i; assert (m for (i=0; { printf printf } } <= MAX); i<m; i++) ("\nNúmero: %3d ", __________); (". Factorial: %ld", __________); 5 Práctica 7: Estructuras EJERCICIOS DE SINTAXIS PROPUESTOS S.7.1 · · · · S.7.2 · · · Declare las siguientes variables estructura: Una variable hora_inicio de tipo Hora. Una variable america de tipo Fecha con valor inicial igual a la fecha del descubrimiento de América. Una tabla empleados capaz de almacenar 200 elementos de tipo Persona. Una tabla directorio capaz de almacenar 256 elementos de tipo EntradaDir. Una variable p_persona de tipo puntero a Persona. · · · · · A partir de las declaraciones del ejercicio anterior, escriba las expresiones para El año en que se descubrió América. El nombre del empleado i-ésimo de la tabla empleados. El día de nacimiento del empleado i-ésimo de la tabla empleados. El nombre de la persona a la que apunta p_persona. El día de nacimiento de la persona a la que apunta p_persona. · · S.7.3 S.7.4 Defina los siguientes tipos de estructuras: Un tipo estructura Hora con tres campos enteros hora, minutos, segundos. Un tipo estructura Fecha con tres campos enteros dia, mes, anyo. Un tipo estructura Persona con los siguientes campos: · nombre: cadena de 20 caracteres. · apellidos: cadena de 40 caracteres. · dni: entero largo. · fecha_nacimiento: estructura de tipo Fecha. Un tipo estructura EntradaDir con los siguientes campos: · nombre: cadena de 8 caracteres. · extension: cadena de 3 caracteres. · tamanyo: entero largo. · fecha_creacion: estructura de tipo Fecha. · hora_creacion: estructura de tipo Hora. Un número complejo se puede representar mediante la siguiente estructura: typedef struct { double a, b; } Complejo; Escriba las siguientes funciones de manipulación de números complejos: void escribe_complejo (Complejo c); Escribe un dato de tipo complejo. Complejo lee_complejo (void); Lee un dato de tipo complejo. Complejo suma_complejos (Complejo c1, Complejo c2); Suma dos datos de tipo complejo. Complejo multiplica_complejos (Complejo c1, Complejo c2); Multiplica dos datos de tipo complejo. S.7.5 Utilizando las funciones del ejercicio anterior, escriba un programa que lea dos datos de tipo Complejo y calcule e imprima la suma y el producto de ambos. S.7.6 Reescriba las funciones del ejercicio S.7.4 para que tengan los siguientes prototipos: void lee_complejo (PComplejo c); void suma_complejos (Complejo c1, Complejo c2, PComplejo c); void multiplica_complejos (Complejo c1, Complejo c2, PComplejo c); siendo PComplejo el tipo definido de la siguiente forma: 6 Práctica 7: Estructuras typedef Complejo * PComplejo; S.7.7 Sea la siguiente definición de estructura: typedef struct { int dia, mes, anyo; int dia_del_anyo; } Fecha; La función void dias_transcurridos (PFecha pf); recibe como parámetro un puntero a una estructura de tipo Fecha que contiene un día, mes y año, y calcula el valor del campo dia_del_anyo, que es igual al número de días transcurridos desde el comienzo del año. Complete la función para que realice su cometido. void dias_transcurridos (PFecha pf) { int i, bisiesto, dias; int tabla_dias[2][13] = {{0,31,28,31,30,31,30,31,31,30,31,30,31}, {0,31,29,31,30,31,30,31,31,30,31,30,31}}; dias = ??????????; bisiesto = pf->anyo%4==0 && pf->anyo%100!=0 || pf->anyo%400==0; for (i=1; i<??????????; i++) dias = dias + tabla_dias[bisiesto][i]; ?????????? = dias; } S.7.8 La siguiente función lee una fecha del teclado y la devuelve como resultado. Complete el código de la función. Fecha lee_fecha (void) { Fecha f; printf ("\nIntroduzca el día (1-31): "); scanf ("%d", ??????????); while (??????????<1 || ??????????>31) scanf ("%d", ??????????); printf ("\nIntroduzca el mes (1-12): "); scanf ("%d", ??????????); while (??????????<1 || ??????????>12) scanf ("%d", ??????????); printf ("\nIntroduzca el año: "); scanf ("%d", ??????????); dias_transcurridos (??????????); /* Calcular el día del año */ return f; } S.7.9 La siguiente función lee una fecha del teclado y la devuelve a través de una variable de salida. Complete el código de la función. void lee_fecha (PFecha pf) { printf ("\nIntroduzca el día (1-31): "); scanf ("%d", ??????????); while (??????????<1 || ??????????>31) scanf ("%d", ??????????); 7 Práctica 7: Estructuras 8 printf ("\nIntroduzca el mes (1-12): "); scanf ("%d", ??????????); while (??????????<1 || ??????????>12) scanf ("%d", ??????????); printf ("\nIntroduzca el año: "); scanf ("%d", ??????????); dias_transcurridos (??????????); /* Calcular el día del año */ } S.7.10 Utilizando la siguiente estructura definida para representar números complejos typedef struct { double a, b; /* forma binómica */ double mod, alfa; /* forma polar */ } Complejo; typedef Complejo * PComplejo; escriba una función que, dado un número complejo en forma binómica, calcule las correspondientes coordenadas en forma polar. El prototipo es: void binomica_a_polar (PComplejo c); y la fórmula de conversión es la siguiente: mod = a 2 + b2 b alfa = arctg a S.7.11 Sea el siguiente algoritmo (con sus definiciones de tipos correspondientes): typedef struct { Cadena nombre; int golf, golc, puntos; } Nodo; void imprime_clasificacion (const Nodo equipos[], const int orden[], int neq) { int i, puntos_ant=-1, dif, puntos; char c; printf ("\nCLASIFICACIÓN GENERAL"); printf ("\n=============================="); printf ("\nNOMBRE PUNTOS DIF"); printf ("\n=============================="); for(i=0; i<neq; i++) { puntos = equipos[orden[i]].puntos; dif = equipos[orden[i]].golf - equipos[orden[i]].golc; if (puntos != puntos_ant) { printf ("\n%-20s%5d", equipos[orden[i]].nombre, puntos); puntos_ant = puntos; } else printf ("\n%-20s%5c", equipos[orden[i]].nombre, '-'); if (dif>0) c = '+'; Práctica 7: Estructuras else if (dif<0) c = '-'; else c=´’ ’; printf ("%3c%2d", c, abs(dif)); } printf ("\n=============================="); } y sean las siguientes tablas de datos: Nodo equipos[MAX]={{"SEVILLA F.C.",59,33,42},{"REAL BETIS",52,25,45}, {"DPVO CORUÑA",60,34,49},{"REAL MADRID",90,28,55}, {"REAL ZARAGOZA",52,52,42},{"F.C. BARCELONA",86,42,45}, {"R.C.D. ESPAÑOL", 58, 45, 42}}; int orden[MAX] = {3, 2, 1, 5, 0, 4, 6}; Siga la traza del algoritmo cuando se realiza la llamada imprime_clasificacion (equipos, orden, 7); indicando el resultado impreso por la función. NOTAS: a) La función abs devuelve el valor absoluto de un entero. b) En el resultado impreso debe quedar claro el número de espacios en blanco existentes entre cada uno de los datos que se imprimen. S.7.12 El siguiente programa lee desde la entrada estándar el nombre y los puntos de los 22 equipos de una liga de fútbol. Los nombres tienen un máximo de 22 caracteres. Corrija, justificadamente, los errores del programa. #include <stdio.h> #define MAX 22; typedef char Nombre[MAX]; typedef strutc { char Nombre; int puntos; } Equipo; void main (void) { Equipo liga[]; for (i=0; i<=MAX; i++) scanf ("%s%d", liga[i].NOMBRE, liga[i].puntos); } EJERCICIOS DE ALGORÍTMICA PROPUESTOS A.7.1 Sean las siguientes definiciones: #define MAXCAR 31 #define MAX 10 typedef char Cadena[MAXCAR]; typedef struct { Cadena nombre, apellido1, apellido2; int edad; long dni; char sexo; } Persona; typedef Persona TPersona[MAX]; 9 Práctica 7: Estructuras Escriba una función int busca_persona (const TPersona clase, int npersonas, long dni); que busque de manera secuencial en la tabla clase aquella persona cuyo DNI coincida con el valor especificado en el parámetro dni. La función devolverá la posición de la persona, si la encuentra, o un valor -1 en caso contrario. A.7.2 Modifique la función anterior para que utilice el esquema de búsqueda binaria. A.7.3 Basándose en la misma definición de Persona del ejercicio anterior, escriba una función void ordena_personas (TPersona clase, int npersonas); que ordene la tabla clase en orden ascendente del campo edad. A.7.4 Una tabla de búsqueda (lookup table) es una tabla de estructuras en la que se realiza una búsqueda por uno de sus campos y se obtiene el valor almacenado en otro campo. Por ejemplo, para almacenar los valores de las variables de un programa se puede utilizar una tabla como la siguiente: #define MAX_SIMBOLOS 100 typedef struct { Cadena identificador; int valor; } Simbolo; Simbolo tabla_simbolos[MAX_SIMBOLOS]; Escriba una función de búsqueda, que, dado un identificador, obtenga el valor que le corresponde en la tabla. Su prototipo será el siguiente: int buscaValor (const Simbolo tabsim[], int nsim, Cadena ident); siendo nsim el número de identificadores almacenados en la tabla tabsim. A.7.5 Sean las siguientes definiciones y declaraciones: typedef char Cadena[MAXCAR]; typedef struct { int cod_idioma; Cadena mensajes[NMENSAJES]; } Mens; Mens tabla_idiomas[NIDIOMAS]; Escriba una función void muestra_mensaje (const Mens tabla_idiomas[], int codigo_idioma, int numero_mensaje); que reciba como parámetro un código de idioma y un número de mensaje (entre 1 y NMENSAJES) e imprima el mensaje correspondiente de tabla_idiomas. A.7.6 Sean las siguientes definiciones y declaraciones: typedef struct { int opcion; /* número de la opción */ Cadena mensaje; /* mensaje de la opción */ int visible; /*visibilidad de la opción: 1=visible, 2=no visible*/ } Opcion; Opcion tabla_menu[MAX]; 10 Práctica 7: Estructuras 11 Escriba una función void menu (const Opcion tabla_menu[], int n); que reciba como parámetros una tabla que representa un menú de opciones y un entero que indica el número de elementos de dicha tabla, e imprima el menú correspondiente, teniendo en cuenta que sólo se mostrarán en la pantalla aquellas opciones del menú que tengan activado el indicador de visibilidad. A.7.7 Se dispone de una tabla bidimensional de estructuras que contiene datos relativos al padrón de habitantes de una ciudad. Las filas representan los distritos de la ciudad (en concreto 10) y las columnas los años en que se han realizado padrones (1981, 1986, 1991 y 1996). 1981 1986 1991 1996 distrito 1 distrito 2 ... distrito 10 Cada elemento de la tabla es una estructura que contiene el número de hombres y de mujeres de cada distrito en el padrón de cada año. Un tercer campo indica la tendencia de crecimiento del distrito, pudiendo tener tres valores posibles: '+' si la población total del distrito ha crecido con respecto al padrón anterior, '-' si ha decrecido e '=' si se mantiene estable. hombres mujeres crecimiento La tabla está rellena a excepción de la tendencia de crecimiento, que sólo se conoce para el año 1981. Se pide escribir un programa que: a) Calcule las tendencias de crecimiento de cada distrito para el resto de los años. b) Muestre tres listados con los distritos que durante los cuatro años han mantenido una tendencia de crecimiento positiva, negativa y estable, respectivamente. A.7.8 Se dispone de una estructura de datos que representa las cartas de la baraja española: #define TAM 40 #define MAXCAR 8 typedef char Cadena[MAXCAR]; typedef struct { Cadena palo; int valor; } Carta; typedef Carta Baraja[TAM]; Cada carta tiene un palo y un valor. Existen cuatro palos: oros, copas, espadas y bastos. Por su parte, los valores posibles son 1, 2, 3, 4, 5, 6, 7, 10, 11 y 12. Realice una función que reciba un número variable de cartas de la baraja, desordenadas, y las devuelva ordenadas según los siguientes criterios: 1. Los palos seguirán el orden oros, copas, espadas, bastos. 2. Dentro de cada palo se seguirá el orden ascendente del valor. El prototipo de la función es: Práctica 7: Estructuras 12 void ordena_baraja (Baraja b, int ncartas); Ejemplo: si b contiene las cartas {"bastos",10}, {"oros",5}, {"copas",7}, {"oros",3}, {"copas",1} al aplicar la función quedará ordenada de la siguiente forma: {"oros",3}, {"oros",5}, {"copas",1}, {"copas",7}, {"bastos",10} A.7.9 Escriba una función void tenis (Cadena est_anterior, Cadena est_nuevo, int ult_punto); capaz de calcular el estado de un juego en un partido de tenis, tomando como datos de entrada el estado anterior del juego y el resultado del último punto disputado. Tanto el estado anterior como el nuevo estado son cadenas de caracteres, y sus posibles valores se muestran en la tabla. El resultado del último punto es un número cuyo valor puede ser 1 ó 2, según el último punto disputado haya sido ganado por el jugador que sirve (jugador 1) o el que resta (jugador 2), respectivamente. La evolución de los puntos en un juego de un partido de tenis es la siguiente: ESTADO ANTERIOR DEL JUEGO NUEVO ESTADO GANA JUGADOR 1 GANA JUGADOR 2 0-0 15-0 0-15 15-0 30-0 15-15 0-15 15-15 0-30 15-15 30-15 15-30 30-0 40-0 30-15 0-30 15-30 0-40 30-15 40-15 30-30 15-30 30-30 15-40 30-30 40-30 30-40 40-0 JUEGO-1 40-15 0-40 15-40 JUEGO-2 40-15 JUEGO-1 40-30 15-40 30-40 JUEGO-2 40-30 JUEGO-1 IGUALES 30-40 IGUALES JUEGO-2 IGUALES VENTAJA-1 VENTAJA-2 VENTAJA-1 JUEGO-1 IGUALES VENTAJA-2 IGUALES JUEGO-2 A.7.10 Si sabemos a priori el número máximo de elementos que tiene una secuencia, podemos implementarla mediante una tabla de registros. Cada registro de la tabla estará compuesto por dos Práctica 7: Estructuras 13 campos, que contienen el valor del elemento de la secuencia y la posición en la tabla del siguiente elemento de la secuencia. Por ejemplo, la secuencia de enteros positivos (máximo 4 elementos) 6, 12, 98 se podría almacenar en una tabla de la siguiente forma: elemento valor siguiente 0 6 3 1 98 -1 2 -1 -1 3 12 1 El último elemento tiene como siguiente el valor -1, y el primer elemento de la secuencia siempre ocupa la posición 0 de la tabla. Los elementos no ocupados de la tabla tienen un valor -1 en sus dos campos. Escriba una función en C que permita insertar en orden un entero positivo en una secuencia de enteros positivos. Utilice las definiciones y el prototipo que se dan a continuación: #define MAX 100 typedef struct { int valor; int siguiente; } Elemento; typedef Elemento Secuencia[MAX]; void insertaElemento (Secuencia s, int elem); Escriba un programa que lea una secuencia de números enteros positivos del teclado y los vaya insertando ordenadamente utilizando la función anterior. Posteriormente, el programa mostrará la lista de números ordenados en la pantalla.