En este capítulo se revisa la forma como pueden ser creados y usados en C tipos de datos más complejos y estructuras.
En C una estructura es una colección de variables que se referencian bajo el mismo nombre. Una estructura proporciona un medio conveniente para mantener junta información que se relaciona. Una definición de estructura forma una plantilla que se puede usar para crear variables de estructura. Las variables que forman la estructura son llamados elementos estructurados.
Generalmente, todos los elementos en la estructura están relacionados
lógicamente unos con otros. Por ejemplo, se puede representar una lista
de nombres de correo en una estructura. Mediante la palabra clave struct
se le indica al compilador que defina una plantilla de estructura.
struct direc { char nombre[30]; char calle[40]; char ciudad[20]; char estado[3]; unsigned int codigo; };
Con el trozo de código anterior no ha sido declarada ninguna variable, tan sólo se ha definido el formato. Para declarar una variable, se hará como sigue:
struct direc info_direc;
Se pueden declarar una o más variables cuando se define una estructura entre )
y ;
. Por ejemplo:
struct direc { char nombre[30]; char calle[40]; char ciudad[20]; char estado[3]; unsigned int codigo; } info_direc, binfo, cinfo;
observar que direc
es una etiqueta para la estructura que sirve
como una forma breve para futuras declaraciones. Como en este última
declaración se indican las variables con esta estructura, se puede omitir el
nombre de la estructura tipo.
Las estructuras pueden ser también preinicializadas en la declaración:
struct direc info_direc={"Vicente Fernandez","Fantasia 2000","Dorado","MMX",12345};
Para referenciar o accesar un miembro (o campo) de una estructura, C proporciona el operador punto .
, por ejemplo, para asignar a info_direc
otro código, lo hacemos como:
info_direc.codigo=54321;
Se señalo previamente (sección 2.4.1) que typedef
se puede usar para definir nuevos nombres de datos explicítamente,
usando algunos de los tipos de datos de C, donde su formato es:
Se puede usar typedef
para crear nombres para tipos más complejos, como una estructura, por ejemplo:
typedef struct direc { char nombre[30]; char calle[40]; char ciudad[20]; char estado[3]; unsigned int codigo; } sdirec; sdirec info_direc={"Vicente Fernandez","Fantasia 2000","Dorado","MMX",12345};
en este casodirec
sirve como una etiqueta a la estructura y es opcional, ya que ha sido definido un nuevo tipo de dato, por lo que la etiqueta no tiene mucho uso, en dondesdirec
es el nuevo tipo de datos einfo_direc
es una variable del tiposdirec
, la cual es una estructura.
Con C también se pueden tener arreglos de estructuras:
typedef struct direc { char nombre[30]; char calle[40]; char ciudad[20]; char estado[3]; unsigned int codigo; } info_direc; info_direc artistas[1000];
por lo anterior,artistas
tiene 1000 elementos del tipoinfo_direc
. Lo anterior podría ser accesado de la siguiente forma:
artistas[50].codigo=22222;
Una union es una variable la cual podría guardar (en momentos
diferentes) objetos de diferentes tamaños y tipos. C emplea la
sentencia union
para crear uniones por ejemplo:
union numero { short shortnumero; long longnumero; double floatnumero; } unumero;
con lo anterior se define una unión llamadanumero
y una instancia de esta llamadaunumero
.numero
es la etiqueta de la unión y tiene el mismo comportamiento que la etiqueta en la estructura.
Los miembros pueden ser accesados de la siguiente forma:
printf("%ld\n",unumero.longnumero);
con la llamada a la función se muestra el valor de longnumero
.
Cuando el compilador de C esta reservando memoria para las uniones, siempre creará una variable lo suficientemente grande para que quepa el tipo de variable más largo de la unión.
Con la finalidad de que el programa pueda llevar el registro del tipo de la variable unión usada en un momento dado, es común tener una estructura (con una unión anidada) y una variable que indica el tipo de unión.
Se muestra un ejemplo de lo anterior:
typedef struct { int maxpasajeros; } jet; typedef struct { int capac_elev; } helicoptero; typedef struct { int maxcarga; } avioncarga; typedef union { jet jetu; helicoptero helicopterou; avioncarga avioncargau; } transporteaereo; typedef struct { int tipo; int velocidad; transporteaereo descripcion; } un_transporteaereo
en el ejemplo se define una unión base de transporte aéreo el cual puede ser un jet, un helicóptero o un avion de carga.
En la estructura un_transporeaereo
hay un miembro para el tipo, que
indica cual es la estructura manejada en ése momento.
C es uno de los pocos lenguajes que permiten la conversión de tipos, esto
es, forzar una variable de un tipo a ser de otro tipo. Lo anterior se presenta
cuando variables de un tipo se mezclan con las de otro tipo. Para llevar a
cabo lo anterior se usa el operador de conversión (cast) ()
. Por
ejemplo:
int numeroentero; float numeroflotante = 9.87; numeroentero = (int) numeroflotante;
con lo cual se asigna 9 a la variable numeroentero
y la fracción es
desechada.
El siguiente código:
int numeroentero = 10; float numeroflotante; numeroflotante = (float) numeroentero;
asigna10.0
anumeroflotante
. Como se observa C convierte el valor del lado derecho de la asignación al tipo del lado izquierdo.
La conversión de tipos puede ser también usada con cualquier tipo simple
de datos incluyendo char
, por lo tanto:
int numeroentero; char letra = 'A'; numeroentero = (int) letra;
asigna 65 (que es el código ASCII de 'A') a numeroentero
.
Algunas conversiones de tipos son hechas automáticamente - esto es principalmente por la característica de compatibilidad de tipos.
Una buena regla es la siguiente: En caso de duda, conversión de tipos.
Otro uso es asegurarse que la división de números se comporta como se requiere, ya que si se tienen dos enteros la forma de forzar el resultado a un número flotante es:
numeroflotante = (float) numerent / (float) denoment;
con lo que se asegura que la división devolverá un número flotante.
Una enumeración es un conjunto de constantes enteras con nombre y especifica todos los valores legales que puede tener una variable del tipo enum.
La forma como se define una enumeración es de forma parecida a como se hace con las estructuras, usando la palabra clave enum
para el comienzo de un tipo de enumeración. Su formato es:
enum nombre_enum { lista_de_enumeración } lista_de_variables;
Es opcional nombre_enum y lista_de_variables. La primera se usa para declarar las variables de su tipo. El siguiente fragmento define una enumeración llamada disco
que declara almacenamiento
para ser de ese tipo.
enum almacenamiento { diskette, dd, cd, dvd, cinta }; enum almacenamiento disco;
Con la siguiente definición y declaración son válidas las siguientes sentencias:
disco = cd; if ( disco == diskette ) printf("Es de 1440 Kb\n");
Se inicializa el primer símbolo de enumeración a cero, el valor del segundo símbolo a 1 y así sucesivamente, a menos que se inicialice de otra manera. Por tanto,
printf("%d %d\n", dd, cinta)
muestra 1 4
en la pantalla.
Se puede especificar el valor de uno o más símbolos usando un inicializador. Para hacerlo, poner un signo igual y un valor entero después del símbolo.
Por ejemplo, lo siguiente asigna el valor 250 a cd
enum disco { diskette, duro, cd=250, dvd, cinta };
Por lo tanto los valores de los símbolos son los siguientes:
diskette | 0 |
---|---|
duro | 1 |
cd | 250 |
dvd | 251 |
cinta | 252 |
C soporta cuatro especificadores de clase de almacenamiento. Son
auto |
---|
extern |
static |
register |
Estos especifcadores le dicen al compilador como almacenar la variable que sigue. El especificador de almacenamiento precede a la declaración de variable que tiene el formato general:
especif_almac especif_tipo lista_variables;
Se usa el especificador auto
para declarar variables locales. Sin embargo, raramente se usa porque las variables locales son auto por defecto.
Las variables static son variables permanentes en su propia función o archivo. Se diferencian de las variables globales porque son desconocidas fuera de sus funciones o archivo, pero mantienen sus valores entre llamadas. Esta característica las hace útiles cuando se escriben funciones generales y bibliotecas de funciones.
Variables static locales. Una variable estática local es una variable local que retienen su valor entre llamadas de función, ya que C les crea un almacenamiento permanente. Si lo anterior no se pudiera hacer, entonces se tendrían que usar variables globales -que abriría la puerta a posibles efectos laterales-. Un ejemplo de una función que requeriría tales variables es un generador de series de números que produce un número nuevo basado en el último.
A continuación se muestra un ejemplo en donde se analiza el comportamiento de una variable auto y una variable static
void stat(); /* Prototipo de la funcion */ main() { int i; for (i=0; i<5; ++i) stat(); } void stat() { auto int a_var = 0; static int s_var = 0; printf("auto = %d, static = %d \n", a_var, s_var); ++a_var; ++s_var; }
La salida del código anterior es:
auto = 0, static = 0 auto = 0, static = 1 auto = 0, static = 2 auto = 0, static = 3 auto = 0, static = 4
Como se puede observar la variable a_var
es creada cada vez que se llama a la función. La variable s_var
es creada en la primera llamada y después recuerda su valor, es decir, no se destruye cuando termina la función.
enumerate
para mostrar el
nombre de un mes, su predecesor y su sucesor. El mes se ingresará desde el
teclado dando un número entre 1 y 12.