Está en la página 1de 18

Lenguaje de Programacin: C Invierno 2012

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);
...
}

struct vector suma(struct vector v1, struct vector v2) {
v1.x+=v2.x;
v1.y+=v2.y;
v1.z+=v2.z;
return (v1);
}


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.



enum etiqueta { lista_de_enumeraciones } lista_de_variables;

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.

enum color{rojo=-1, azul, amarillo, verde, negro=0};

Las variables de enumeracin pueden utilizarse como enteros; asignarles valores, compararlas, etc.

Vemos un ejemplo:

Lenguaje de Programacin: C Invierno 2012


DICIS-Universidad de Guanajuato josh_ram@hotmail.com
enum moneda { medio, real, bolivar };
...
enum moneda dinero;

Entonces podramos decir:

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 ).

enum colores {negro, azul, verde, cyan, rojo, magenta, marron, amarillo=14, blanco };

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");
}