Documente Academic
Documente Profesional
Documente Cultură
Declaracin typedef
La declaracin typedef de C nos permite establecer un alias para un tipo de dato
predefinido o previamente definido por el usuario. Una vez declarado, ese alias puede
utilizarse en declaraciones de objetos (variables y parmetros), casts, tipos de funciones,
etc. La sintaxis de la declaracin typedef es la siguiente:
typedef tipo alias;
Una declaracin typedef empieza con la palabra reservada typedef. tipo es el tipo de
datos al que le estamos estableciendo el sinnimo dado por alias. Por ejemplo:
typedef unsigned char uchar;
typedef unsigned long ulong;
typedef int contador;
como una declaracin de una variable, en la que alias ocupa la parte en la que ira el
nombre de la variable a declarar. Por ejemplo:
ITSON
236
Aqu hacemos que cadena sea un alias de char *, esto es, de apuntador a char y
mensaje sea un alias de char ... [80], esto es, una cadena de 80 caracteres. Ms
adelante veremos que la declaracin typedef puede emplearse con tipos declarados por
el usuario.
Hay varias razones para desear establecer aliases para los tipos de datos:
que
unsigned char x, y;
unsigned long z, w;
Enumeraciones
Hay ocasiones en que usamos variables enteras para representar valores que no son
necesariamente numricos. Por ejemplo para almacenar los valores Booleanos de falso y
verdadero, el lenguaje C, emplea una variable entera donde 0 representa el valor de falso
y 1 representa el valor de verdadero. Como un segundo ejemplo, para representar los
meses del ao podemos emplear una variable entera codificando cada mes con un
nmero entero: 1 para Enero, 2 para Febrero, .. , 12 para Diciembre. Los inconvenientes
de codificar valores no numricos como nmeros son: tener que recordar la codificacin
empleada y el hecho de que en el programa no resulta tan obvio el significado de dichos
nmeros. En estos casos C nos permite definir tipos enumerados. Un tipo enumerado
nos permite asignarles un identificador a cada valor de un subconjunto finito del tipo entero
y de declarar variables que tomen valores de ese subconjunto. El conjunto de valores se
conoce como constantes de enumeracin.
ITSON
Captulo 12
237
enum es una palabra reservada con que empieza la definicin de un tipo enumerado.
rtulo es un identificador que sirve para referenciar al tipo que se est definiendo en las
declaraciones de objetos, casts y tipos de funcin. La referencia al tipo enumerado que se
est creando es enum rtulo y no slo rtulo.
nomCte1 = cte1, nomCte2 = cte2... es una lista de identificadores y las
constantes enteras que representan. Los identificadores de las constantes de
enumeracin deben ser diferentes entre s y diferentes de los nombres de las variables en
su mismo mbito. Si se omite el valor para el primer identificador ste toma el valor de 0.
Si se omite el valor de alguno de los otros identificadores ste toma el valor del
identificador anterior ms uno. Los valores asociados a cada identificador no tienen que
ser diferentes entre s ni aparecer en algn orden.
Al mismo tiempo que definimos un tipo enumerado podemos declarar variables de ese
tipo. nomVar1, nomVar2 ... son los identificadores de esas variables. Por ejemplo:
enum boolean {
FALSE, TRUE
};
enum mes {
ENE, FEB, MAR, ABR, MAY, JUN, JUL, AGO, SEP, OCT, NOV, DIC
} mes;
enum {
DOM, LUN, MAR, MIE = 1, JUE, VIE = 1, SAB = 0
} dia;
En este caso estamos definiendo tres tipos enumerados: enum boolean, enum mes y un
tercero que no tiene rtulo (cuando en una definicin de un tipo omitimos el rtulo, se dice
que es una definicin annima). La definicin del tipo enum boolean le asigna al
subconjunto de los enteros {0, 1} los identificadores FALSE y TRUE, respectivamente,
mientras que la definicin del tipo enum mes le asigna al subconjunto de los enteros {0, 1,
..., 11} los identificadores ENE, FEB, ..., DIC. En la segunda definicin, tambin se
est declarando la variable mes como del tipo enum mes. En la tercera definicin, se
establece que la variable eDia puede tomar los valores: DOM, LUN, MAR, MIE, JUE,
ITSON
238
VIE, SAB. Los identificadores DOM y SAB tienen el valor de 0, LUN, Mie y VIE tienen el
valor de 1 y MAR y JUE el valor de 2.
Podemos establecer un alias para un tipo enumerado. Por ejemplo:
typedef enum boolean eBoolean;
Sin embargo, como el propsito de crear un alias para un tipo es el de usarlo en lugar del
tipo original. Usaremos BOOLEAN como especificador de tipo ms que enum boolean y
por lo tanto el rtulo boolean no ser empleado. Por lo tanto la definicin anterior puede
escribirse como:
typedef enum {
FALSE, TRUE
} eBoolean;
ITSON
Captulo 12
239
enum {
DOM, LUN, MAR, MIE = 1, JUE, VIE = 1, SAB = 0
} dia;
int ENE = 0;
int FEB = 1;
int MAR = 2;
int DIC = 11;
ITSON
240
typedef enum {
FALSE, TRUE
} eBoolean;
typedef enum {
ENE, FEB, MAR, ABR, MAY, JUN, JUL, AGO, SEP, OCT, NOV, DIC
} eMes;
y luego emplearlos
enum boolean hayDatos(void);
float ventasMes(enum mes mes);
o
boolean hayDatos(void);
float ventasMes(eMes mes);
Uso de Enumeraciones
Una variable de un tipo enumerado no est limitada a tomar slo los valores de las
constantes de enumeracin. En realidad puede tomar cualquier valor en el rango de los
enteros. Sin embargo, lo normal es slo asignarles los valores de las constantes de
enumeracin. Por ejemplo en:
mes = ABR;
la variable eMes toma el valor de 3. Una variable de tipo enumerado puede utilizarse de la
misma forma en que se utiliza una variable entera. Puede usarse en expresiones, ciclos,
listas de argumentos de una funcin y an como parte de nuevos tipos. Por ejemplo las
siguientes expresiones son vlidas.
if(bandera) break;
for(mes = ENE; mes <= DIC; mes++)
ventasAnuales += ventasMes(mes);
Construya una funcin que reciba como parmetro un valor de tipo MESES que represente
el mes actual y que regrese el valor del mes siguiente. El prototipo de la funcin es el
siguiente:
ITSON
Captulo 12
241
Espacios de Nombre
Dentro de un mbito o alcance no podemos usar el mismo identificador para nombrar dos
o ms objetos y/o funciones. Se dice que los objetos y funciones pertenecen al mismo
espacio de nombre. El mismo identificador puede utilizarse para diferentes propsitos,
incluso dentro del mismo alcance, si los usos son en diferentes espacios de nombres. Hay
cuatro espacios de nombre:
Etiquetas.
podemos usar el identificador mes tanto para el rtulo de la enumeracin como para su
alias ya que pertenecen a diferentes espacios de nombre.
ITSON
242
Estructuras
Un arreglo es una lista de variables todas del mismo tipo. Una estructura tambin es una
lista de variables relacionadas pero a diferencia de un arreglo, stas pueden ser de
diferentes tipos. Algunos ejemplos de listas de variables relacionadas que pueden
almacenarse en una estructura son los datos de un alumno: matrcula, NIP, nombre,
carrera; los datos de un artculo en inventario: clave, nombre, cantidad, localizacin, etc.
rtulo es un identificador que sirve para referenciar al tipo que se est declarando en las
declaraciones de objetos, casts y tipos de funcin. La referencia al tipo estructura que se
est creando es struct rtulo y no slo rtulo.
tipo1 es el tipo de las variables nomMiembro11, nomMiembro12 ..., tipo2 es el
tipo de las variables nomMiembro21, nomMiembro22 ..., etc. Esas variables son las
que forman la variable tipo estructura y son llamadas miembros de la estructura.
Al mismo tiempo que definimos un tipo estructura podemos declarar variables de ese tipo.
nomVar1, nomVar2 ... son los identificadores de esas variables.
Por ejemplo:
struct punto {
double x, y;
};
define a struct punto como un tipo estructura para almacenar las coordenadas de un
punto en el plano.
struct triangulo {
struct punto p1, p2, p3;
}
define a struct triangulo como un tipo estructura para almacenar las coordenadas
de los vrtices de un tringulo. Note que una estructura puede contener a otra estructura
como miembro. La siguiente definicin establece a struct alumno como un tipo
ITSON
Captulo 12
243
estructura con los datos de un alumno y al mismo tiempo declara a alumno como una
variable del tipo struct alumno.
struct alumno {
int matricula;
char *nip;
char *nombre;
char *carrera;
} alumno;
o
typedef struct {
int matricula;
char *nip;
char *nombre;
char *carrera;
} sAlumno;
La primera forma es declararlas al mismo tiempo que se define el tipo. Por ejemplo
al definir el tipo struct alumno, se declar la variable alumno como de ese tipo.
o
sAlumno alumno;
ITSON
244
Al igual que con las enumeraciones, esta forma de declaracin solo se recomienda
usarse cuando la declaracin de variables se hace en un slo punto del programa
ya que no podemos declarar posteriormente otras variables del mismo tipo usando
la segunda forma de declaracin.
ITSON
Captulo 12
245
sPunto punto;
sAlumno alumno;
char nombre[40] = "Juan Olivas";
o
*(alumno.nombre + 1) = 'o';
hacen que el contenido de la cadena titulo sea " Joan Olivas ".
Cada uno de los miembros de la estructura sAlumno2 se copian, byte por byte, a la
estructura sAlumno1.
ITSON
246
La primera lnea declara a alumno1 y alumno2 como dos estructuras del tipo sAlumno y
a pAlumno como un apuntador a una estructura de tipo sAlumno.
La segunda lnea almacena en pAlumno la direccin de alumno1, mientras que la tercera
lnea asigna a la variable alumno2 la estructura que se encuentra en la direccin dada por
pAlumno. Las dos ltimas lneas equivalen a la lnea
alumno2 = alumno1;
En el ejemplo anterior vimos como podemos utilizar el operador de indireccin (*) para
accesar a una estructura de la cual tenemos su direccin. Tambin podemos accesar a los
miembros de esa estructura. Por ejemplo para accesar al miembro matricula de la
estructura apuntada por psAlumno escribimos
(*pAlumno).matricula
Note que debemos primero desreferenciar el apuntador para obtener la estructura ya que
el operador punto requiere del lado izquierdo una estructura. Tambin note que son
necesarios los parntesis ya que el operador punto tiene mayor precedencia que el
operador de indireccin. Para simplificar la sintaxis de la expresin anterior C posee un
operador que nos permite accesar a un miembro de una estructura de la cual tenemos su
direccin, el operador de apuntador a estructura llamado tambin operador flecha. El
operador flecha formado por el signo menos (-) y el signo mayor que (>) sin espacios
intermedios (->) tiene la siguiente sintaxis
nomApunVar -> nomMiembro
nomMiembro es el nombre del miembro de la variable tipo estructura cuya direccin est
dada por nomApunVar. La expresin anterior es sintcticamente equivalente al nombre de
una variable del tipo del miembro accesado. Luego para accesar al miembro matricula
de la estructura apuntada por psAlumno utilizando el operador flecha, escribimos
pAlumno->matricula
ITSON
Captulo 12
247
nos dan el tamao de la variable x, mientras que el tamao del arreglo y puede obtenerse
con la expresin:
sizeof(y)
nos dan el tamao en bytes de la variable alumno, dadas las declaraciones de los
ejemplos anteriores.
ITSON
248
Estructuras y Funciones
Una funcin puede regresar por el mecanismo de return una estructura completa. Por
ejemplo la siguiente funcin inicializa una estructura de tipo sPunto a un par de valores
que recibe como argumentos.
sPunto punto(double x, double y)
{
sPunto p;
p.x = x;
return p;
p.y = y;
Una funcin tambin puede recibir como argumento una estructura. Por ejemplo la
siguiente funcin regresa la distancia entre dos puntos
#include <math.h>
double distancia(sPunto p1, sPunto p2)
{
return sqrt(pow((p2.x-p1.x),2) + pow((p2.y-p1.y),2);
}
Por ltimo una funcin puede recibir como argumento un apuntador a una estructura. Por
ejemplo, la siguiente funcin recibe la informacin necesaria para desplegar un alumno, en
una estructura del tipo sAlumno.
void despliegaAlumno(sAlumno *pAlumno)
{
printf("%d, %s, %s, %s", pAlumno -> matricula, pAlumno -> nip,
pAlumno -> nombre, pAlumno -> carrera);
}
Note que dado a que el parmetro pAlumno es un apuntador a una estructura de tipo
sAlumno, utilizamos el operador flecha para accesar a los miembros de la estructura
apuntada por pAlumno. La llamada a la funcin despliegaAlumno() tendra la forma
sAlumno alumno = {12345, "BXPK", "Juan Perez", "IE"};
...
despliegaAlumno(&alumno);
...
ITSON
Captulo 12
249
Arreglos de Estructuras
Ya vimos que un miembro de una estructura puede ser de cualquier tipo: enteros,
flotantes, enumerados, estructuras y como veremos posteriormente uniones. Por otro lado
podemos agrupar estructuras en arreglos. Por ejemplo
sPunto puntos[100];
declara un arreglo de estructuras del tipo sPunto. La siguiente pieza de cdigo muestra la
sintaxis para accesar a los miembros de una estructura que es un elemento de un arreglo:
...
puntos[1] = punto(4.0, 7.0);
puntos[2] = punto(8.0, 2.0);
printf("\La distancia entre los puntos ");
printf("(%.2f, %.2f) y ", puntos[1].x, puntos[1].y);
printf("(%.2f, %.2f) es ", puntos[2].x, puntos[2].y);
printf("%.2f", distancia(puntos[1], puntos[2]);
...
En este ejemplo puntos[1] y puntos[2] son los nombres de dos de las estructuras
que componen el arreglo puntos.
ITSON
250
as como la declaracin de las funciones que permiten inicializar los datos de un alumno y
crear una cadena con los datos de un alumno.
alumno.h
/*
* File:
alumno.h
* Author: mdomitsu
*
* Created on 11 de abril de 2010, 05:31 PM
*/
#ifndef _ALUMNOS_H
#define
_ALUMNOS_H
// Tamao de una cadena para los datos de un alumno
#define TAM_ALUMNO 80
typedef struct {
int matricula;
char nip[7];
char nombre[40];
char carrera[7];
} sAlumno;
void inicializaAlumno(sAlumno *pAlumno, int matricula, char *pNip,
char *pNombre, char *pCarrera);
char* alumnoACadena(char *pCadenaAlumno, sAlumno *pAlumno);
#endif /* _ALUMNOS_H */
ITSON
Captulo 12
251
El siguiente cdigo es un listado parcial del archivo alumnos.c con la declaracin del
arreglo para almacenar el catlogo de alumnos y los mtodos: indiceAlumno() y
despliegaAlumnos().
alumnos.c
/*
* alumnos.c
*
* Este mdulo representa las operaciones del catalogo de
* alumnos de una universidad
*/
#include <stdio.h>
#include "../../alumno/includes/alumno.h"
#include "../includes/alumnos.h"
static sAlumno alumnos[100];
static const int MAX_ALUM = 100;
static int numAlumnos = 0;
/*
* Esta funcin busca a un alumno en el catlogo de alumnos cuya
* matricula coincida con la matricula del parmetro. Regresa el
ITSON
252
que agrega al alumno del parmetro, al catlogo de alumnos. Si hay xito la funcin
regresa el valor OK. Si no hay espacio en el catlogo, la funcin regresa el valor de
CATALOGO_LLENO. Si el alumno ya est en el catlogo, la funcin regresa el valor
REPETIDO.
2. Implemente la funcin
int eliminaAlumno(int matricula);
que borra los datos del alumno cuya matrcula est dado por el parmetro, del
catlogo de alumnos. Si hay xito la funcin regresa el valor OK. Si el alumno no
existe en el catlogo, la funcin regresa el valor NO_EXISTE.
ITSON
Captulo 12
253
Uniones
Al igual que las estructuras, una unin es un tipo definido por el usuario consistente de una
lista de variables relacionadas que pueden ser de diferente tipo. A diferencia de una
estructura, en la que cada uno de sus miembros ocupa su propio espacio de memoria, en
una unin todos los miembros de la unin comparten el mismo espacio de memoria. Por
ejemplo, considere las siguientes definiciones y declaraciones:
struct s {
int x;
long y;
double z;
}
union u {
int x;
long y;
double z;
}
struct s a;
union u b;
b
x
rtulo es un identificador que sirve para referenciar al tipo que se est declarando en las
declaraciones objetos, casts y tipos de funcin. La referencia al tipo unin que se est
creando es union rtulo y no slo rtulo.
ITSON
254
pero no como:
u b = 789.56
ITSON
Captulo 12
255
la funcin printf() no despliega el valor de 125, sino un nmero largo cuyos dos bytes
menos significativos contienen la secuencia binaria equivalente a 125. Sin embargo no
siempre es un error asignarle a una unin un valor del tipo de uno de sus miembros y
extraerle un valor del tipo de otro de sus miembros. De hecho esta propiedad de las
uniones se emplear en un subtema ms adelante. Otra de las ventajas de las uniones es
la de que al compartir sus miembros el mismo espacio de memoria, son de menor tamao
que una estructura con los mismos miembros. Por supuesto la unin slo se puede
emplear si estamos seguros que slo un miembro va a ocupar la unin a la vez.
ITSON
256
#endif /* _PRODUCTO_H */
producto.c
/*
* producto.c
*
* Este mdulo representa a un producto de un almacen
*/
#include <stdio.h>
#include <string.h>
#include "../includes/producto.h"
/*
* Esta funcion inicializa los campos de un material apuntado por sProducto
* con los valores de sus parametros
*/
void inicializaMaterial(sProducto *pProducto, int clave, char *nombre,
int nCantidad, char *unidad) {
pProducto->clave = clave;
strcpy(pProducto->nombre, nombre);
pProducto->tipo = MATERIAL;
pProducto->cantidad.nCantidad = nCantidad;
strcpy(pProducto->unidad, unidad);
}
/*
* Esta funcion inicializa los campos de un reactivo apuntado por sProducto
* con los valores de sus parametros
*/
void inicializaReactivo(sProducto *pProducto, int clave, char *nombre,
float fCantidad, char *unidad) {
pProducto->clave = clave;
strcpy(pProducto->nombre, nombre);
pProducto->tipo = REACTIVO;
pProducto->cantidad.fCantidad = fCantidad;
strcpy(pProducto->unidad, unidad);
}
/*
* La funcin despliega los valores de los campos del producto del parametro
* en un renglon.
*/
char* productoACadena(char *pCadenaProducto, sProducto *pProducto) {
if (pProducto->tipo == MATERIAL)
sprintf(pCadenaProducto, "%d, %s, Material, %d, %s",
pProducto->clave, pProducto->nombre,
pProducto->cantidad.nCantidad, pProducto->unidad);
else if (pProducto->tipo == REACTIVO)
sprintf(pCadenaProducto, "%d, %s, Reactivo, %.4f, %s",
pProducto->clave, pProducto->nombre,
pProducto->cantidad.fCantidad, pProducto->unidad);
return pCadenaProducto;
}
ITSON
Captulo 12
257
ITSON
258
de
los
campos
de
los
productos
del
char cadenaProducto[TAM_PRODUCTO];
for(i =0; i < numProductos; i++)
printf("\n%s", productoACadena(cadenaProducto, &productos[i]));
printf("\n");
}
ITSON
Captulo 12
259
Campos de Bits
Un miembro entero o entero sin signo de una estructura puede declararse como formado
por un nmero dado de bits. Tal miembro se denomina Campo de bits, y su nmero
asociado de bits se llama su ancho. La sintaxis para declarar un campo de bits es:
{int|unsigned} nomCampo: ancho;
Con signo
Sin signo
-1 .. 0
0 .. 1
-2 .. 1
0 .. 3
-4 .. 3
0 .. 7
-8 .. 7
0 .. 15
-16 .. 15
0 .. 31
-32 .. 31
0 .. 63
-64 .. 63
0 .. 127
...
i:
j:
:
k:
m:
2;
5;
4;
1;
4;
ITSON
260
15 14 13 12 11 10 9
m
Sin uso
0
i
La mayora de los compiladores no permiten que un campo de bits quede repartido entre
dos palabras. Por ejemplo la siguiente declaracin:
struct BITS2
{
int
a:
unsigned b:
int
c:
int
d:
unsigned e:
} y;
4;
5;
10;
1;
4;
Crea una variable y de tipo estructura en la cul los primeros dos campos quedan en una
palabra y los otros tres en otra.
Primer palabra
15 14 13 12 11 10 9 8 7 6
Segunda palabra
15 14 13 12 11 10 9 8 7 6 5
e
Podemos mezclar en una estructura, campos normales y campos de bits. Por ejemplo:
struct BITS3
{
long
char
int
unsigned
int
unsigned
};
x;
msj[20];
a: 4;
b: 5;
c: 10;
e: 4;
ITSON
Captulo 12
261
i: 3;
j: 5;
k[4]: 1;
m: 4;
/* No es vlido */
b2
b1
b0
a3
a2
a1
a0
Problemas
1. Para el programa que permite administrar el catlogo de alumnos de una
universidad de los ejemplos sobre estructuras, implemente las siguientes funciones
en el mdulo alumnos:
int obtenAlumno(sAlumno *pAlumno, int matricula);
que actualiza los datos del alumno cuya matrcula est en el alumno del parmetro,
del catlogo de alumnos. Si hay xito la funcin regresa el valor OK. Si el alumno no
existe en el catlogo, la funcin regresa el valor NO_EXISTE.
2. Para el programa que permita administrar el inventario de un laboratorio de los
ejemplos sobre uniones, implemente las siguientes funciones:
int obtenProducto(sProducto *pProducto, int clave)
ITSON
262
que regresa el producto del catlogo de productos cuya clave coincida con la clave
del parmetro. El producto se regresa en la estructura apuntada por el parmetro
pProducto. Regresa el ndice del producto en el arreglo si existe, NO_EXISTE en
caso contrario.
int actualizaProducto(sProducto *pProducto)
que actualiza al producto del catalogo de productos cuya clave coincida con la
clave del producto del parmetro. Si hay xito la funcin regresa OK. Si el producto
no existe, la funcin regresa NO_EXISTE.
int elimninaProducto(sProducto *pProducto)
que reduce la cantidad del producto del catalogo de productos cuya clave coincida
con la clave del producto parmetro. Si despus de la reduccin la cantidad <= 0 el
producto se elimina del catalogo. Si hay xito la funcin regresa OK. Si el producto
no existe, la funcin regresa NO_EXISTE. Si la cantidad del producto en el
inventario para reducirla, la funcin regresa PRODUCTO_INSUFICIENTE.
3. Se requiere una funcin que reciba como parmetro un unsigned char y que
intercambie los bits 0 a 2 por los bits 4 a 6 sin alterar los bits 3 y 7. La funcin debe
regresar el valor del parmetro con los bits intercambiados. Utilice campos de bits
en la solucin. La sintaxis de la funcin es
unsigned char intercambia(unsigned char x);
ITSON