Materiales y repaso Taller 5 2022 + Grabación

Materiales y repaso Taller 5 2022 + Grabación

de Juan Pablo Garella -
Número de respuestas: 0

Estimados, 

A continuación encontrarán el repaso del taller 5. La grabación del taller se encuentra en la sección: Clases Online. Se adjunta materiales y código fuente  de las soluciones de los ejercicios que se realizaron en clase.  

El siguiente taller (Taller 6) se dictará el Jueves 21 de Abril de 8 a 10 am. El link de zoom será el mismo para todos los talleres, lo pueden encontrar la sección Novedades. 


Taller 5: Estructuras

Requisitos:

  • Mandatorio ver la grabación Teórico-Clase 5 (Sección: Clases Online)
  • (Opcional) Leer capítulo 6 del Libro K&R.
  • Relevamiento sobre instalación de la máquina virtual/ Entornos Linux.

Esquema: 

  • Tutorial GDB para depurar errores de violación de segmento en tiempo de ejecución (código provisto en el taller 4)
  • Revisión pasaje por valor y pasaje por referencia (solución del ejercicio 2 del práctico 5, código provisto en el taller 4).
  • Repaso de estructuras y uniones, se adjunta código fuente visto en clase.

 NOTA: En el siguiente taller se continuará y culminará con estructuras y uniones.


                Conceptos básicos de estructuras:

                Una estructura es una colección de una o más variables, posiblemente de diferentes tipos, agrupadas bajo un solo nombre para un manejo conveniente. A modo de ejemplo, proviene de los gráficos, un punto es un par de coordenadas, un rectángulo es un par de puntos, etc. Siendo el punto el objeto básico.

                Los dos componentes se pueden colocar en una estructura declarada de la siguiente manera:

                struct point {

                                int x;

                                int y; 

                };

                La palabra struct introduce una declaración de estructura, que es una lista de declaraciones entre llaves.

                La etiqueta nombra este tipo de estructura y puede utilizarse posteriormente como abreviatura de la parte de la declaración entre llaves.

                Las variables nombradas en una estructura se denominan miembros.

                Una declaración de estructura define un tipo:

                struct { ... } x, y, z;

                es sintácticamente análoga a:

                int x, y, z;

                Por otro lado:  

                struct point pt;

                define una variable pt que es una estructura de tipo struct point.

                struct point pt  = { 320, 200 }; // Declaración e inicialización de una variable struct point.

                De esta manera se acceden a lo miembros: structure-name.member  

                printf("%d,%d", pt.x, pt.y);

                Si se va a pasar una estructura grande a una función, generalmente es más eficiente pasar un puntero que copiar toda la estructura. Los punteros de estructura son como punteros a variables ordinarias. 

                La declaración:

                struct point *pp;

                dice que pp es un puntero a una estructura de tipo struct point. Si pp apunta a una estructura de puntos, *pp es la estructura y (*pp).x y (*pp).y son los miembros. 

                Podríamos escribir, por ejemplo,

                struct point origin, *pp;

                pp = &origin;

                printf("origin is (%d,%d)\n", (*pp).x, (*pp).y);


                Declaración de un estructura rectángulo:

                struct rect {

                                struct point pt1;

                                struct point pt2;

                 };


                La estructura rect contiene dos estructuras de puntos. Si declaramos screen cómo:

                struct rect screen;

                entonces:

                screen.pt1.x

                se refiere a la coordenada x del miembro pt1 de screen.


                Estructuras y funciones

                Investiguemos las estructuras escribiendo algunas funciones para manipular puntos y rectángulos. Hay al menos tres enfoques posibles: pasar componentes por separado, pasar una estructura completa o pasarle un puntero. Cada uno tiene sus puntos buenos y sus puntos malos.

                struct point origin, *pp;

                pp = &origin;

                printf("origin is (%d,%d)\n", (*pp).x, (*pp).y);

                Los paréntesis son necesarios en (*pp).x debido a la precedencia del operador de miembro de estructura . es mayor que *. La expresión *pp.x significa *(pp.x), lo cual es ilegal aquí porque x no es un puntero.

                p->miembro-de-estructura

                se refiere al miembro en particular. Así que podríamos escribir en su lugar

                printf("el origen es (%d,%d)\n", pp->x, pp->y);

                Ambas cosas . y -> asocian de izquierda a derecha, por lo que si tenemos

                struct  rect r, *rp = &r;

                entonces estas cuatro expresiones son equivalentes:

                r.pt1.x

                rp->pt1.x

                (r.pt1).x

                (rp->pt1).x


                Los operadores de estructura . y ->, junto con () para las llamadas a funciones y [] para los subíndices, se encuentran en la parte superior de la jerarquía de precedencia y, por lo tanto, se unen muy estrechamente. 

                Por ejemplo, dada la declaración

                struct {

                                int len;

                                char *str;

                } *p;

                entonces

                ++p->len;

                incrementa len, no p, porque el paréntesis implícito es ++(p->len).


                Arreglos de estructuras (ejemplos):

                struct key {                

                                char *word;

                                int count;

                } keytab[NKEYS];


                struct key {

                                char *word;

                                int count; 

                };

                struct key keytab[NKEYS];

                No asuma, sin embargo, que el tamaño de una estructura es la suma de los tamaños de sus miembros. Debido a los requisitos de alineación de diferentes objetos, puede haber "agujeros" sin nombre en una estructura. Así, por ejemplo, si un char es de un byte y un int de cuatro bytes, la estructura

                struct {

                                char c;

                                int i;

                };

                bien podría requerir ocho bytes, no cinco. El operador sizeof devuelve el valor adecuado. 

                C proporciona una función llamada typedef para crear nuevos nombres de tipos de datos. Por ejemplo, la declaración 

                typedef int Length;

                hace que el nombre Length sea un sinónimo de int.


                Ejemplo:

                typedef struct Books {

                                char title[50];

                                char author[50];

                                char subject[100];

                                int book_id;

                } Book;

                 Book book;


                Uniones

                Una unión es una variable que puede contener (en diferentes momentos) objetos de diferentes tipos y tamaños.

                En efecto, una unión es una estructura en la que todos los miembros tienen un desplazamiento cero desde la base, la estructura es lo suficientemente grande como para contener el miembro "más ancho" y la alineación es adecuada para todos los tipos de la unión. Se permiten las mismas operaciones en las uniones que en las estructuras: asignación o copia como unidad, toma de dirección y acceso a un miembro.


                Ejemplo:

                union Data {

                                int i;

                                float f;

                                char str[20];

                };

                Una unión solo puede inicializarse con un valor del tipo de su primer miembro, por lo tanto, la unión anterior sólo se puede inicializar con un valor entero.

                Ejemplo:


                union Data data;

                data.i = 10;

                printf( "data.i : %d\n", data.i);

                data.f = 220.5;

                printf( "data.f : %f\n", data.f);

                strcpy( data.str, "C Programming");

                printf( "data.str : %s\n", data.str);


Requisitos para el siguiente Taller (Taller 6: Entrada/Salida )

  • Mandatorio ver la grabación Teórico-Clase 6 (Sección: Clases Online)
  • (Recomendado) Leer capítulo 7 del Libro del curso (K & R).
  • En caso de tener instalado un sistema operativo que no sea linux (Windows, MAC) instalar virtualBOx y levantar la máquina virtual concedida por los docentes. En caso de dudas, realizar la consulta en la sección de Consultas en EVA.


Links de interés: 

  • Tutorial sobre gdb: link