\chapter{Estructuras, Uniones y enumeraciones}

\section{Estructuras en C}

Una Estructura es una colección de variables simples, que pueden contener diferentes tipos de datos. Es un tipo de dato definido por el usuario. Son también conocidas como Registros. Ayudan a organizar y manejar datos complicados en programas debido a que agrupan diferentes tipos de datos a las que se les trata como una sola unidad en lugar de ser vistas como unidades separadas.

La Declaración de estructuras en programas C es un nuevo tipo de datos denominado tipo Estructura y declarar una variable de este tipo.

En la definición del tipo de estructura, se especifican los elementos que la componen asÌ como sus tipos. Cada elemento es llamado miembro (similar a un campo de un registro).

\begin{verbatim}
struct tipo_estructura { Declaración de los miembros };
\end{verbatim}


Después de definir un tipo estructura, se puede declarar una o más variables de ese tipo de la siguiente forma:

\begin{verbatim}
struct tipo_estructura [variables];
\end{verbatim}

Ejemplo

\begin{verbatim}
struct articulo {
  int codigo;
  char nombre[20];
  float peso, longitud;
};
\end{verbatim}

Definición de variables de esta estructura : struct a, b; ó también se pueden definir la estructura y sus variables al mismo tiempo:

\begin{verbatim}
struct articulo {
  int codigo;
  char nombre[20];
  float peso, longitud;
} a, b;
\end{verbatim}

El Acceso a los Miembros de la Estructura es por medio del operador Punto de la siguiente manera:

\begin{verbatim}
a.codigo = 1234;
b.nombre = "escoba";
b.peso = 23;
\end{verbatim}

Los miembros de las Estructuras también se pueden inicializar individualmente o bien, todos simultáneamente. La inicialización individual es por medio del operador punto, para la estructura completa es con caracteres llaves y los valores de los miembros separados por coma. Iniciando solo por miembros: a.codigo=1234;

Iniciando Estructura completa:
\begin{verbatim}
articulo a={1234, "escoba", 23, 1.50};
\end{verbatim}


\subsection{Ejemplo de manejo de estructuras}

\begin{verbatim}
// Ejemplo ej045.c

/**
 * Title: Manejo de estructuras en C
 * Description: Crea una estructura con datos
 * desde el teclado
 * Copyright: Copyright (c) 2005
 * Company: UMSNH
 * author Dr. Felix Calderon Solorio
 * version 1.0
 */

#include <stdio.h> 
#include <conio.h>

struct datos {
    char no_control[9];
    char nombre[30];
    int edad;
    char sexo;
    char domicilio[50];
};


void imprime(struct datos a);

int main() {
    struct datos alumno;

    printf("\nIntroduce los datos del alumno");
    printf("\nNo Control : ");
    scanf("%s", alumno.no_control);
    printf("\nNombre     : ");
    scanf("%s", alumno.nombre);
    printf("\nEdad       : ");
    scanf("%d", &alumno.edad);
    printf("\nSexo       : ");
    alumno.sexo = getchar();
    alumno.sexo = getchar();
    printf("\nDireccion  : ");
    scanf("%s", alumno.domicilio);

    imprime(alumno);

    return 1;
}

void imprime(struct datos a) {
    printf("No de control %s\n", a.no_control);
    printf("Nombre %s\n", a.nombre);
    printf("Edad %d\n", a.edad);
    printf("Sexo %c\n", a.sexo);
    printf("Direccion %s\n", a.domicilio);
}
\end{verbatim}

\subsection{Arreglos de Estructuras}
Arreglos de Estructuras pueden ser construidas, es decir, conceptuar a los elementos de un arreglo como estructuras, esto se puede hacer de la siguiente manera:

\begin{verbatim}
struct datos {
    char no_control[9];
    char nombre[30];
    int edad;
    char sexo;
    char domicilio[50];
};

struct datos alumnos[35];
\end{verbatim}

Para tener acceso a una determinada estructura , se indexa el nombre de la estructura de la siguiente manera: alumnos[i].nombre; aquí sabemos el nombre del alumno que se encuentra en la posición i del arreglo, y de esta manera para todos los datos. Si se desea inicializar los valores, se podría hacer de la siguiente manera:

\begin{verbatim}
struct datos.alumno[5]={96147523, "Luis", 22, "m", "pino 45"};
\end{verbatim}

\subsection{Estructuras Anidadas}

El siguiente ejemplo muestra una estructura anidada. Las estructuras que hemos visto han sido muy sencillas aunque útiles. Es posible definir estructuras conteniendo docenas y aún cientos ó miles de elementos pero sería ventajoso para el programador no definir todos los elementos en una pasada sino utilizar una definición de estructura jerárquica.

\begin{verbatim}

// Ejemplo ec046.cpp

/**
 * Title: Manejo de estructuras en C
 * Description: Crea una estructura con datos
 * desde el teclado
 * Copyright: Copyright (c) 2005
 * Company: UMSNH
 * author Dr. Felix Calderon Solorio
 * version 1.0
 */

#include <string.h> #include <stdio.h>

struct persona {
    char nombre[25];
    int edad;
    char estado; // C = casado, S = soltero
};

struct datos {
    int calificacion;
    struct persona descripcion;
    char comida[25];
};

void imprime(struct datos a);

int main() {
    struct datos estudiante[53];
    struct datos maestro, sub;

    maestro.calificacion = 94;
    maestro.descripcion.estado = 'C';
    strcpy(maestro.descripcion.nombre, "Lisseth Gil");
    strcpy(maestro.comida, "Chocolate de Ron");

    sub.descripcion.edad = 87;
    sub.descripcion.estado = 'C';
    strcpy(sub.descripcion.nombre, "Abuela Pata");
    sub.calificacion  = 73;
    strcpy(sub.comida, "Maiz y agua");

    estudiante[1].descripcion.edad = 15;
    estudiante[1].descripcion.estado = 'S';
    strcpy(estudiante[1].descripcion.nombre, "Bill, Griton");
    strcpy(estudiante[1].comida, "Crema de cacahuate");
    estudiante[1].calificacion = 77;

    estudiante[7].descripcion.edad = 14;
    estudiante[12].calificacion = 87;

    imprime(sub);

    return 1;
}


void imprime(struct datos a) {
    printf("Nombre %s\n", a.descripcion.nombre);
    printf("Edad %d\n", a.descripcion.edad);
    printf("Estado %c\n", a.descripcion.estado);
    printf("calificacion %d\n", a.calificacion);
}
\end{verbatim}

La primera estructura contiene tres elementos pero no le sigue ninguna variable definida, sólo una estructura, pero como incluimos un nombre al principio de la estructura, la estructura es llamada persona. La palabra persona puede utilizarse para referirse a la estructura pero no a cualquier variable de éste tipo de estructura, se trata por lo tanto de un nuevo tipo que hemos definido y lo podemos utilizar de la misma manera en que usamos un int, char o cualquier otro tipo que existe en C. La única restricción es que éste nuevo tipo debe estar siempre asociado con la palabra clave struct.

La siguiente definición de estructura contiene tres campos siendo el segundo la estructura previamente definida la cual llamamos persona. La variable de tipo persona se llama descripción, así la nueva estructura contiene dos variables simples, calificación y una cadena llamada comida, y la estructura llamada descripción. Como descripción contiene tres variables, la nueva estructura tiene entonces cinco variables, a ésta estructura le hemos dado el nombre de datos, lo cual es otro tipo definido. Finalmente, dentro de la función main ( ) definimos un array de 53 variables cada una con la estructura definida por el tipo datos, y cada una con el nombre estudiante, en total hemos definido 53 veces 5 variables, cada una de las cuales es capaz de almacenar datos. Como tenemos la definición de un nuevo tipo podemos utilizarla para a su vez definir dos variables. Las variables maestro y sub están definidas en la línea 20 como variables de tipo datos por lo que cada una de éstas dos variables contienen 5 campos en los cuales podemos almacenar datos.

En las líneas 22 a 26 del programa asignamos valores a cada uno de los campos de maestro. El primero es el campo calificación y es manejado como las otras estructuras que hemos estudiado porque no forma parte de la estructura anidada. Enseguida deseamos asignar un valor a edad el cual es parte de la estructura anidada. Para acceder a éste campo empezamos con el nombre de la variable maestro al cual le concatenamos el nombre del grupo descripción, y entonces debemos definir en cuál campo de la estructura anidada estamos interesados por lo que concatenamos el nombre de la variable edad. El estado de los maestros se manejan de la misma manera que su edad pero los últimos dos campos son cadenas asignadas utilizando la función strcpy ( ). Observe que los nombres de las variables en la función strcpy ( ) se consideran como una unidad aunque estén compuestas de varias partes.

Compile y ejecute el programa, probablemente obtenga un aviso sea de error ó advertencia respecto a un desbordamiento de memoria.

Lo que esto significa es que el programa requiere más memoria que la asignada por el compilador por lo que es necesario incrementar el tamaño de stacks, el método para hacer esto varía de un
compilador a otro.

\subsection{Manejo de estructuras con apuntadores}

Cuando se manejan estructuras como apuntadores el acceso a los campos es a través de una flecha. Por ejemplo si definimos una estructura como

\begin{verbatim}
struct per {
    char *nombre;
    char *domicilio;
    int edad;
    char sexo;
};
\end{verbatim}

\noindent
y defininos

\begin{verbatim}
struct per * a
\end{verbatim}

\noindent 
cada uno de los campo se accesa como  a->nombre, a->domicilio, a->edad y a->sexo.

En general es mucho mas robusto el manejo de las estructuras para generar arreglos. El siguiente es un ejemplo de como se debe hacer este manejo.

\begin{verbatim}
/* 
 * File:   persona.c
 * Author: felix
 *
 * Created on 23 de noviembre de 2011, 11:59
 */

#include <stdio.h>
#include <stdlib.h>

/*
 * Ejemplo de manejo de estructuras.
 * Se introduce los datos refetentes a personas.
 */

typedef struct per * persona;

struct per {
    char *nombre;
    char *domicilio;
    int edad;
    char sexo;
};

int longitud(char *a) {
    int i;
    for(i=0; a[i]!=0; i++);
    return i;
}

persona nueva(char *n, char *d, int e, char s) {
    persona aux;
    int i, nc;
    
    aux = (persona) calloc(1, sizeof(struct per));
    
    nc = longitud(n);
    aux->nombre = (char *) calloc(nc, sizeof(char));
    for(i=0; i<nc; i++)
        aux->nombre[i] = n[i];
    
    nc = longitud(d);
    aux->domicilio = (char *) calloc(nc, sizeof(char));
    for(i=0; i<nc; i++)
        aux->domicilio[i] = d[i];
    
    aux->edad = e;
    aux->sexo = s;
    
    return aux;
}


void imprime(persona a) {
    printf("Nombre    = %s\n", a->nombre);
    printf("Domicilio = %s\n", a->domicilio);
    printf("Edad      = %d\n", a->edad);
    printf("sexo      = %c\n", a->sexo);
}

int main(int argc, char** argv) {
    persona a;
    persona *b;
    int i;
    a = nueva("Juan", "El retajo", 10, 'h');
    imprime(a);
    
    b = (persona *) calloc(3, sizeof(persona));
    b[0] = nueva("Carlos", "CU", 20, 'h');
    b[1] = nueva("Ana", "cerca de CU", 21, 'm');
    b[2] = nueva("Luis", "no se ", 40, 'h');
    
    for(i=0; i<3; i++)
        imprime(b[i]);
    
    return (EXIT_SUCCESS);
}

\end{verbatim}

\subsection{Manejo de Fracciones}
El siguiente es un ejemplo de manejo de fracciones utilizando estructuras de datos. El código tiene implementado funciones para suma, resta, multiplicación y división de fracciones, adicionalmente tiene el algoritmo de Euclides para simplificar fracciones y una función para imprimir fracciones

\begin{verbatim}
#include <stdio.h>
#include <stdlib.h>

typedef struct razon * fraccion;

int EuclidesMCD(int a, int b);
int EuclidesMCM(int a, int b);
fraccion nueva(int n, int d);
void imprime(fraccion a);
fraccion suma(fraccion a, fraccion b);
fraccion resta(fraccion a, fraccion b);

struct razon {
   int numerador;
   int denominador;
};

int EuclidesMCD(int a, int b){

    int aux;
    int mayor = a > b ? a : b;
    int menor = a < b ? a : b;
    
    do{
        aux = menor;
        menor = mayor % menor;
        mayor = aux;  
    } while(menor!=0);
    return mayor;
}

int EuclidesMCM(int a, int b) {
    return(a/EuclidesMCD(a,b))*b;
}

fraccion nueva(int n, int d) {
   fraccion aux = (fraccion) calloc(1, sizeof(struct razon));
   int x;
   x = EuclidesMCD(n, d); 
   aux -> numerador = n/x;
   aux -> denominador = d/x;
   return aux;
}

void imprime(fraccion a) {
   printf("%d/%d \n", a->numerador, a->denominador);
}

fraccion suma(fraccion a, fraccion b) {
   fraccion aux;

   int num, den;
   den = a->denominador * b->denominador;
   num = a->numerador * b->denominador + a->denominador * b->numerador;

   aux = nueva(num, den);
   
   return aux;
}

fraccion resta(fraccion a, fraccion b) {
   fraccion aux;

   int num, den;
   den = a->denominador * b->denominador;
   num = a->numerador * b->denominador - a->denominador * b->numerador;

   aux = nueva(num, den);
   
   return aux;
}

fraccion multiplicacion(fraccion a, fraccion b){

   return nueva(a->numerador*b->numerador,  a->denominador*b->denominador);
}

fraccion division(fraccion a, fraccion b){

   return nueva(a->numerador*b->denominador,  a->denominador*b->numerador);
}

int main(){
   fraccion a = nueva(20, 30);
   fraccion b = nueva(4, 20);
   fraccion c;

   imprime(a);
   imprime(b);
   c = suma(a, b);
   imprime(c);
   c = resta(a, b);
   imprime(c);
   c = multiplicacion(a, b);
   imprime(c);
   c = division(a, b);
   imprime(c);
}
\end{verbatim}

\subsection{Estructuras a nivel de bits}

\begin{verbatim}
/* 
 * File:   cartas.c
 * Author: felix
 *
 * Created on 1 de diciembre de 2011, 17:59
 */

#include <stdio.h>
#include <stdlib.h>

/*
 * 
 */

struct cartaBit {                                  
   unsigned cara : 4;  /* 4 bits; 0-15 */            
   unsigned palo : 2;  /* 2 bits; 0-3  */          
   unsigned color : 1; /* 1 bit; 0-1   */           
}; /* fin de la estructura cartaBit    */                       
 
typedef struct cartaBit Carta; /* nuevo nombre de tipo para la estructura cartaBit */ 
void llenaMazo( Carta * const wMazo );      /* prototipo */
void repartir( const Carta * const wMazo ); /* prototipo */
 
int main(){ 
   Carta mazo[ 52 ]; /* crea el arreglo de Cartas */
 
   llenaMazo( mazo );
   repartir( mazo ); 
   return 0; /* indica terminacion exitosa */
 
}

/* fin de main */
/* inicializa Carta */

void llenaMazo( Carta * const wMazo )
{ 
   int i; /* contador */
    /* ciclo a traves de wMazo */
   for ( i = 0; i <= 51; i++ ) { 
      wMazo[ i ].cara = i % 13; 
      wMazo[ i ].palo = i / 13; 
      wMazo[ i ].color = i / 26;   } /* fin de for */
 
} /* fin de la funcion llenaMazo */
 
/* muestra las barajas con formatoc de dos columnas; el subindice de las   
 * barajas de 0 a 25 es k1 (columna 1); el subindice de las barajas de 26 
 * a 51 es k2 (columna 2) */

void repartir( const Carta * const wMazo )
{ 
   int k1; /* subindice 0-25 */
   int k2; /* subindice 26-51 */ 
   /* ciclo a traves de wMazo */
   for ( k1 = 0, k2 = k1 + 26; k1 <= 25; k1++, k2++ ) { 
      printf( "Carta:%3d  Palo:%2d  Color:%2d   \n",
         wMazo[ k1 ].cara, wMazo[ k1 ].palo, wMazo[ k1 ].color );      
      printf( "Carta:%3d  Palo:%2d  Color:%2d \n",
         wMazo[ k2 ].cara, wMazo[ k2 ].palo, wMazo[ k2 ].color );
   } /* fin de for */
 
} /* fin de la funcion repartir */
\end{verbatim}

\section {Uniones en C}

Uniones. Las uniones son similares a las estructuras, con la diferencia de que en las uniones se almacenan en los campos solapándose unos con otros en la misma disposición; al contrario que en las estructuras, al contrario que en las estructuras, donde los campos se almacenan unos a continuación de otros. En esencia, las uniones sirven para ahorrar espacio en memoria. Para Almacenar los miembros de una unión, se requiere una zona de memoria igual a la que ocupa el miembro mas largo de la unión. Todos los miembros son almacenados en el mismo espacio de memoria y comienzan en la misma dirección. El valor almacenado es sobre escrito cada vez que se asigna un valor al mismo miembro o a un miembro diferente, aquí radica la diferencia con las estructuras.


La Declaración de Uniones es similar a la de las estructuras:

\begin{verbatim}
union tipo_union {
 declaracion_de_miembros;
 } ;

 tipo_union
\end{verbatim}

Después de definir un tipo union, se puede declarar una o mas variables de ese tipo de la siguiente forma:

\begin{verbatim}
union tipo_union [variables];
\end{verbatim}


Una declaración union define un tipo. La llave derecha que termina la lista de miembros puede ser seguida por una lista de variables de la siguiente manera:

\begin{verbatim}
union tipo_union{ ... } variable;
\end{verbatim}

Ejemplo

\begin{verbatim}
union datos {
  char a;
  int b;
  float c
};

union datos p;
\end{verbatim}

Dicho de una forma simple, una unión le permite manejar los mismos datos con diferentes tipos, ó utilizar el mismo dato con diferente nombre, a continuación le presento un ejemplo:

\begin{verbatim}
// union01.c

/**
 * Title: Manejo de uniones en C
 * Description: Crea una union de datos
 * desde el teclado
 * Copyright: Copyright (c) 2005
 * Company: UMSNH
 * author Dr. Felix Calderon Solorio
 * version 1.0
 */

#include <stdio.h>

union
{
	int valor;

	struct 
	{
		char primero;
		char segundo;
	} mitad;
} numero;


int main()
{
	long indice = 34000L;

	numero.valor = indice;

	printf("%4x %2x %2x\n", numero.valor, numero.mitad.primero, numero.mitad.segundo);

	return 1;

}
\end{verbatim}

La ejecución muestra los siguientes resultados.

\begin{verbatim}
    84d0 ffffffd0 ffffff84
\end{verbatim}


ver \cite{DeitelC}

En éste ejemplo tenemos dos elementos en la unión, la primera parte es el entero llamado valor el cual es almacenado en algún lugar de la memoria de la computadora como una variable de dos bytes. El segundo elemento está compuesto de dos variables de tipo char llamadas primero y segundo. Estas dos variables son almacenadas en la misma ubicación de almacenamiento que valor porque esto es precisamente lo que una unión hace, le permite almacenar diferentes tipos de datos en la misma ubicación física. En éste caso Usted puede poner un valor de tipo entero en valor y después recobrarlo en dos partes utilizando primero y segundo, ésta técnica es utilizada a menudo para empaquetar bytes cuando, por ejemplo, combine bytes para utilizarlos en los registros del microprocesador. La unión no es utilizada frecuentemente y casi nunca por programadores principiantes, en este momento no necesita profundizar en el empleo de la unión así que no dedique mucho tiempo a su estudio, sin embargo no tome a la ligera el concepto de la unión, podría utilizarlo a menudo.


El siguiente es un ejemplo donde de manera indistinta una variable puede ser declarada como entero o doble. Esto no debe crear confusión ya que esto permite tener datos de tipo genérico donde con un nombre de variable lo vemos de una manera y con otra variable de otra forma.

\begin{verbatim}
/* 
 * File:   ejemplo_union.c
 * Author: felix
 *
 * Created on 1 de diciembre de 2011, 20:04
 */

#include <stdio.h>
#include <stdlib.h>

/* definicion de la union numero */

union numero {
   int x;
   double y;
}; /* fin de la union numero */
 
int main()
{   union numero valor; /* define la variable de union */
 
   valor.x = 100; /* coloca un entero dentro de la union */
   printf( "%s\n%s\n%s%d\n%s%f\n",
      "Coloca un valor en el miembro entero",
       "e imprime ambos miembros.",
      "int:   ", valor.x,
      "double: ", valor.y );
 
   valor.y = 100.0; /* coloca un double dentro de la misma union */
   printf( "%s\n%s\n%s%d\n%s%f\n",
      "Coloca un valor en el miembro flotante",
      "e imprime ambos miembros.",
      "int:   ", valor.x,
      "double: ", valor.y ); 
   return 0; /* indica terminacion exitosa */
 
} /* fin de main */
\end{verbatim}

\subsection{Ejemplo Tipo Genéricos}

El siguiente es un ejemplo donde manejamos un tipo de dato genérico. Este tipo tiene la posibilidad de ser al mismo tiempo un carácter, un entero, un flotante o una cadena de caracteres. Un identificador permite diferenciar cada tipo al momento de imprimir y todos los datos son la unión de los tipos mencionados.

\begin{verbatim}
/* 
 * File:   tipo_generico.c
 * Author: felix
 *
 * Created on 25 de junio de 2012, 10:17
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct gen * generico;

#define CHAR   0
#define INT    1
#define FLOAT  2
#define STRING 3


struct gen {
  int tipo;  // tipo de datos
  union {
    char cval;
    int ival;
    float fval;
    char *sval;
  } valor;  // valores
};

generico nueva_entero(int a){
  generico aux;
  aux  = (generico) calloc(1, sizeof(struct gen));
  aux->tipo = INT;
  aux->valor.ival = a; 
  return aux;
}

generico nueva_char(char a){
  generico aux;
  aux  = (generico) calloc(1, sizeof(struct gen));
  aux->tipo = CHAR;
  aux->valor.cval = a; 
  return aux;
}

generico nueva_flotante(float a){
  generico aux;
  aux  = (generico) calloc(1, sizeof(struct gen));
  aux->tipo = FLOAT;
  aux->valor.fval = a; 
  return aux;
}

generico nueva_cadena(char *a){
  generico aux;
  int N;
  aux  = (generico) calloc(1, sizeof(struct gen));
  aux->tipo = STRING;
  N = strlen(a);
  aux->valor.sval = (char *) calloc(N, sizeof(char)); 
  strcpy(aux->valor.sval,a );
  return aux;
}

void imprime(generico a){
  if(a->tipo == CHAR) printf("%c\n", a->valor.cval);
  else if(a->tipo == INT) printf("%d\n", a->valor.ival);
  else if(a->tipo == FLOAT) printf("%f\n", a->valor.fval);
  else if(a->tipo == STRING) printf("%s\n", a->valor.sval);
  else printf("Tipo no valido\n");
}

generico * vector(int N){
  return (generico *) calloc(N, sizeof(generico));
}

int main(int argc, char** argv) {
    generico *a;
    a = vector(3);
    int i;
    a[0] = nueva_entero(2);
    a[1] = nueva_char('c');
    a[2] = nueva_flotante(15.4);

    for(i=0; i<3; i++)
        imprime(a[i]);    
    
    generico b = nueva_cadena("Hola Mundo");
    
    imprime(b);
    return (EXIT_SUCCESS);
}
\end{verbatim}


