Programación en C/Estructuras y Uniones
En la creacion de soluciones para algunos problemas surge la necesidad de agrupar datos de diferente tipo o de manejar datos que serian muy dificil de describir en los tipos de datos primitivos, esta es la situacion en la que debemos aprovecharnos de las caracteristicas que hacen al lenguaje C especial, o sea el uso de estructuras, uniones y punteros.
Estructuras
[editar]Una estructura contiene varios datos. La forma de definir una estructura es haciendo uso de la palabra clave struct. Aqui hay ejemplo de la declaracion de una estructura:
struct mystruct
{
int int_member;
double double_member;
char string_member[25];
} variable;
"variable" es una instancia de "mystruct" y no es necesario ponerla aquí. Se podria omitir de la declaracion de "mystruct" y más tarde declararla usando:
struct mystruct variable;
También es una práctica muy común asignarle un alias o sinónimo al nombre de la estructura, para evitar el tener que poner "struct mystruct" cada vez. C nos permite la posibilidad de hacer esto usando la palabra clave typedef, lo que crea un alias a un tipo:
typedef struct
{
...
} Mystruct;
La estructura misma no tiene nombre (por la ausencia de nombre en la primera linea), pero tiene de alias "Mystruct". Entonces se puede usar así:
Mystruct variable;
Note que es una convencion, y una buena costumbre usar mayúscula en la primera letra de un sinónimo de tipo. De todos modos lo importante es darle algún identificador para poder hacer referencia a la estructura: podriamos tener una estructura de datos recursiva de algún tipo.
Ejemplo de una estructura :
/*
* estructura.c
*
* Julio César Brizuela <brizuelaalvarado@gmail.com> 2009
*
* para el wikilibro "Programación en C (fundamentos)"
* bajo licencia FDL, adaptado del Dominio Público
*
* Nombre Miembro Tipo
* Titulo char[30]
* Artista char[25]
* Precio float
* Total Canciones int
*/
#include <stdio.h>
#include <string.h>
/* definimos una estructura para cds */
struct cd
{
char titulo[30];
char artista[25];
float precio;
int canciones;
} Cd1 = { /* inicializamos la estructura Cd1 crea con sus valores
* usando las definiciones iniciales*/
"Canciones Bebe", /* titulo */
"Pinocho", /* artista */
12.50, /* precio */
16 /* total canciones */
};
int main(void)
{
struct cd Cd2; /* definimos una nueva estructura llamado cd2 */
/* asignamos valores a los tipos de datos del cd2 */
strcpy(Cd2.titulo, "New Age");
/* la forma de insertar valores a un
* tipo char en una estructura es usando strcpy
* de la libreria string.h
*/
strcpy(Cd2.artista, "Old Man");
Cd2.precio = 15.00;
Cd2.canciones = 12;
/* la forma de acceder a los valores de una estructura */
/* es usando el "." despues de la definicion del dato*/
printf("\n Cd 1");
printf("\n Titulo: %s ", Cd1.titulo);
printf("\n Artista: %s ", Cd1.artista);
printf("\n Total Canciones: %d ", Cd1.canciones);
printf("\n Precio Cd: %.2f ", Cd1.precio);
printf("\n");
printf("\n Cd 2");
printf("\n Titulo: %s ", Cd2.titulo);
printf("\n Artista: %s ", Cd2.artista);
printf("\n Total Canciones: %d ", Cd2.canciones);
printf("\n Precio Cd: %.2f ", Cd2.precio); /* el .2 que esta entre %f
* sirve para mostrar unicamente
* 2 decimales despues del punto*/
return 0;
}
Estructuras Anidadas
[editar]Una estructura puede estar dentro de otra estructura a esto se le conoce como anidamiento o estructuras anidadas. Ya que se trabajan con datos en estructuras si definimos un tipo de dato en una estructura y necesitamos definir ese dato dentro de otra estructura solamente se llama el dato de la estructura anterior.
Definamos una estructura en nuestro programa:
struct empleado /* creamos una estructura llamado empleado*/
{
char nombre_empleado[25];
char direccion[25];
char ciudad[20];
char provincia[20];
long int codigo_postal;
double salario;
}; /* las estructuras necesitan punto y coma (;) al final */
Y luego necesitamos una nueva estructura en nuestro programa:
struct cliente /* creamos una estructura llamada cliente */
{
char nombre_cliente[25];
char direccion[25];
char ciudad[20];
char provincia[20];
long int codigo_postal;
double saldo;
}; /* las estructuras necesitan punto y coma (;) al final */
Podemos ver que tenemos datos muy similares en nuestras estructuras, asi que podemos crear una sola estructura llamada infopersona con estos datos idénticos:
struct infopersona /* creamos la estructura que contiene datos parecidos */
{
char direccion[25];
char ciudad[20];
char provincia[20];
long int codigo_postal;
}; /* las estructuras necesitan punto y coma (;) al final */
Y crear las nuevas estructuras anteriores, anidando la estructura necesaria:
struct empleado /* se crea nuevamente la estructura */
{
char nombre_empleado[25];
/* creamos direcc_empleado con "struct" del tipo "estructura infopersona" */
struct infopersona direcc_empleado;
double salario;
}; /* las estructuras necesitan punto y coma (;) al final */
struct cliente /* se crea nuevamente la estructura */
{
char nombre_cliente[25];
/* creamos direcc_cliente con "struct" del tipo "estructura infopersona" */
struct infopersona direcc_cliente;
double saldo;
}; /* las estructuras necesitan punto y coma (;) al final */
Y acá el ejemplo completo con estructuras anidadas:
/*
* estructura2.c
*
* Julio César Brizuela <brizuelaalvarado@gmail.com> 2009
*
* para el wikilibro "Programación en C (fundamentos)"
* bajo licencia FDL, adaptado del Dominio Público
*
* Nombre Miembro Tipo
*
* Titulo char[30]
* Artista char[25]
* Precio float
* Total Canciones int
*/
#include <stdio.h>
#include <string.h>
/* creamos nuestra estructura con datos similares */
struct infopersona
{
char direccion[25];
char ciudad[20];
char provincia[20];
long int codigo_postal;
}; /* las estructuras necesitan punto y coma (;) al final */
/* creamos nuestra estructura empleado */
struct empleado
{
char nombre_empleado[25];
/* agregamos la estructura infopersona
* con nombre direcc_empleado
*/
struct infopersona direcc_empleado;
double salario;
}; /* las estructuras necesitan punto y coma (;) al final */
/* creamos nuestra estructura cliente */
struct cliente
{
char nombre_cliente[25];
/* agregamos la estructura infopersona
* con nombre direcc_cliente
*/
struct infopersona direcc_cliente;
double saldo;
}; /* las estructuras necesitan punto y coma (;) al final */
int main(void)
{
/* creamos un nuevo cliente */
struct cliente MiCliente;
/*inicializamos un par de datos de Micliente */
strcpy(MiCliente.nombre_cliente,"Jose Antonio");
strcpy(MiCliente.direcc_cliente.direccion, "Altos del Cielo");
/* notese que se agrega direcc_cliente haciendo referencia
* a la estructura infopersona por el dato direccion
*/
/* imprimimos los datos */
printf("\n Cliente: ");
printf("\n Nombre: %s", MiCliente.nombre_cliente);
/* notese la forma de hacer referencia al dato */
printf("\n Direccion: %s", MiCliente.direcc_cliente.direccion);
/* creamos un nuevo empleado */
struct empleado MiEmpleado;
/*inicializamos un par de datos de MiEmplado */
strcpy(MiEmpleado.nombre_empleado,"Miguel Angel");
strcpy(MiEmpleado.direcc_empleado.ciudad,"Madrid");
/* para hacer referencia a ciudad de la estructura infopersona
* utilizamos direcc_empleado que es una estructura anidada
*/
/* imprimimos los datos */
printf("\n");
printf("\n Empleado: ");
printf("\n Nombre: %s", MiEmpleado.nombre_empleado);
/* notese la forma de hacer referencia al dato */
printf("\n Ciudad: %s", MiEmpleado.direcc_empleado.ciudad);
return 0;
}
Uniones
[editar]La definición de "unión" es similar a la de "estructura", La diferencia entre las dos es que en una estructura, los miembros ocupan diferentes áreas de la memoria, pero en una unión, los miembros ocupan la misma área de memoria. Entonces como ejemplo:
union {
int i;
double d;
} u;
El programador puede acceder a través de "u.i" o de "u.d", pero no de ambos al mismo tiempo. Como "u.i" y "u.d" ocupan la misma área de memoria, modificar uno modifica el valor del otro, algunas veces de maneras impredecibles.
El tamaño de una unión es el de su miembro de mayor tamaño.
Ejemplo de una unión:
/*
* uniones.c
*
* Julio César Brizuela <brizuelaalvarado@gmail.com> 2009
*
* para el wikilibro "Programación en C (fundamentos)"
* bajo licencia FDL, adaptado del Dominio Público
*/
#include <stdio.h>
#include <string.h>
/*Creamos una union*/
union frases
{
char mensajes[50];
char ayudas[50];
char lineas[50];
} palabra;
/*Creamos una estructura*/
struct comparte
{
char mensajes[50];
char ayudas[50];
char lineas[50];
}Sistema;
/*Nótese que la estructura y la union tienen los mismos tipos de datos*/
int main(int argc, char** argv)
{
/*Inicializamos*/
strcpy(palabra.mensajes, "Primer Mensaje");
/*Inicializamos*/
strcpy(palabra.ayudas, "Una Ayuda");
printf("\nFrases en Union: ");
/*Imprimimos mensajes de union*/
printf("\n1- %s", palabra.mensajes);
/*Imprimimos ayudas de union*/
printf("\n2- %s", palabra.ayudas);
/*Inicializamos*/
strcpy(Sistema.mensajes, "Primer Mensaje");
/*Inicializamos*/
strcpy(Sistema.ayudas, "Una Ayuda");
/* Podemos notar que aunque inicializamos los valores
* al imprimir se tiene el mismo valor para cada miembro
* de la estructura, esto se debe a que las uniones usan el
* mismo espacio de memoria para todos los elementos
* de la union, siendo del tamaño de su miembro de
* mayor tamaño, en este caso 50 bytes.
* Entonces los tres miembros creados dentro de la
* union comparten esos 50 bytes.
* Entonces el ultimo valor agregado a la union es
* el que se tiene.
*/
printf("\n\nFrases en Struct: ");
/*Imprimimos mensajes de struct*/
printf("\n1- %s", Sistema.mensajes);
/*Imprimimos ayudas de union*/
printf("\n2- %s", Sistema.ayudas);
/* En la estructura comparte, se reservan 150 bytes
* de memoria para los tres miembros, en este caso
* cada uno es independiente en memoria, asi pues se
* puede inicializar cada uno o usar como un campo
* independiente.
*/
return 0;
}
Enumeraciones
[editar]Una enumeracion (enum) es un tipo definido con constante de tipo entero. En la declaracion de un tipo enum creamos una lista de tipo de datos que se asocian con las constantes enteras 0, 1, 2, 3, 4, 5...
su forma de definirlas es la siguiente:
enum
{
enumerador1, enumerador2, … enumeradorn
};
enum Nombre
{
enumerador1, enumerador2, … enumeradorn
};
En este caso al ser declaradas enumerador1 toma el valor entero de 0, enumerador2 el valor de 1 y asi sucesivamente para cada una de las expresiones siguientes.
Al declarar la enum se puede asociar a los tipos de datos a valores constantes en vez de la asociacion que por defecto se realiza (0, 1, 2, …), se utiliza entonces este formato:
enum Nombre
{
enumerador1 = valor_constante1,
enumerador2 = valor_constante2,
...
enumeradorn = valor_constanten,
};
Un ejemplo de una enum:
enum Boolean
{
FALSE,
TRUE
};
Se definen dos constantes para las constantes true y false con valores iguales a 0 para False y 1 para True.
Ejemplo:
/*
* Enum.c
*
* Julio César Brizuela <brizuelaalvarado@gmail.com> 2009
*
* para el wikilibro "Programación en C (fundamentos)"
* bajo licencia FDL, adaptado del Dominio Público
*/
#include <stdio.h>
enum Boolean
{
FALSE, TRUE
};
/* Se define un enum para emular las constantes
* True y False con valores de 0 y 1.
* Notese que las enum no necesitan ; al final
* de cada tipo de dato.
*/
/* Definimos una funcion del tipo enum llamada numero*/
enum Boolean numero(char c);
int main(int argc, char** argv)
{
char caracter;
int Numeros = 0;
printf("\nIntroduce un texto. Para terminar: Enter. \n\t");
/* Tenemos un while que mientras no se presione Enter
* seguira leyendo un tipo de dato caracter
*/
while((caracter = getchar()) != '\n')
{
if (numero(caracter))
{
Numeros++;
}
}
printf("\nTotal de Numeros leidos: %d", Numeros);
return 0;
}
enum Boolean numero(char c)
{
switch(c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return TRUE;
/* Mientras el caracter valga de 0 a 9 retornara TRUE (1) */
default:
return FALSE;
/* Por default retornara FALSE (0) */
}
}
En la siguiente enum se declaran las variables inicializando la primera y las demas con los siguientes valores enteros:
/*
* Enum2.c
*
* Julio César Brizuela <brizuelaalvarado@gmail.com> 2009
*
* para el wikilibro "Programación en C (fundamentos)"
* bajo licencia FDL, adaptado del Dominio Público
*/
#include <stdio.h>
enum DiasSemanas
{
Domingo = 1,
Lunes,
Marte,
Miercoles,
Jueves,
Viernes,
Sabado
};
/* Podemos inicializar nuestra primer constante Domingo
* en 2, asi pues las demas los siguientes valores enteros.
*/
int main(int argc, char** argv)
{
enum DiasSemanas dia;
for (dia = Domingo; dia <= Sabado; dia++)
{
printf("%d ", dia); /* Salida: 1 2 3 4 5 6 7 */
}
return 0;
}
A los enumeradores se pueden asignar valores o expresiones constantes durante la declaracion:
enum Hexaedro
{
VERTICE = 8,
LADOS = 12,
CARAS = 6
};