DICIS-Universidad de Guanajuato josh_ram@hotmail.com
Estructuras, uniones y tipos de datos definidos por el usuario.
Estructuras.
Las estructuras ( struct ) son agrupaciones de una o ms variables de tipos posiblemente diferentes, agrupadas bajo un mismo nombre. Esto permite un manejo ms cmodo de la informacin cuando sta est relacionada. Las struct son estructuras de datos similares a los registros ( record ) de Pascal. La forma general de definicin es:
struct tipo_estructura { tipo miembro_1; tipo miembro_2; . tipo miembro_n; } Lista_variables_estructura;
donde tipo_estructura ( que ser el nombre de la estructura ) Lista_variables_estructura ( que es una lista de las variables que sern de este tipo de estructura ) pueden omitirse pero no ambos. Las estructuras ayudan a agrupar informacin relacionada como los datos de una cdula de identidad, las coordenadas de un punto, etc.
Lenguaje de Programacin: C Invierno 2012
DICIS-Universidad de Guanajuato josh_ram@hotmail.com Ejemplos de declaracin de estructuras
struct datos { char nombre[20]; char direccion[20]; long int NumCedula; char sexo; };
/* Veamos ahora como declaramos una variable de tipo struct datos. Aqu tenemos a a como una estructura de este tipo y b como un array de 5 estructuras de este tipo*/
struct datos a,b[5];
Las estructuras tambin pueden estar anidadas. Esto quiere decir que un elemento de una estructura puede ser a su vez otra estructura.
Veamos un ejemplo:
struct fecha { int dia; int mes; int anio; }; Lenguaje de Programacin: C Invierno 2012
DICIS-Universidad de Guanajuato josh_ram@hotmail.com
struct persona { char nombre[20]; struct fecha nacimiento; };
struct persona p;
Aqu vemos que la estructura persona contiene un elemento que es del tipo de estructura fecha.
OJO: Como vimos en la definicin, tambin pueden declararse las variables que sern de un tipo de estructura desde el momento de la declaracin haciendo algo como:
struct persona { char nombre[20]; struct fecha nacimiento; } p, q ; // Esto declara 'p' y 'q' de tipo struct persona"
Cmo se referencian estas variables?. Muy bien, los elementos individuales de una estructura se referencian utilizando el operador punto ( . ) entre el nombre de la variable de tipo estructura y el nombre del miembro de la estructura. A los elementos de una estructura se les denomina miembros.
Continuando con las estructuras de los ejemplos anteriores, se pueden tener las siguientes referencias a miembros:
a.nombre // Referencia la variable nombre de la estructura datos llamada a Lenguaje de Programacin: C Invierno 2012
DICIS-Universidad de Guanajuato josh_ram@hotmail.com a.direccin // Referencia la variable direccin de la estructura datos llamada a b[2].NumCedula // Referencia la variable NumCedula del segundo elemento del arreglo // de tipo struct datos llamado b p.nombre p.nacimiento.dia // Estos casos referencian un elemento de una struct fecha dentro p.nacimiento.mes // de la struct persona. Analcenlo.
Funciones y estructuras.
1 .- Paso por valor de miembros de una estructura a una funcin.
Se realiza como si fueran variables simples. Por ejemplo, para pasar por valor el miembro a.NumCedula:
void funcion f1(int x); /*declaracin de la funcin prototipo*/
f1(a.NumCedula); /* llamada a la funcin */
void f1(int x) { /* definicin de la funcin */ ... }
2.- Paso por direccin ( lo mismo que por referencia ) de miembros de una estructura a una funcin. Se realiza como si fueran variables simples. Por ejemplo, para pasar por referencia el miembro a.NumCedula: Lenguaje de Programacin: C Invierno 2012
DICIS-Universidad de Guanajuato josh_ram@hotmail.com
void funcion f1(int *) /*declaracin de la funcin prototipo*/
f1(&a.codigo); /* llamada a la funcin */
void f1(int *x) { /* definicin de la funcin */ }
Hay que tener en cuenta que si lo que se pasa a una funcin es un miembro de una estructura que sea un arreglo, ste siempre se pasa por direccin ( ya que el nombre del arreglo es la direccin del primer elemento del mismo ).
3.- Paso por valor de estructuras completas a funciones.
En el siguiente ejemplo, suma es una funcin que recibe dos estructuras pasadas por valor y a su vez devuelve una estructura.
struct vector { int x,y,z; };
struct vector (struct vector v1, struct vector v2); void main() { struct vector v1,v2,v3; Lenguaje de Programacin: C Invierno 2012
DICIS-Universidad de Guanajuato josh_ram@hotmail.com ... v3=suma(v1,v2); ... }
4.- Paso por referencia de estructuras completas a funciones.
Cuando las estructuras son muy grandes es ms eficiente pasarlas por direccin. En ese caso se utilizan punteros a estructuras para realizar la comunicacin. Para acceder a los miembros de la estructura debe utilizarse la combinacin de los operadores * y punto. Sin embargo el operador punto tiene ms precedencia que * siendo necesario el uso de parntesis para asegurar que se aplique primero * y despus punto. Tambin puede utilizarse el operador -> para acceder a los miembros de una estructura referenciada por un puntero y de hecho este es la forma ms usada en la actualidad.
#include <stdio.h>
struct pareja { int a,b; }; Lenguaje de Programacin: C Invierno 2012
DICIS-Universidad de Guanajuato josh_ram@hotmail.com
void f1(struct pareja *q);
void main() { struct pareja p = { 13, 17 } /* inicializacin de los miembros*/ f1(&p); printf("a:%d y b:%d\n", p.a, p.b); /* a: 14 y b:18 */ }
void f1(struct pareja *q) { q->a++; /* equivalente a (*q).a++ pero ms usado */ q->b++; return; // Este return no retorna nada ya que la funcin es void. // En este caso no era necesario su uso pero recuerden que return tambin // se usa para finalizar una funcin inmediatamente. }
En este ejemplo tambin se observ como se inicializan los elementos de una estructura: con {ele1, ele2,...,elen}; igual que en los arreglos. El primer elemento inicializa la primera variable de la estructura, el segundo elemento a la segunda variable y as sucesivamente. As, si usamos la estructura datos que mencionamos al principio, una forma de inicializarla sera algo como:
struct datos a = {Tony, Maracay, 8765432, 'M'};
COMENTARIO ADICIONAL: Existe una forma en C de acceder a los bits de una variable de forma independiente sin tener que hacer operaciones a nivel de stos. Esta forma de acceso est ligada al uso de estructuras. Si lo necesita, puede buscar ms informacin acerca de este tema o preguntarme. Lenguaje de Programacin: C Invierno 2012
DICIS-Universidad de Guanajuato josh_ram@hotmail.com Uniones
Las uniones son otro tipo de datos que pueden ser usados en C y aunque tienen una sintaxis similar a las estructuras se diferencian de stas en que sus miembros comparten almacenamiento. Esto quiere decir que una variable unin define a un conjunto de valores alternos que se almacenan en una porcin compartida de memoria. Es una versin C de los registros variantes de otros lenguajes como Pascal.
El compilador asigna una porcin de almacenamiento que pueda acomodar al ms grande de los miembros especificados. La notacin para acceder a un miembro de la unin es idntica a la que se emplea para acceder a un miembro de una estructura. Un ejemplo de unin es el siguiente:
union simple { char ch; int i; }; union simple a;
// podemos acceder a las variables de la unin haciendo: a.ch = a; ... a.i = 3;
Como ya comentamos, las uniones comparten el almacenamiento, o sea, que slo se reserva espacio en memoria como para almacenar la ms grande de las variables que en este caso es un int por lo que son dos bytes. Dentro de esos dos bytes se almacenarn las variables pero, como usted ya habr analizado, slo puede mantenerse el valor de una de ellas. O sea que en el ejemplo anterior, al usar a.i, a.ch se pierde. Veamos otro ejemplo:
Lenguaje de Programacin: C Invierno 2012
DICIS-Universidad de Guanajuato josh_ram@hotmail.com
union ejemplo { long int cedula; char nombre[10]; char Nacimiento[12]; };
Esta variable slo ocupar 12 bytes que es el mayor dato que puede contener y mantendr en cada momento slo a una de ellas.
OJO: Es muy importante que sepan que una unin slo puede ser inicializada con un valor del tipo de su primer miembro.
union ejemplo a={8765432};
Uso de sizeof para asegurar la portabilidad.
Al principio del curso, y tambin en la primera parte de punteros, comentamos el operador sizeof(). El uso de este operador es de gran importancia a la hora de calcular el tamao real de las variables, el cual puede variar de maquina en maquina. Por ejemplo, en MSDOS:
char c; sizeof(int); //Retorna 2, ya que int ocupa dos bytes sizeof(c); // retorna 1 ya que c es de tipo char y ocupa un byte Lenguaje de Programacin: C Invierno 2012
DICIS-Universidad de Guanajuato josh_ram@hotmail.com
mientras que en Linux, aunque los char son del mismo tamao, sizeof(int) retorna 4.
En todo caso, hice nuevamente referencia al operador sizeof debido a que uno de sus mayores usos es en el clculo de tamaos de variables definidas por el usuario tales como estructuras y uniones. Supongamos que se necesita guardar datos en un arreglo que ser creado dinmicamente con malloc y que este arreglo contendr, por ejemplo, 27 elementos de un tipo de estructura que ha sido creada por nosotros. Supongamos tambin que la estructura es la siguiente:
struct tamao { char ch; int i; long int li; float f; double d; long double ld; char cad[10]; int mat[10][15]; } me;
Para poder reservar memoria con malloc de forma directa deberamos primero calcular cuantos bytes ocupa esta estructura que en MSDOS sera: ch = 1, i = 2, li = 4, f = 4, d = 8, ld = 10, cad = 10 y mat = 2*10*15 = 300. Sumado todo da 339 bytes por estructura que luego multiplicamos por 27 para obtener el espacio total requerido = 9153 bytes. As, haramos:
struct tamao *pe; pe = (struct tamao *)malloc(9153);
Lenguaje de Programacin: C Invierno 2012
DICIS-Universidad de Guanajuato josh_ram@hotmail.com y tendramos que hacer los distintos clculos para las diferentes plataformas. Usando sizeof slo haramos:
pe = (struct tamao *)malloc(27*sizeof(me));
Lenguaje de Programacin: C Invierno 2012
DICIS-Universidad de Guanajuato josh_ram@hotmail.com Tipos de datos definidos por el usuario.
C soporta la creacin de nuevos nombres de tipos de datos. Esto se realiza utilizando la palabra reservada typedef:
typedef tipo nombre
Ejemplos:
Con tipos simples:
typedef int ENTERO typedef float REAL
ENTERO a,b; // Define a y b como de tipo ENTERO, o sea, int. REAL c;
Con tipos estructurados:
typedef struct{ int dia; int mes; int anio; } FECHA;
Lenguaje de Programacin: C Invierno 2012
DICIS-Universidad de Guanajuato josh_ram@hotmail.com FECHA a;
incluso si la estructura ya est creada:
struct test { int i; char ch; char cad[10]; }
podemos usar:
typedef struct test MiNuevoTipo; ... MiNuevoTipo a;
Lenguaje de Programacin: C Invierno 2012
DICIS-Universidad de Guanajuato josh_ram@hotmail.com Enumeraciones ( enum )
Una enumeracin, es un conjunto de constantes enteras con nombre, que especifica todos los valores vlidos que una variable de este tipo puede tener. Estos valores son listados explcitamente por el programador. Las constantes representan los valores que pueden ser asignados a las variables declaradas del tipo del enum. Su forma de declaracin es:
enum nombre { val1,val2,...,valn }; donde valn son identificadores de constantes.
En el primer caso, val1 es un identificador que tendr un valor de cero, val2 un valor de 1 y as sucesivamente pero se pueden asignar otros valores indicndolo en la enumeracin:
enum nombre {val1=0, val2=10, val3=13,... };
Puede suceder incluso que ms de una constante de enumeracin tenga el mismo valor entero.
dinero = medio; if (dinero == medio ) printf(Es un medio\n); La clave para entender las enumeraciones es que cada uno de los smbolos corresponde a un valor entero. De esta forma, puede usarse en cualquier expresin entera. Por ejemplo:
printf(El valor de un medio es %i, medio);
Perfectamente vlido.
Como ya comentamos, a menos que se inicialice de otro modo, el valor del primer smbolo ser cero, el del segundo 1 y as sucesivamente. Por lo tanto en el ejemplo anterior:
printf(%i %i, medio, bolivar);
imprimir 0 2 en la pantalla.
Tambin dijimos que se pueden especificar valores en la inicializacin:
enum moneda { medio=25, real=50, bolivar=100 }; Lenguaje de Programacin: C Invierno 2012
DICIS-Universidad de Guanajuato josh_ram@hotmail.com
, por ejemplo, en:
enum color { amarillo, azul=10, verde, rojo, negro=100 };
tendremos que, segn la inicializacin: amarillo=0, azul=10, verde=11, rojo=12 y negro =100.
No se puede escribir ms que el valor entero de la variable enum lo que quiere decir que no se puede escribir su nombre. Recuerde, NO son cadenas. Son slo nombres de enteros.
dinero = real; printf(%s, dinero); // Esto est mal.
Lo que si se puede hacer es pedir un entero y asignrselo a una enumeracin.
Los tipos enumerados NO aportan capacidades nuevas al lenguaje, pero aumentan la claridad de algunos programas. Veamos un caso tpico de su uso ( en conjunto con arreglos de cadenas ).
char *nombreColores[]={ negro", "azul", "verde", "cyan", Lenguaje de Programacin: C Invierno 2012
DICIS-Universidad de Guanajuato josh_ram@hotmail.com "rojo", "magenta", "marron", amarillo, blanco };
/* Aunque por supuesto en este caso el ndice del amarillo y blanco no corresponden con los valores en enum lo cual presentar errores en el siguiente cdigo. Sern comentados */
printf("Introduzca un numero de color: "); scanf("%i",&i); color = i; printf("El numero del color es %i\n",color); switch(color) { case negro: printf("negro = %s\n",nombreColores[negro]); printf("%s\n",nombreColores[color]); // Anlogo a nombreColores[negro] break; case azul: printf("azul = %s\n",nombreColores[azul]); printf("%s\n",nombreColores[color]); break; case verde: printf("verde = %s\n",nombreColores[verde]); printf("%s\n",nombreColores[color]); break; case cyan: printf("cyan = %s\n",nombreColores[cyan]); Lenguaje de Programacin: C Invierno 2012
DICIS-Universidad de Guanajuato josh_ram@hotmail.com printf("%s\n",nombreColores[color]); break; case rojo: printf("rojo = %s\n",nombreColores[rojo]); printf("%s\n",nombreColores[color]); break; case magenta: printf("magenta = %s\n",nombreColores[magenta]); printf("%s\n",nombreColores[color]); break; case marron: printf("marron = %s\n",nombreColores[marron]); printf("%s\n",nombreColores[color]); break;
/* Para los siguientes casos, los valores de color no estn definidos dentro de los permitidos por el arreglo de cadenas ( aunque si por el enum ). Por tal hecho, al tratar de imprimir la cadena del arreglo correspondiente, imprimir lo que encuentre en ese punto de memoria hasta conseguir el caracter nulo */
case amarillo: printf("amarillo = %s\n",nombreColores[amarillo]); printf("%s\n",nombreColores[color]); break; case blanco: printf("blanco = %s\n",nombreColores[blanco]); printf("%s\n",nombreColores[color]); break; default: printf("Ese color no lo conozco\n"); }