Fundamentos de Informática 1 2 Introducción Nos permiten agrupar valores de tipos diferentes en una misma variable (tipo compuesto). { { { Declaración de tipos de estructuras Para declarar un nuevo tipo de estructura se utiliza la siguiente sintaxis: struct nombre_estructura { declaración del campo_1; declaración del campo_2; ... Una estructura se divide en campos. Cada campo puede ser de cualquier tipo. Cada campo de la estructura se identifica por un nombre. declaración del campo_N; Nos permiten crear nuevos tipos de datos en C (tipos definidos por el usuario). { { { }; Podemos definir diferentes tipos de estructuras en nuestro programa. Al definir una estructura, se especifica: Los campos se declaran igual que las variables El número de campos. El nombre de los campos. El tipo de los campos. Con la declaración anterior se define un nuevo tipo de datos llamado: Cada tipo de estructura definido pasa a ser un nuevo tipo de datos que podemos utilizar para declarar variables. struct nombre_estructura Se pueden declarar variables del nuevo tipo definido. 3 4 Declaración de tipos de estructuras: ejemplo struct complejo { double real; double imag; }; real Definimos un nuevo tipo de datos llamado struct complejo formado por dos campos de tipo double llamados real e imag . imag apellidos[80] Podemos declarar variables del nuevo tipo de estructura en la propia declaración de la estructura: struct nombre_estructura { ... } variable ; Definimos un nuevo tipo de datos llamado struct empleado formado por los siguientes campos: struct empleado { char nombre[40]; char apellidos[80]; int edad; . }; nombre[40] Declaración de variables También podemos declarar las variables en una declaración independiente: nombre (cadena de 40 caracteres) apellidos (cadena de 80 caracteres) struct nombre_estructura variable ; edad (de tipo entero) edad La estructura struct nombre_estructura debe haber sido declarada previamente en el código. ATENCIÓN: en los ejemplos anteriores no se han declarado variables, sólo se han creado dos nuevos tipos de datos llamados struct complejo y struct empleado. Dpto. de ATC, Universidad de Sevilla - Página 1 de 9 Fundamentos de Informática 5 Declaración de variables: ejemplo Declaración de variables con inicialización secretario struct complejo { double real; double imag; }; nombre[40] 6 struct nombre_estructura variable = {valor, valor, ... }; apellidos[80] edad Por cada campo de la estructura debe aparecer un valor. Los valores se asignan en el mismo orden en que se han declarado los campos dentro de la estructura. director struct empleado { char nombre[40]; char apellidos[80]; int edad; } director; nombre[40] apellidos[80] edad Ejemplo: Las variables director y secretario son de tipo struct empleado. struct polinomio { unsigned grado; double coeficientes[10]; }; struct complejo { double real; double imag; }; Las variables x e y son de tipo struct complejo. struct empleado secretario; struct complejo x, y; struct polinomio parabola; Valor del campo real Valor del campo imag x struct complejo x = {3.56, -1}; real 3.56 imag -1 La variable parabola es de tipo struct polinomio. 7 Acceso a los campos Declaración de variables con inicialización: ejemplo struct empleado { char nombre[40]; char apellidos[80]; int edad; }; 8 nombre_variable.nombre_campo El nombre de la variable y del campo se separan por el carácter ‘.’ El campo coeficientes es un vector, por lo tanto sus valores deben aparecer entre llaves. struct polinomio { unsigned grado; double coeficientes[10]; }; Ejemplo: struct complejo { double real; double imag; }; struct polinomio pol = {2, {-1, 5, 2} }; struct empleado director = {“Ana”, “Raya”, 18 }; . real x imag real y imag real imag x real 3.56 imag -1 director pol 0 grado 2 coeficientes -1 0 5 2 ... 1 2 ... 9 1 2 3 ... nombre A n a \0 ... apellidos R a y a \0 edad 18 39 ... ... 79 struct complejo x = {3.56, -1}; struct complejo y; y.real = x.real + 1; y.imag = 0; Dpto. de ATC, Universidad de Sevilla - Página 2 de 9 y real 4.56 imag 0 Fundamentos de Informática 9 10 Acceso a los campos: ejemplo 1a struct complejo { double real; double imag; }; Acceso a los campos: ejemplo 1b struct complejo { double real; double imag; }; p grado 2 coeficientes 4 1 0 1 struct polinomio { unsigned grado; double coeficientes[10]; }; 2.1 ... 2 ... y real 4 1 0 1 2.1 ... 2 ... x real 9 7.2 imag y real x.real = 3.1 * p.grado + p.coeficientes[1]; imag y.imag = x.real + 2.34; 2 main() { struct polinomio p = {2, {4,1,2.1} }; struct complejo x, y; imag x.real = 3.1 * p.grado + p.coeficientes[1]; grado coeficientes struct polinomio { unsigned grado; double coeficientes[10]; }; 9 x real main() { struct polinomio p = {2, {4,1,2.1} }; struct complejo x, y; p imag y.imag = x.real + 2.34; scanf( “%lf”, &x.imag ); scanf( “%lf”, &x.imag ); if (p.coeficientes[0] > y.real – 2) { ... if (p.coeficientes[0] > y.real – 2) { ... 11 12 Acceso a los campos: ejemplo 1c struct complejo { double real; double imag; }; Operador de asignación p grado 2 coeficientes 4 1 0 1 struct polinomio { unsigned grado; double coeficientes[10]; }; main() { struct polinomio p = {2, {4,1,2.1} }; struct complejo x, y; x.real = 3.1 * p.grado + p.coeficientes[1]; 2.1 ... 2 x real ... 7.2 imag y real imag 9.54 9 Al igual que ocurre con los tipos básicos (int, float, double, ...), se pueden realizar asignaciones entre variables del mismo tipo de estructura. Ejemplo: fx struct polinomio { unsigned grado; double coeficientes[3]; }; main() { struct polinomio fx = {2, {4,0,-1}}; struct polinomio pol; pol = fx; } grado 2 coeficientes 4 0 -1 0 1 2 0 1 2 pol grado coeficientes y.imag = x.real + 2.34; scanf( “%lf”, &x.imag ); if (p.coeficientes[0] > y.real – 2) { ... pol fx grado grado 2 coeficientes 4 0 -1 0 1 2 Dpto. de ATC, Universidad de Sevilla - Página 3 de 9 Se copian los valores coeficientes 2 4 0 -1 0 1 2 Fundamentos de Informática 13 14 Estructuras y funciones (1) Estructuras y funciones (2) Las funciones pueden devolver valores de tipo estructura. Ejemplo: struct punto { float x, y; }; struct punto crea_punto( float, float ); void main() { struct punto s; 3 struct punto { float x, y; }; float modulo( struct punto ); El valor devuelto se copia en s s s = crea_punto( -3, 2 ); x -3 y 2 void main() { struct punto s = {0,-2}; printf( “%f\n”, modulo( s ) ); } 1 } Los parámetros de tipo estructura se pasan por valor: en la llamada a la función, el valor de la estructura se copia en el parámetro. Ejemplo: Se ejecuta la función struct punto crea_punto( float cx, float cy ) { struct punto aux; aux.x = cx; aux.y = cy; return aux; } 2 -3 y 2 p se inicializa con el valor de s float modulo( struct punto p ) { return sqrt( p.x * p.x + p.y * p.y ); } La función devuelve el valor de aux: x s p x 0 y -2 x 0 y -2 Ejecución del 2 programa: 15 Estructuras y funciones: ejemplo 1a 16 Estructuras y funciones: ejemplo 1b En este ejemplo se muestran un conjunto de funciones y estructuras de datos para manipular números complejos. Devuelve la suma de los complejos a y b. #include <stdio.h> struct cmplj { double real; double imag; }; struct cmplj crea_c( double r, double i ) { struct cmplj aux; aux.real = r; aux.imag = i; return aux; } void impr_c( struct cmplj c ) { printf( “(%lf + %lfi)”, c.real, c.imag ); } Las variables de tipo struct cmplj contienen números complejos. Crea y devuelve un complejo con la parte real igual a r y la parte imaginaria igual a i. Muestra por pantalla el complejo c. struct cmplj sum_c ( struct cmplj a, struct cmplj b ) { struct cmplj aux; aux.real = a.real + b.real; aux.imag = a.imag + b.imag; return aux; } Devuelve el producto de los complejos a y b. struct cmplj mul_c ( struct cmplj a, strucr cmplj b ) { struct cmplj aux; aux.real = a.real * b.real – a.imag * b.imag; aux.imag = a.real * b.imag + a.imag * b.real; return aux; } Continúa... Dpto. de ATC, Universidad de Sevilla - Página 4 de 9 Fundamentos de Informática 17 Estructuras y funciones: ejemplo 1c 18 Estructuras y funciones: ejemplo 1d A continuación mostramos un pequeño programa que muestra por pantalla el resultado de la expresión 4x2+1, siendo x un número complejo cualquiera. El programa utiliza las funciones mostradas en las transparencias anteriores. Veamos paso a paso la sentencia del código anterior que realiza el cálculo: resultado = sum_c( mul_c( crea_c(4,0), mul_c(x,x) ), crea_c(1,0) ); x real 2 x2 (4,0) imag 1 resultado = sum_c( mul_c( resultado real Ejecución del programa: real 3 , imag 4 4x2 main() { imag struct cmplj x = {2,1}; struct cmplj resultado; resultado = sum_c( mul_c( crea_c(4,0), mul_c(x,x) ), crea_c(1,0) ); impr_c( resultado ); } real 4 imag 0 (1,0) real 12 resultado = sum_c( ), crea_c(1,0) ); imag 16 , real 1 ); imag 0 4x2+1 (13 + 16i) resultado = real 13 ; imag 16 19 Estructuras y funciones: ejemplo 2a 20 Estructuras y funciones: ejemplo 2b En este ejemplo se muestra una estructura que contiene datos de empleados de una empresa y dos funciones que realizan operaciones de este tipo de estructuras. Lee del teclado los datos de un empleado y devuelve un valor de tipo struct empleado con los datos leidos. #include <stdio.h> struct empleado { char nombre[80]; char apellidos[100]; unsigned int dni; char letra_nif; }; Las variables de tipo struct empleado contienen los datos de un empleado. Muestra por pantalla los datos del empleado contenidos en el parámetro e. void impr_empl( struct empleado e ) { printf( “NOMBRE:%s, %s\nDNI: %u%c\n”, e.apellidos, e.nombre, e.dni, e.letra_nif ); } struct empleado lee_empl() { struct empleado aux; printf( “Escribe el nombre: “ ); scanf( “%s”, aux.nombre ); printf( “Escribe los apellidos: “ ); gets( “%s”, aux.apellidos ); printf( “Escribe el DNI: “ ); scanf( “%u”, &aux.dni ); scanf( “%c”, &aux.letra_nif ); return aux; } Continúa... Dpto. de ATC, Universidad de Sevilla - Página 5 de 9 Fundamentos de Informática 21 22 Estructuras y funciones: ejemplo 2c Estructuras anidadas: ejemplo 1a A continuación se muestra como se pueden utilizar las funciones anteriores para leer e imprimir por pantalla los datos de un empleado. main() { struct empleado var; var = lee_empl(); printf( “\nEMPLEADO:\n“ ); printf( “*********\n“ ); impr_empl( var ); } Ejemplo de ejecución del programa: Escribe el nombre: Pedro Escribe los apellidos: Vargas Vargas Escribe el DNI: 54112112A EMPLEADO: ********* NOMBRE: Vargas Vargas, Pedro DNI: 54112112A Se pueden declarar estructuras que contienen a otras estructuras. Ejemplo: em hoy struct fecha { dia 1 int dia, mes, anio; mes 1 }; anio 2005 struct empleado { unsigned dni; struct fecha nac; struct fecha alta; }; main() { struct fecha hoy = {1,1,2005}; struct empleado em = {45112112, {25,1,1990}, {1,10,2004}}; em.nac.dia = 9; em.alta = hoy; printf( “%d”, em.alta.anio ); } dni 45112112 nac mes 1 anio 1990 dia alta 25 dia 1 mes 10 anio 2004 23 24 Estructuras anidadas: ejemplo 1b Vectores de estructuras: ejemplo struct fecha { int dia, mes, anio; }; struct empleado { unsigned dni; struct fecha nac; struct fecha alta; }; dni em nac alta 2005 Ejecución del programa: 9 mes 1 anio 1990 dia main() { struct fecha hoy = {1,1,2005}; struct empleado em = {45112112, {25,1,1990}, {1,10,2004}}; em.nac.dia = 9; em.alta = hoy; printf( “%d”, em.alta.anio ); } struct fecha { int dia, mes, anio; }; struct empleado { char nombre[30]; struct fecha alta; }; 45112112 dia 1 mes 1 anio 2005 Accedemos al campo anio del campo alta de em dia 1 hoy mes 1 anio 2005 Vector de 2 elementos de tipo struct empleado Valor inicial de plantilla[0] Valor inicial de plantilla[1] struct empleado plantilla[2] = { {“Lisa”, {12,5,1990}}, {“Bart”, {11,10,1985}} La variable hoy se copia en el campo alta de em Se pueden declarar vectores de estructuras, por ejemplo: Veamos algunos ejemplos de uso de vectores de estructuras: struct fecha hoy = {31,1,2005}; strcpy( plantilla[1].nombre, “Juan” ); plantilla[1].alta.mes = plantilla[1].alta.dia + 2; plantilla[0].alta = hoy; plantilla[0].alta = plantilla[1].alta; plantilla[1] = plantilla[0]; Dpto. de ATC, Universidad de Sevilla - Página 6 de 9 }; Accedemos al campo día del campo alta de plantilla[1] Fundamentos de Informática 25 Matrices de estructuras: ejemplo 26 Estructuras complejas: ejemplo 1a El siguiente ejemplo muestra un ejemplo de una posible estructura para manipular polinomios de coeficientes complejos y un ejemplo de una función que trabaja con dicha estructura: También podemos declarar matrices de estructuras. Ejemplo: Matriz de 2x2 elementos de tipo struct cmplj #define MAX 10 Las variables de tipo struct polinomio_cmplj contienen polinomios de coeficientes complejos. struct cmplj { double real, imag; }; La función suma_coef suma los coeficientes del polinomio struct polinomio_cmplj { contenido en el parámetro p y int grado; devuelve la suma calculada. struct cmplj coef[MAX]; }; struct cmplj suma_coef( struct polinomio_cmplj p ) { struct cmplj res = {0,0}; int i; Accedemos al campo imag del for (i=0; i<=p.grado; i++) { elemento de índice i del campo res.imag = res.imag + p.coef[i].imag; coef de la estructura p. res.real = res.real + p.coef[i].real; } return res; } Continúa... struct cmplj { double real, imag; }; Valor inicial de m[0][0] main() { struct cmplj m[2][2] = { {1,0}, {0,4}, {-3,1}, {5,5} }; struct cmplj p[9][15]; p[0][0] = m[1][1]; p[0][1].real = m[0][1].real + m[0][1].imag; } Matriz de 9x15 elementos de tipo struct cmplj 27 Estructuras complejas: ejemplo 1b Estructuras complejas: ejemplo 2 El siguiente programa muestra cómo podemos utilizar las estructuras y funciones anteriores. main() { struct polinomio_cmplj pol = { 3, {{1,2}, {0,1}, {-10,3}} }; struct cmplj res; res = suma_coef( pol ); } grado -9 imag 6 Ejemplos de acceso a campos coef 3 real 1 real 0 imag 2 imag 1 0 pol.coef[1].imag 1 real -10 imag 3 2 real ... ... A continuación se muestra un ejemplo de una función que calcula el valor de un polinomio de coeficientes complejos. struct polc { int grado; struct cmplj coef[10]; }; pol res real 28 imag 9 El tipo struct cmplj y la función crea_c están definidas en la transparencia “Estructuras y funciones: ejemplo 1a” struct cmplj evalua_polc( struct polc p, double x ) { int i; struct cmplj res = crea_c (0,0); double pot_x = 1; for (i=0; i<=grado; i++) { res = sum_c( res, mul_c( p.coef[i], crea_c(pot_x,0) ); pot_x = pot_x * x; } return res; } pol.coef[9].real Las funciones sum_c y mul_c están definidas en la transparencia “Estructuras y funciones: ejemplo 1b” Dpto. de ATC, Universidad de Sevilla - Página 7 de 9 Fundamentos de Informática 29 30 Punteros a estructuras: ejemplo 1a struct polinomio { int grado; double coef[10]; }; Punteros a estructuras: ejemplo 1b struct polinomio { int grado; double coef[10]; }; grado coef ... 0 1 2 3 ... 9 main() { struct polinomio v1 = {2, {-2, 0.1, 5.3}}; struct polinomio v2; p apunta a la variable v2 struct polinomio *p; int *g; Asignamos v1 a la variable apuntada por p p = &v2; (v1 se copia en v2). *p = v1; (*p).grado = 3; Asignamos 3 al campo grado de la variable (*p).coef[3] = 100; apuntada por p (asignamos 3 a v2.grado). g = &(v1.grado); v2 v2.coef[5] = *g; grado 3 g = &((*p).grado); *g = 0; coef -2 0.1 5.3 100 ... } 0 1 2 3 ... 9 main() { struct polinomio v1 = {2, {-2, 0.1, 5.3}}; struct polinomio v2; struct polinomio *p; int *g; p = &v2; *p = v1; g apunta al campo grado de v1 (*p).grado = 3; (*p).coef[3] = 100; Accedemos al campo grado de v1 g = &(v1.grado); v2.coef[5] = *g; g = &((*p).grado); g apunta al campo grado de v2 *g = 0; } Asignamos 0 al campo grado de v2 31 32 Punteros a estructuras: ejemplo Estructuras y ficheros: ejemplo 1a En el siguiente ejemplo se muestra una función que lee del teclado un número complejo y lo guarda en la estructura de tipo struct cmplj que se le pasa por referencia. struct cmplj { double real, imag; }; void scan_cmplj( struct cmplj *c ) { scanf( “%lf”, &(*c).real ); scanf( “%lf”, &(*c).imag ); } void main() { struct cmplj x; printf( “Escribe los valores real e imaginarios: “ ); scan_cmplj( &x ); } Cuando se trabaja con ficheros organizados en registros, es útil utilizar estructuras para contener los datos de los registros. Ejemplo: A continuación se muestra una posible solución al problema propuesto en la transparencia del tema de ficheros “Tratamiento secuencial: ejemplo 2a”. Los registros del fichero “temp.txt” se implementan con una estructura y se define una función para leer un registro de dicho fichero. #include <stdio.h> struct sensor { char nombre; int temp; }; Las variables de tipo struct sensor contienen los valores de un registro del fichero “temp.txt”. void lee_registro( FILE* f, struct sensor *r ) { char aux; fscanf( f, “%c”, &(*r).nombre ); fscanf( f, “%d”, &(*r).temp ); fscanf( f, “%c”, &aux ); } Continúa... Dpto. de ATC, Universidad de Sevilla - Página 8 de 9 Fundamentos de Informática 33 Estructuras y ficheros: ejemplo 1b main() { FILE *ftemp, *fsal; struct sensor reg; ftemp = fopen( “c:\\dir\\temp.txt”, “rt” ); fsal = fopen( “c:\\dir\\temp_a.txt”, “wt” ); if (ftemp != NULL && fsal != NULL) { lee_registro( ftemp, &reg ); while (!feof(ftemp)) { if (reg.nombre == ‘A’) { fprintf( fsal, “%d\n”, reg.temp ); } lee_registro( ftemp, &reg ); } fclose( ftemp ); fclose( fsal ); }else { printf( “ERROR\n” ); if (ftemp != NULL) fclose(ftemp); } } Dpto. de ATC, Universidad de Sevilla - Página 9 de 9