Fundamentos de programación Estructuras y Uniones Estructuras Una estructura es una forma de agrupar un conjunto de datos de distinto tipo bajo un mismo nombre o identificador. struct [nombre] { <tipo> <campo> [,<campo>,…,<campo>]; ··· ··· ··· <tipo> <campo> [,<campo>,…,<campo>]; } La declaración de una estructura crea un nuevo tipo de datos, cuyo nombre puede ser o no especificado. Estructuras Declaraciones struct complejo { double Re, Im; }; struct complejo z, w, vector[20]; struct persona { int dni; char nombre[20], apellido[50]; char direccion[100]; } persona1, persona2; struct persona arraypersonas[40]; Estructuras Declaraciones struct vehiculo { int precio; char marca [20]; char * matricula; }; struct vehiculo coche, camion, moto; typedef struct TLista { int NElem; TElem valores [MaxElem]; } TipoLista; TipoLista Lista, ArrayListas [10]; Estructuras Acceso a los campos de una estructura <variable estructura>.<campo> struct vehiculo coche, camion, moto; coche.precio = 15500; memcpy(camion.marca,“RENAULT”,7); moto.matricula = “3491 CKS”; for(i = 0; i < 20; i++) coche.marca[i] = ‘ ’; scanf(“%d %s”, &coche.precio, coche.marca); printf(“%s\n”,moto.matricula); Estructuras Inicialización de estructuras struct fecha { int dia; char * mes; int año; } fiesta = {12, “octubre”, 1991}; struct fecha Fec[2] ={{6, “enero”, 2012}, {4, “marzo”, 2004}}; struct complejo z = {1, 1}; struct complejo w = {0, 1}; TipoLista Lista = {0, {0}}; struct TLista NuevaLista = {4, {6,3,1,9}}; Estructuras Asignación de estructuras La sentencia de asignación, a diferencia de arrays, puede usarse para realizar una copia global de estructuras. struct fecha { int dia; char * mes; int año; } Antigua, Nueva; La sentencia de asignación Antigua = Nueva; copia la estructura Nueva en Antigua campo a campo. Estructuras Estructuras como retorno de una función struct Rect { double coX, coY; }; struct Polar { double rad, ang; }; struct Rect polar2rect (struct Polar punto) { struct Rect rt; rt.coX = punto.rad * cos(punto.ang); rt.coY = punto.rad * sin(punto.ang); return rt; } Estructuras Estructuras con campos estructura struct Coordenadas { struct Rect rec; struct Polar pol; }; struct Coordenadas c, coor[3]; c.rec.coX = 1.0; c.rec.coY = 2.0; c.pol.rad = 1.5; c.pol.ang = 0.5; c.rec = polar2rect(c.pol); coor[0] = c; coor[1].rec.coX = 1.0; coor[2].pol.ang = PI/2; Estructuras Punteros a estructuras struct ejemplo { int vp; char * cadena; char vector [4]; }; struct ejemplo A, *ptr; A.vp = 3; A.cadena = “Hola”; A.vector = {0}; ptr = &A; printf(“%d\n”, ptr->vp); printf(“%s\n”, ptr->cadena); for(j = 0; j < 4; j++) ptr->vector[j] = 8; Estructuras Acceso a los campos de un puntero a estructura (*<variable puntero>).<campo> <variable puntero> -> <campo> ¾ Los paréntesis son necesarios debido a la mayor prioridad del operador ‘.’ respecto a ‘*’ ¾ La segunda forma de acceso es más compacta y habitual. struct ejemplo * ptr; (*ptr).vp; (*ptr).cadena[0]; (*ptr).vector; *(*ptr).cadena; &(*ptr).vector[j]; ptr->vp; ptr->cadena[0]; ptr->vector; *ptr->cadena; &ptr->vector[j]; Estructuras Acceso a los campos de un puntero a estructura struct { int num; char * cad; } *ptr; ++ptr->num (++ptr)->num (ptr++)->num ptr++->num *ptr->cad *ptr->cad++ (*ptr->cad)++ *ptr++->cad : : : : : : : : Incrementa num, no ptr. Incrementa ptr antes de acceder a num. Accede a num y después incrementa ptr. Lo mismo que lo anterior. Accede al contenido del puntero cad. Accede al contenido de cad y después incrementa cad. Aumenta el valor del contenido de cad en una unidad. Incrementa ptr tras acceder al contenido del punt. cad. Estructuras Funciones y parámetros de salida con estructuras struct registro { int valor; char cadena [6]; int vector [4]; }; void LeerRegistro (struct registro * Reg) { int j; scanf(“%d”, &Reg->valor); for(j = 0; j < 6; j++) scanf(“%c”, &Reg->cadena[j]); for(j = 0; j < 4; j++) scanf(“%d”, &Reg->vector[j]); } Estructuras Funciones y parámetros de salida con estructuras void main ( ) { int j; struct registro info; void LeerRegistro (struct registro *); do LeerRegistro(&info); while(info.valor < 0); printf(“%d\n”,info.vector[0]); for(j = 1; j < 4; j++) { info.vector[j] += info.vector[0]; printf(“%d\n”, info.vector[j]); } } Estructuras Tamaño de una estructura En general el tamaño (en bytes) de una estructura no tiene por qué coincidir con la suma del tamaño de sus campos. Por ejemplo, si asumimos que el tamaño de un char es un byte y que un int ocupa cuatro bytes, la estructura struct campos { char car; int ent; }; puede requerir ocho bytes en vez de cinco. Esto se debe al alineamiento de variables en C. En estos casos hay que utilizar el operador sizeof, sizeof(struct campos). Uniones Una unión es una variable que puede tener (en distintos instantes) objetos de diferentes tipos y tamaños. Estas variables proporcionan una forma de manejar clases de datos diferentes, pero que se ubican en una misma área de memoria. union [nombre] { <tipo> <campo>; ··· ··· ··· <tipo> <campo>; } Uniones La unión debe tener el suficiente tamaño para almacenar el campo más largo. El tamaño total dependerá de la máquina donde se realice la implementación. union UClase { char *svalor; long int ivalor; } Clase; Supongamos que sizeof Clase == 4. El tratamiento de estos cuatro bytes está condicionado al campo con que se accede a la unión. Uniones El acceso a los campos de una unión se realiza de igual forma que las estructuras. Ahora, si tenemos en cuenta que los campos de las uniones comparten el mismo área de memoria, ¿qué salida nos podemos esperar al ejecutar estas sentencias? Clase.svalor = “ABC”; printf(“%s\n”, printf(“%ld\n”, printf(“%ld\n”, printf(“%p\n”, printf(“%lx\n”, Clase.svalor); Clase.ivalor); Clase.svalor); Clase.svalor); Clase.ivalor); Uniones ¾ Los accesos a los campos de una unión y/o puntero a unión se hacen de la misma forma que una estructura y/o puntero a estructura. ¾ Los campos de una unión comparten una misma área de memoria. ¾ Una unión sólo puede ser inicializada con un valor del tipo de su primer campo. ¾ La sentencia de asignación puede usarse para copiar uniones que tengan la misma definición. Uniones con campos de bits union byte { unsigned char b; struct { unsigned int unsigned int unsigned int unsigned int unsigned int unsigned int unsigned int unsigned int } bits; struct { unsigned int unsigned int } nibbles; }; bit8:1; bit7:1; bit6:1; bit5:1; bit4:1; bit3:1; bit2:1; bit1:1; nibble2:4; nibble1:4;