FUNDAMENTOS DE PROGRAMACIÓN PRÁCTICA 12: Manejo de Estructuras Objetivos El alumno conocerá y aplicará el concepto de estructuras para la solución de programas de ingeniería en Lenguaje C Introducción El leguaje C proporciona los medios para agrupar un conjunto de variables bajo un mismo nombre por medio de estructuras, ya que conviene mantener las variables relacionadas lo cual nos proporciona un enfoque orientado a datos. La sintaxis es struct nombre { tipo_dato nombre_variable; tipo_dato nombre_variable; }; El nombre de la estructura es opcional, también se pueden declarar el nombre de las variables después de la llave derecha que cierra. Por ejemplo, x,y,z que son variables del tipo de datos de la estructura. struct nombre { … } x,y,z: Cuando se accede a archivos de datos, con una estructura de registros fijo, el manejo de variables de tipo estructura es esencial. El siguiente ejemplo muestra una estructura de registro para un archivo sencillo de nombres y direcciones. struct data { int identificador; char nombre[100]; char direccion[30]; char ciudad[30]; char pais[30]; char cp[12]; char telefono[15]; }; Para declarar una variable posterior a la declaración de la estructura es necesario el nombre de la estructura para poder referenciarla por dicha etiqueta, por ejemplo: struct data registro1; Las estructuras no sólo contienen datos del mismo tipo, sino que pueden mezclarse los datos dentro de la estructura. Incluso, pueden incluirse estructuras dentro de otras estructuras (anidamiento de estructuras). Por ejemplo el campo nombre podemos descomponerlo en otra estructura llamada Nombre e incluir: nombre, apellido paterno y apellido materno como la siguiente. struct Nombre{ char nombre[40]; 1 Elaborado por: Sabino Miranda Jiménez FUNDAMENTOS DE PROGRAMACIÓN PRÁCTICA 12: Manejo de Estructuras char apellido_pat[30]; char apellido_mat [30]; } Entonces, en la estructura data podemos sustituir el campo nombre[30] por struct Nombre nom, lo cual representaría al nombre descompuesto en su tres partes: nombre, apellido paterno y materno. También en C se dispone de un keyword que nos auxilia al manejar el nombrado de las estructuras: typedef. Esta palabra clave nos sirve para crear un sinónimo de alguna variable. Por ejemplo, si queremos crear un sinónimo llamado Entero para el tipo de dato entero (int) se definiría de la siguiente forma. typedef int Entero El tipo de dato al que queremos crearle un sinónimo es el primer elemento, y el sinónimo es el segundo elemento para typedef. Entonces para declarar una variable por medio del sinónimo se define: Entero numero; La cual equivale a la declaración: int numero; En la declaración anterior Entero es un sinónimo del tipo de dato int. En la declaración de estructuras la declaración del sinónimo sí es de utilidad. Por ejemplo, si declaramos un sinónimo para la estructura data podemos declarar variables con el nombre del sinónimo definido: typedef struct data { int identificador; char nombre[100]; char direccion[30]; char ciudad[30]; char pais[30]; char cp[12]; char telefono[15]; } Registro; La declaración de una variable de estructura tipo struct data por medio de su sinónimo sería: Registro regist1; Que sería equivalente a definir struct data regist1; Para acceder a los miembros o elementos de la estructura, se utiliza el operador punto “.” En el caso siguiente se asigna el valor de 10 a la variable identificador de la estructura regist1.identificador = 10; 2 Elaborado por: Sabino Miranda Jiménez FUNDAMENTOS DE PROGRAMACIÓN PRÁCTICA 12: Manejo de Estructuras Debido a que apuntadores a estructuras son muy usados, C proporciona una abreviación para acceder al miembro de la estructura cuando se trata de un apuntador a estructura, es el operador flecha (guión seguido del signo mayor que) “->” Si p es un apuntador a estructura de tipo Registro, para acceder o asignar a lo que apunta su elemento identificador se utiliza el operador flecha. Registro *p; p->identificador = 10; En el Ejemplo1 se inicializan los elementos de la estructura por medio de la asignación explícita de los datos, punto pt1; o por medio del operador punto como se hace la asignación para el punto pt2. En este caso, los valores se asignan a cada una de las variables, es decir, el primer valor se asigna a la primera variable, el segundo a la segunda variable, etc. Ejemplo1 #include <stdio.h> #include <conio.h> typedef struct punto{ int x; int y; } Punto; int main() { Punto pt1 ={10,20}; Punto pt2; pt2.x=20; pt2.y=30; printf("Punto1(x,y)= (%d,%d)\n",pt1.x,pt1.y); printf("Punto2(x,y)= (%d,%d)\n",pt2.x,pt2.y); getche(); return 0; } En el Ejemplo2 se cambia los datos del punto 2, pt2, por medio de un apuntador pt3, el cual direcciona la localidad de memoria del punto 2. En este caso se hace uso del operador flecha para acceder a la localidad de memoria de pt2. Ejemplo2 #include <stdio.h> #include <conio.h> typedef struct punto{ int x; int y; } Punto; int main() { Punto pt1 ={10,20}; 3 Elaborado por: Sabino Miranda Jiménez FUNDAMENTOS DE PROGRAMACIÓN PRÁCTICA 12: Manejo de Estructuras Punto pt2; Punto *pt3; pt2.x=20; pt2.y=30; printf("Punto1(x,y)= (%d,%d)\n",pt1.x,pt1.y); printf("Punto2(x,y)= (%d,%d)\n",pt2.x,pt2.y); pt3=&pt2; pt3->x=30; // equivale a (*pt3).x = 30 pt3->y=0; // equivale a (*pt3).y = 0 printf("Punto2(x,y)= (%d,%d)\n",pt2.x,pt2.y); getche(); return 0; } En el Ejemplo3 se hace uso de la estructura Punto del Ejemplo2. Se definen dos funciones. La primera es imprimePunto la cual acepta una estructura de tipo Punto e imprime los valores de los elementos x e y. La segunda función muevePunto desplaza el punto la cantidad de unidades que se indican con el parámetro incremento, al finalizar retorna una estructura de tipo Punto. Es importante que esa variable retornada sea recibida por algún tipo de dato compatible, por ejemplo, pt2 que es una variable de tipo Punto. En el ejemplo se despliegan los datos antes de desplazarlos y después de realizar el desplazamiento del punto, pt1. Ejemplo3. void imprimePunto(Punto p) { printf("Coordenadas (x,y)= (%d,%d)\n",p.x,p.y); } Punto muevePunto(Punto p, int incremento) { p.x = p.x + incremento; p.y = p.y + incremento; return p; } int main() { Punto pt1 ={10,20}; Punto pt2; imprimePunto(pt1); pt2 = muevePunto(pt1,50); imprimePunto(pt2); getche(); return 0; } 4 Elaborado por: Sabino Miranda Jiménez FUNDAMENTOS DE PROGRAMACIÓN PRÁCTICA 12: Manejo de Estructuras En el Ejemplo4 se hace uso de la estructura Punto definida en el Ejemplo2, para describir un rectángulo por medio un arreglo de 4 puntos, ya que las estructuras se definen como un tipo más de datos, podemos definir arreglos de este tipo de datos. Recuérdese que Punto es un sinónimo de struct punto y podemos intercambiarlos indistintamente. La función imprimeRect recibe como parámetro una variable de tipo Rect la cual contiene un arreglo de datos de tipo Punto. El manejo de los elementos es similar a los arreglos de cualquier otro tipo de datos: int, char, etc. La consideración importante es que cada elemento de la variable pts es un elemento de tipo Punto. pts[0] es un elemento de tipo Punto que une dos variables enteras: x e y. También pts[1] es de tipo Punto y posee dos variables enteras: x e y pero que pertenecen a otro elemento, es decir, son independientes ya que pertenecen a otro elemento. Para acceder al arreglo de puntos del rectángulo se hace con el operador punto “.” y la variable pts se maneja como un arreglo tradicional, como se muestra en el ejemplo. Ejemplo4 typedef struct rect { Punto pts[4]; }Rect; void imprimePunto(struct punto p); void imprimeRect(struct rect r); int main() { Rect rec ={10,20,1,2,10,11,5,6}; imprimeRect(rec); rec.pts[2].x=1000; rec.pts[2].y=2000; printf("\n\nRectángulo modificado\n"); imprimeRect(rec); getche(); return 0; } void imprimePunto(Punto p) { printf(" (%d,%d)\n",p.x,p.y); } void imprimeRect(Rect r) { 5 Elaborado por: Sabino Miranda Jiménez FUNDAMENTOS DE PROGRAMACIÓN PRÁCTICA 12: Manejo de Estructuras for(int i=0; i<4;i++) { printf("Punto %d=",i+1); imprimePunto(r.pts[i]); } } EJERCICIOS PROPUESTOS Capturar y probar los ejercicios resueltos. Resolver los ejercicios siguientes: 1. Modificar el Ejemplo4 para que los datos del rectángulo los capture el usuario,es decir, el programa solicita al usuario cada pareja de datos (x,y) que representa a cada punto, la asignación de los datos se hace en una estructura de tipo Rect, para después imprimir los datos del rectángulo por medio de la función imprimeRect. 2. Desarrollar un programa que defina una estructura para guardar un número Complejo (parte real y parte imaginaria) y las funciones de suma, resta y multiplicación de números complejos. Presentar al usuario un menú de las operaciones disponibles. El usuario captura los dos números complejos con los que se quiere hacer la operación (parte real y parte imaginaria). Los resultados se presentan por medio de otra función que imprime sólo números complejos. Un número complejo en forma binomial se representa : Z = a + bi a: representa la parte real b: representa la parte imaginaria Dados Z1 y Z2 números complejos entonces: Z1 + Z2 = ( a1 + a2 ) + (b1 + b2)i Z1 – Z2 =( a1 + b1i) – (a2 + b2i) = ( a1 – a2) - (b1 - b2)i. Z1 * Z2 = (a1 a2 - b1b2) + (a1 b2+ b1 a2)i Todas las operaciones aceptan dos números complejos, regresan el resultado como el valor de retorno de la función, es decir, retornan un número complejo. Por ejemplo, todos los números representan a un tipo de dato Complejo. complejo3 = suma(complejo1, complejo2); 6 Elaborado por: Sabino Miranda Jiménez