Una estructura es un conjunto de variables de los mismos o diferentes tipos. Las estructuras son semejantes a los registros (records) de Pascal.
Los elementos integrantes de una estructura se denominan miembros. Pascal llama campos (fields) a los elementos de una estructura, pero C reserva este nombre para referirse a los miembros particulares de estructuras que permiten manejo de bits.
La declaraciòn de una estructura se hace como:
struct x {
miembros-y-declaraciones
}
utilizándose como un tipo de dato más en declaraciones de tipo de variables.
"x" es el nombre de la estructura. Las referencias posteriores a la misma estructura pueden omitir las llaves ({}) y la declaración de sus miembros.
Los miembros y declaraciones incluidos en la estructura son como cualquier declaración de variable de las vistas hasta ahora, con la única diferencia de que no puede especificarse'un tipo de almacenamiento (auto, static, register, extern). Por ejemplo:
struct fecha {
int dias;
int mes;
int año;
};
struct persona {
char nombre[TAMAÑO1];
long cod_postal;
long ss_num;
double sueldo;
struct date nacim_fecha;
struct date incorp_fecha;
};
serìa equivalente a los records de Pascal:
type
date = record
dia: 1..31;
mes: 1..12;
año: integer;
end;
person = record
nombre: array [1.. TAMAÑO2] of char;
cod_postal: integer;
sueldo: real;
nacim_fecha: date;
incorp_fecha: date;
end;
En este ejemplo definimos una estructura "fecha" conteniendo tres variables enteras: día, mes y año, y definimos una estructura "persona", conteniendo dos arrays de caracteres (nombre y dirección) cod_postal de tipo long, ss_num de tipo long, sueldo de tipo double, y dos miembros consistentes en estructuras "fecha", correspondientes a nacim_fecha e incorp_fecha.
Para acceder a un miembro de una estructura se utiliza el operador ".", como ya anticipábamos al hablar.de las variables en C y sus tipos. Se recurre a él en la forma:
estructura-variable.miembro 4
Por ejemplo, para declarar una variable "d" como una estructura "fecha" e inicializarla a la fecha 1 de junio de 1986, se haría del modo siguiente:struct fecha d;
d.dia = 1
d.mes = 6;
d.año = 1986;
Como podemos observar en la declaración de la estructura persona las estructuras se pueden encadenar, pudiendo utilizarse como miembros de otras estructuras. Si se define "emp" como una estructura persona:
struct persona emp;
entonces
emp.nacim_fecha.año
se referirá al año de nacimiento del empleado en cuestión.
Una estructura externa o estática se puede inicializar acompañando el nombre de la estructura por una lista de inicializado-res rodeados por llaves ({}).
struct fecha d = {1, 6, 1986};
Declara "d" como una estructura fecha, e inicializa d.día a 1, d.mes a 6 y d.año a 1986.
Operaciones sobre estructuras
En implementaciones antiguas de C las únicas operaciones permitidas sobre las estructuras eran el acceso a sus miembros (mediante un "."), o el acceso a su dirección (mediante un &). ,
Los compiladores más recientes permiten la asignación de variables estructura, incluyendo el paso de estructuras como parámetros y devolviendo estructuras como valores de funciones.
No está permitido realizar comparaciones de estructuras.
Muchos compiladores que admiten la devolución de estructuras lo hacen de manera no-reentrante, dejando el valor de la estructura devuelta en una variable estática en lugar de en el stack.
Las estructuras automáticas no pueden inicializarse a pesar de que inicializar variables automáticas es equivalente a realizar una asignación. En el S.O. Unix se obtendría el mensaje de error "No auto aggregate inicialitation" como respuesta a este intento.
Punteros a estructuras:
Debido a las restricciones impuestas a las variables de tipo estructura normalmente se suelen utilizar punteros a estructuras para realizar el traspaso de estructuras como argumentos de funciones.
Incluso si se permiten asignaciones de estructuras, pasar una estructura como argumento puede no ser muy buena idea en ocasiones; por ejemplo:
#define LINEAS 24
#define COLUMNAS 80
struct ventana { /* una parte de una pantalla */
char lineas [LINEAS] [COLUMNAS];
int ult_col; /* esquina superior */
int ult_fila; /* esquina superior */
int nlineas; /* esquina superior */
int ncols; /* esquina superior */
La llamada a "muestra" (definida en otro lugar) copia la totalidad de la estructura en el stack. Esta estructura contiene LINEAS * COLUMNAS = 24 x80 = 1920 caracteres, así como algunas variables enteras. Compárese esto frente a la alternativa de pasar como argumento un puntero a la estructura, que requeriría tan sólo una variable entera (la dirección de la estructura).
Hay que destacar que pantalla.lineas es un array, y aquí se pasaría un puntero al primer elemento de este araay en la llamada a la función borra_pantalla.
Los punteros a estructuras se declaran de la manera habitual, como los restantes punteros:
/* extrae elementos de la estructura
# persona y los imprime
*/
ppersona (p)
struct persona *p
{
print-f ( "Nombre: %s\n", p->nombre) ;
print-f ("Dirección: %s\n", p->direccion) ;
print-f ("Código Postal: "%d\n", p->cod_postal)
print-f ("Código de la S.S.:%d\n", p->ss_num)
printf("Sueldo: %.2-f\n", p->sueldo);
printf ("Fecha de nacimiento: %d %d %d\n",
p->nacim_fecha.dia,
p->nacim_fecha.mes,
p->nacim_fecha.año);
print-f ("Fecha de incorporación: %d $d %d\n",
p->incorp_fecha.dia,
p->incorp_fecha.mes
p->incorp_fecha. año);
La construcción
puntero-a-estructura->miembroes equivalente a:
(*puntero-a-estructura) .miembro
El operador "->" consiste eb un signo menos "-" seguido por el signo mayor ">".
Los paréntesis en "(*p).nombre" son necesarios porque el orden de evaluación del operador "." (miembro de una estructura) es mayor que el del operador "*" (valor apuntado por) Así *emp.nombre es equivalente a emp.nombre[0].
Los operadores "." y "->" tienen mayor prioridad que los operadores aritmèticos. Así pues, dada la declaración:
struct {
int x;
inty;
} *p;
la expresiòn
++p->x
incrementaría el valor del miembro "x" de la estructura apuntada por "p", en lugar de incrementar el puntero "p".
Análogamente:
*p->y; obtiene el valor de "y" apuntado por "p"
*p->y++ idem. , incrementando p->y
(*p->y)++ incrementa la "y" apuntada por "p"
*p++->y; incrementa "p" tras buscar p->y
Del mismo modo que C permite arrays de arrays como un tipo más de variables, también permite la definición de arrays de estructuras.