0% encontró este documento útil (0 votos)
70 vistas18 páginas

Estructuras en C: Tipos y Declaraciones

El documento describe los tipos abstractos de datos en C, específicamente las estructuras. Las estructuras permiten almacenar datos de diferentes tipos agrupados bajo una sola unidad. Se definen las estructuras mediante la palabra clave "struct" y sus miembros. Las variables estructura se pueden declarar y acceder a sus miembros individuales mediante el operador punto. También se pueden definir arrays de estructuras.

Cargado por

Víctor Carvajal
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
70 vistas18 páginas

Estructuras en C: Tipos y Declaraciones

El documento describe los tipos abstractos de datos en C, específicamente las estructuras. Las estructuras permiten almacenar datos de diferentes tipos agrupados bajo una sola unidad. Se definen las estructuras mediante la palabra clave "struct" y sus miembros. Las variables estructura se pueden declarar y acceder a sus miembros individuales mediante el operador punto. También se pueden definir arrays de estructuras.

Cargado por

Víctor Carvajal
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

INFORMÁTICA II – GRADO EN MATEMÁTICAS

Tema II.- Tipos Abstractos de Datos -1-

Estructura
Los datos simples pueden almacenar un único elemento de información. Los vectores y las
matrices pueden almacenar un cierto número de elementos de información del mismo tipo
de dato. Pero frecuentemente es necesario almacenar en una única unidad, datos de diferentes
tipos, para lo cual C proporciona un tipo especial de dato: la estructura.
Una estructura consta de un número de elementos de datos, que no necesitan ser del mismo
tipo, agrupados dentro de la misma entidad. En otros lenguajes se les suele denominar
registro o record.
Los datos individuales que forman la estructura se denominan elementos o miembros de la
estructura. Los miembros de una estructura normalmente están relacionados de una forma
lógica desde el punto de vista de la información que tratan.
Declaración de estructuras
Mediante la palabra reservada struct se establece un patrón, plantilla o tipo de la estructura
que se va a emplear. La forma general de declarar el tipo de una estructura es:
struct nombre_tipo_estructura {
tipo1 miembro1;
tipo2 miembro2;
...
tipon miembron;
};
donde:
§ struct es una palabra reservada requerida.
§ nombre_tipo_estructura es un identificador para dar nombre a la estructura declarada.
§ tipox miembrox son las declaraciones de los miembros individuales de la estructura.
§ Es necesaria la inclusión de un punto y coma (;) después de cerrar las llaves.
Los nombres de los miembros dentro de una estructura particular deben ser diferentes, pero
pueden coincidir con el nombre de variables fuera de la estructura o con los nombres de los
miembros de otras estructuras.

La declaración de un tipo de estructura crea un nuevo tipo de dato definido por el


programador. Pero no ocupa memoria, ya que no se produce reserva de la misma hasta que
no se declara una variable de dicho tipo.

Por ejemplo, la siguiente será la declaración de una estructura alumno para relacionar los
datos correspondientes a un alumno de primer curso. Esta estructura contiene el nombre, la
dirección, el número de matrícula, el teléfono y las notas de las 10 asignaturas.
struct alumno {
alumno (estructura)
char nombre [51];
char direccion [81]; nombre (miembro)
unsigned long num_matricula; direccion (miembro)
unsigned long telefono; num_matricula (miembro)
float notas[10];
};
telefono (miembro)
notas (miembro)

Departamento de Informática y Automática – Universidad de Salamanca


INFORMÁTICA II – GRADO EN MATEMÁTICAS
Tema II.- Tipos Abstractos de Datos -2-

Los miembros individuales de la estructura pueden ser de cualquier tipo, incluso punteros,
matrices u otras estructuras.

Definición de variables estructura


Existen dos formas:

A) En la declaración del tipo de la estructura, especificando los nombres de las variables


estructuras después de la llave de cierre.
struct nombre_tipo_estructura {
tipo1 miembro1;
tipo2 miembro2;
...
tipon miembron;
} nomvar1, nomvar2, ... ;

En este caso es posible omitir, si se desea, el nombre del tipo estructura, por lo que también
sería válida la declaración:
struct { tipo1 miembro1;
tipo2 miembro2;
...
tipon miembron;
} nomvar1, nomvar2, ... ;

Si se omite el nombre del tipo estructura, se dice que se está declarando variables estructura
sin etiqueta. En este caso no se puede volver a definir otras variables de este tipo de estructura,
pues no existe nombre para el tipo.

B) Después de que el tipo de la estructura ha sido declarado, pueden definirse variables de


ese tipo de estructura como si se tratase de un tipo predefinido.
struct nombre_tipo_estructura nomvar1, nomvar2, ... ;

En la declaración de las variables es necesario especificar struct nombre_tipo_estructura y


no nombre_tipo_estructura simplemente

Estructuras anidadas
Una variable estructura puede ser definida como miembro de otra estructura. En tales
situaciones, la declaración de la estructura interna debe aparecer antes que la declaración de la
estructura externa.
Por ejemplo,
struct fecha {
int dia;
int mes;
int anio;
};

struct cuenta {
unsigned long numero;
char tipo;
char titular[51];
float saldo;
struct fecha fapertura;
};
INFORMÁTICA II – GRADO EN MATEMÁTICAS
Tema II.- Tipos Abstractos de Datos -3-

struct cuenta nuevocliente, antiguocliente;

La segunda estructura cuenta contiene otra estructura fecha como uno de sus miembros, por
lo que la declaración de la estructura fecha debe preceder a la de la estructura cuenta.
Referencia a elementos individuales
Los miembros de una variable estructura pueden procesarse de modo individual, como
entidades separadas, por lo que debe ser posible acceder a los miembros individuales de una
variable estructura.
Una forma de acceder a ellos es a través del operador miembro de una estructura, que se
presenta por un punto (.), precedido por el nombre de la variable estructura y seguido por el
nombre del miembro.
variable.miembro

Un miembro de una variable estructura referenciado de esta forma se comportará como


cualquier variable ordinaria del tipo declarado para ese miembro de la estructura.

Por ejemplo, en la variable estructura nuevocliente declarada anteriormente, son válidas


sentencias del tipo:
nuevocliente.numero = 3130786;
gets(nuevocliente.titular);
strcpy(nuevocliente.titular, "Juan López Aguilrre");
nuevocliente.fapertura.dia = 17;
nuevocliente.fapertura.anio = 2003;

El operador miembro de una estructura (.) pertenece al grupo de mayor prioridad, por lo
que se evalúa primero que cualquier otro operador de menor prioridad.

Por ello, la expresión &variable.miembro es equivalente a &(variable.miembro), por lo


que la expresión anterior accede a la dirección de comienzo del miembro de la variable
estructura y no a la dirección de comienzo de la variable estructura.

Del mismo modo, la expresión ++variable.miembro es equivalente a ++


(variable.miembro), por lo que el operador ++ se aplica sobre el miembro de la variable
estructura y no sobre la variable estructura completa.

Iniciación de una estructura en su definición


A los miembros de una variable estructura se les puede asignar valores iniciales en su
definición. Los valores iniciales deben aparecer en el mismo orden en que serán asignados a
los correspondientes miembros de la variable estructura, encerrados entre llaves y separados
por comas. El siguiente ejemplo ilustra la iniciación de variables estructuras.
struct fecha {
int dia;
int mes;
int anio;
};
struct cuenta {
unsigned long numero;
char tipo;
char titular[51];
float saldo;
struct fecha fapertura;
INFORMÁTICA II – GRADO EN MATEMÁTICAS
Tema II.- Tipos Abstractos de Datos -4-

};
struct cuenta nuevocliente = {30056231452, 'C',
"SANTIAGO DENIA", 365800, 12, 5, 1989};

Arrays de estructuras
Es posible declarar arrays de estructuras, es decir, vectores o tablas en las que cada
elemento sea una estructura.
struct alumno {
char nombre [51];
char direccion [81];
unsigned long num_matricula;
unsigned long telefono;
float notas[10];
};

struct alumno clase_primero[100];

En este ejemplo, clase_primero es un vector de estructuras con espacio para almacenar los
datos de 100 alumnos. Cada elemento de clase_primero es una estructura de tipo alumno
(cada elemento de clase_primero representa un registro de alumno individual).

El operador subíndice de una tabla [ ], tiene la misma prioridad que el operador miembro
de una estructura (.) y su asociatividad es de izquierda a derecha.

Por ello, en el caso de vectores miembros de una estructura,


struct {
int miembro [N];
} variable;

la expresión variable.miembro[i] es equivalente a (variable.miembro)[i], por lo que se


está accediendo a elemento i del vector miembro de la variable estructura.

Del mismo modo, en el caso de vectores de estructuras


struct {
int miembro;
} variable[M];

la expresión variable[k].miembro es equivalente a (variable[k]).miembro, por lo que se


está accediendo al miembro del elemento k del vector de estructuras.

Pueden asignarse valores iniciales en la declaración de una matriz de estructuras, como


cualquier otra matriz.
struct fecha {
int dia;
int mes;
int anio;
};
struct persona {
char nombre[81];
struct fecha fnacimiento;
} agenda[] = {"ANA", 30, 12, 1973,
"JOSE", 13, 5, 1966,
"ROSA", 4, 2, 1977,
INFORMÁTICA II – GRADO EN MATEMÁTICAS
Tema II.- Tipos Abstractos de Datos -5-

"SARA", 29, 7, 1963,


"ANTONIO", 31, 3, 1974};

En este ejemplo, agenda es un vector de estructuras cuyo tamaño está sin especificar. El
número de valores de iniciación definirá, por tanto, el tamaño del vector.
Cada fila de los valores de iniciación contiene 4 constantes. Estas constantes representan los
valores iniciales, eso es, un nombre, un día, un mes y un año para un elemento del vector.
Como hay 5 conjuntos de constantes (5 filas), el vector contendrá 5 elementos numerados del
0 al 4.
Punteros y estructuras
Se pueden declarar punteros a estructuras. La forma de hacerlo es igual que para otro tipo
de dato cualquiera de C.
struct nombre_tipo_estructura *nombrepuntero;

Para “apuntar” con un puntero a una variable estructura, se utiliza el operador & (operador
dirección), igual que para otro tipo de dato cualquiera de C.
struct nombre_tipo_estructura nombrevariable;
nombrepuntero = &nombrevariable;

Ahora el puntero nombrepuntero apunta a la variable estructura nombrevariable, y esto nos


permite una nueva forma de acceder a sus miembros, utilizando el operador flecha (->),
llamado operador puntero a miembro de una estructura, formado por los símbolos (-) y (>).

Se utiliza de forma análoga a como se utilizaba el operador punto (.), pero en lugar de utilizar
el nombre de la variable estructura de utiliza el nombre del puntero.
nombrepuntero->nombremiembro

También se podría utilizar el operador asterisco (*) pero es muy infrecuente:


(*nombrepuntero).nombremiembro

En este segundo caso, obsérvese la necesidad de utiliza los paréntesis, por la mayor prioridad
del operador (.) respecto al (*).

En el siguiente ejemplo se utiliza el operador puntero a miembro de una estructura dentro


de un array de estructuras.
#include <stdio.h>
#include <stdlib.h>
struct medidas {
int ancho;
int largo;
};
int main(void) {
struct medidas muebles[3]; /* Array de 3 estructuras "medidas" */
struct medidas *m; /* Puntero a estructuras "medidas" */
int i;
m=muebles; /* El puntero "m" apunta al array "muebles" */
for (i=0; i<3; i++) {
muebles[i].ancho=2*(i+1);
muebles[i].largo=3*(i+1);
}

/* >>> Las 4 siguientes sentencias son equivalentes <<< */


INFORMÁTICA II – GRADO EN MATEMÁTICAS
Tema II.- Tipos Abstractos de Datos -6-

/* ============================================ */

for (i=0; i<3; i++)


printf("Medidas: %d x %d\n", muebles[i].ancho, muebles[i].largo);
printf ("\n");
for (i=0; i<3; i++)
printf("Medidas: %d x %d\n", (muebles+i)->ancho,(muebles+i)->largo);
printf ("\n");
for (i=0; i<3; i++)
printf("Medidas: %d x %d\n", m[i].ancho, m[i].largo);
printf ("\n");
for (i=0; i<3; i++)
printf("Medidas: %d x %d\n", (m+i)->ancho, (m+i)->largo);
printf ("\n");

system ("pause");
return 0;
}
Operaciones con estructuras como unidades
A parte de las operaciones que ya hemos visto con variables estructuras:
§ acceder individualmente a sus miembros (con . o ->).
§ obtener su dirección (con el operador &).
§ iniciarla en su declaración.
También es posible realizar ciertas operaciones que actúen sobre toda la estructura como una
unidad:
§ asignar una estructura completa a otra, como una unidad1 (siempre que ambas sean del
mismo tipo), con el operador asignación (=).
§ pasar una estructura completa como argumento a una función2 (tanto por valor como por
referencia), y devolver una estructura como valor de retorno de una función.
Sin embargo, no es posible comparar dos estructuras como una unidad; debe hacerse
miembro a miembro.

1
Esta característica se incluye en el C estándar ANSI. En compiladores que no soportan C ANSI no es posible
asignar estructuras como unidades de información, por lo que no se pueden pasar por valor estructuras a
funciones, ni pueden ser devueltas por éstas como valor de retorno. Para ello, en esos compiladores se debe
trabajar con punteros.
2
A la hora de pasar estructuras a funciones se ha de tener en cuenta que si ésta es muy complicada (con muchos
miembros) se escribe y borra mucho en la pila, con la consiguiente pérdida de tiempo. Por eso se aconseja
utilizar punteros en estos casos, es decir, pasarlas por referencia aunque no se vayan a modificar dentro de la
función.
INFORMÁTICA II – GRADO EN MATEMÁTICAS
Tema II.- Tipos Abstractos de Datos -7-

Enumeraciones
Una enumeración es un tipo de dato que consta de una lista de constantes enteras con signo.
Los nombres de estas constantes representan los valores legales que puede tomar una
variable que se defina de ese tipo.
La declaración de la plantilla o tipo de una enumeración se realiza con la palabra reservada
enum y la lista de constantes3 encerrada entre paréntesis.
enum nombre_tipo_enumeracion {
constante1,
constante2,
...
constanten,
};
Los nombres de las constantes deben ser todos diferentes y distintos a los nombres de otros
identificadores cuyo ámbito sea el mismo que el de la enumeración.
La definición de variables tipo enum se realiza de forma análoga a como se define una
variable estructura:

enum nombre_tipo_enumeracion variable_enumeracion;


o bien

o bien

enum nombre_tipo_enumeracion { constante1,


constante2,
...
constanten,
} variable_enumeracion;

enum {
constante1, constante2,
...
constanten,
} variable_enumeracion;

Internamente los elementos que forman parte de una enumeración son constantes enteras con
signo cuyos valores son asignados automáticamente por el compilador, comenzando por cero
para la primera constante, uno para la segunda, y así sucesivamente.
Por ejemplo, puede pensarse en una variable llamada diasemana que sólo puede tomar los 7
siguientes valores: lunes, martes, miercoles, jueves, viernes, sabado y domingo.
Comenzaremos por declarar un nuevo tipo enumeración al que llamaremos dia.
enum dia {lunes, martes, miercoles, jueves, viernes, sabado, domingo };

La declaración anterior crea un nuevo tipo de dato (tipo enum dia) cuyas variables que se
definan de dicho tipo sólo podrán tomar uno de los 7 valores especificados.
Posteriormente la definición de la variable diasemana se realizará de la siguiente forma:
enum dia diasemana;

Internamente los elementos que forman parte de una enumeración son constantes tipo int con
los siguientes valores:
lunes 0
INFORMÁTICA II – GRADO EN MATEMÁTICAS
Tema II.- Tipos Abstractos de Datos -8-

martes 1
miercoles 2
jueves 3
viernes 4
sabado 5
domingo 6

Al declarar un tipo enumerado, se puede redefinir los valores que el compilador asigna
automáticamente, iniciando las constantes con los valores que se deseen, recordando que cada
constante no iniciada toma un valor superior en una unidad a la anterior.
enum monedas {peseta=1, duro=5, cincoduros=25, veinteduros=100};
enum mobiliario {silla, mesa, puerta=100, escalera, armario};

En esta segunda declaración los valores que tomarán las constantes son
silla 0
mesa 1
puerta 100
escalera 101
armario 102

Referencia a las variables enumeración


Para dar valor a una variable enumeración se utiliza el nombre de la constante
correspondiente.
Por ejemplo, supongamos la definición de la variable enumerada color.
enum colores {rojo, amarillo=4, verde, azul};
enum colores color;

Los únicos operadores que pueden acompañar a los tipos enumerados son el operador de
asignación y los de relación.
§ Asignación de valor: color = verde;
§ Comparación para decisión: if (color == amarillo)
....
No es posible leer (teclado, fichero, ...) una variable enumerada y asignarle un valor. Podría
leerse un entero y asignárselo a la variable enumerada, aunque esto no es muy común.
Tampoco es posible escribir (pantalla, fichero, ...) una variable enumerada. Sólo el valor
entero de una variable enumerada podría ser mostrado.
El siguiente ejemplo presenta una posible forma de dar valor a una variable enumeración a
partir de la lectura desde teclado de un número entero.
Además, ilustra como poder utilizar una variable enumerada como variable de control de un
for y como subíndice para un array, es decir, utilizando la característica de que internamente
los elementos que forman parte de una enumeración son constantes enteras con signo cuyos
valores son asignados automáticamente por el compilador, comenzando por cero, en caso de
no especificar explícitamente otro valor para las mismas.
#include <stdio.h>
#include <stdlib.h>
enum dias {lunes, martes, miercoles, jueves, viernes, sabado, domingo};

char nombre[][12] = {"Lunes", "Martes", "Miércoles", "Jueves",


"Viernes", "Sabado", "Domingo"};
int main(void) {
enum dias hoy;
int unDia;
INFORMÁTICA II – GRADO EN MATEMÁTICAS
Tema II.- Tipos Abstractos de Datos -9-

printf("Los dias de la semana son:\n");


for (hoy = lunes; hoy <= domingo; hoy++)
printf("El dia %d es el %s\n", hoy, nombre[hoy]);
printf("\n\nEscriba el numero de un día: ");
scanf("%d",&unDia);
printf("El dia %d es el %s\n", unDia, nombre[unDia]);

printf ("\n");
system ("pause");
return 0;
}
Un resultado interesante, que se obtiene en algunos compiladores en el programa, es si damos
el 7 como día de la semana solicitado por teclado. En ese caso el programa indica como
resultado
El dia 7 es el Los dias de la semana son:

¿Qué explicación tiene?. C forma una tabla de cadenas en el lugar oportuno de memoria. Las
cadenas que se han utilizado en este programa son los 7 días de la semana en la cadena
nombre (índices del 0 al 6), y luego la cadena del printf() inicial, que es la que se muestra
para la entrada anterior.

A menudo se puede incrementar la claridad lógica de un programa utilizando variables


enumeradas. Las variables de enumeración son particularmente útiles como indicadores,
para indicar varias opciones para realizar un cálculo, o para identificar condiciones que
puedan haber surgido como resultado de cálculos internos anteriores. Desde esta perspectiva
se aconseja el uso de variables de enumeración dentro de un programa complejo. No
obstante debe quedar claro que se pueden usar variables enteras en lugar de variables de
enumeración. Por lo tanto, las variables de enumeración, a parte de facilitar la codificación
y la legibilidad de los programas, no proporcionan fundamentalmente nuevas capacidades.

typedef
Permite que el programador defina nuevos nombres o alias para los tipos ya existentes. No
se trata, por tanto, de la creación de nuevos tipos de datos.

La forma general de la sentencia es: typedef tipo nombre;

Donde tipo es cualquier tipo de datos legal, y nombre el alias. El nuevo nombre es una
adición a los tipos de existentes, no una sustitución de éstos.

Por ejemplo, si se define un alias para el tipo de dato float.


typedef float real;

Con esta definición no se ha creado un tipo nuevo sino que se emplea otro nombre para un
tipo de dato ya existente que sigue estando activo. Por ello, podemos usar real para cualquier
finalidad que pudiéramos hacer con float. A diferencia de otros lenguajes, el nuevo tipo
declarado es completamente compatible con el tipo con el que se declara, es decir, se podrán
intercambiar variables, valores, parámetros, etc., sin ningún problema.
float a = 10.5;
real e = -2073;
e = a;
a = e;
INFORMÁTICA II – GRADO EN MATEMÁTICAS
Tema II.- Tipos Abstractos de Datos - 10 -

Aunque este último aspecto sugiere una pregunta: ¿para qué queremos crear un tipo nuevo si
lo vamos a seguir mezclando con el viejo?. Como ahora veremos, la utilidad es precisamente
realizar un tipo nuevo que se pueda utilizar independientemente de que cambie su definición.
Por ejemplo, si hemos realizado la definición typedef float real; más adelante podremos
decidir aumentar la precisión del tipo real cambiando la definición del typedef. Gracias a esto
podemos hacerlo sin necesidad de tocar todas las variables y funciones que hayamos definido
a partir del tipo real. Por tanto, es recomendable no mezclar tipos distintos por muy
compatibles que sean.
Por ejemplo, las siguientes definiciones
typedef unsigned char byte;
typedef unsigned short int word;
typedef unsigned long int dword;

son muy usuales para utilizar estos nuevos tipos de manera independiente del compilador y
procesador. Así si se cambia a una nueva máquina sólo habrá que cambiar el typedef apropiado
en una sola parte del código, sin tocar el resto.
Según Kernighan y Ritchie: "Hay dos razones principales para usar declaraciones typedef.
La primera es parametrizar un programa contra problemas de portabilidad. Si los typedef se
usan para tipos de datos que son independientes de la máquina, sólo los typedef deben ser
cambiados cuando el programa se mueva. Una situación común es usar nombres typedef
para diversas cantidades enteras, luego se hace un conjunto apropiado de elecciones de
short, int y long para cada máquina. El segundo propósito de typedef es proveer mejor
documentación para un programa".
Es posible utilizar distintos nombres para un mismo tipo de dato. Por ejemplo,
typedef long entero_largo;
typedef long entero_grande;

De esta forma en el programa se podrá utilizar para definir una variable de tipo long int
llamada longitud, cualquiera de las siguientes definiciones:
long longitud;
entero_largo longitud;
entero_grande longitud;

También se puede usar typedef para los tipos de datos complejos y compuestos:
typedef struct tipo_usuario {
char nombre [40];
char login [16];
int id;
} usuario;
usuario lista [200];

La palabra usuario no es en este caso una variable, sino el alias definido para el nuevo tipo de
dato estructura struct tipo_usuario.

Si no se utilizara typedef deberá definirse la variable lista de la siguiente forma:


struct tipo_usuario lista [200];
INFORMÁTICA II – GRADO EN MATEMÁTICAS
Tema II.- Tipos Abstractos de Datos - 11 -

Ejercicios resueltos

EJERCICIO 1
Encuentra los errores en la siguiente declaración de estructura y posterior definición de
variable
struct hormiga {
int patas;
char especie[41];
float tiempo;
};
hormiga colonia[200];

Solución
Es necesario conservar la palabra struct en la declaración de variables
struct hormiga colonia[200];

a no ser que se añada una sentencia typedef como la siguiente:


typedef struct hormiga hormiga;

EJERCICIO 2
Declara una variable enum para representar las estaciones del año. Deberán representarse
internamente por las constantes 1, 2, 3 y 4.
Solución
enum estaciones {PRIMAVERA=1, VERANO=2, OTOÑO=3, INVIERNO=4};

EJERCICIO 3
¿Es válida en un programa la siguiente definición?. ¿Por qué?
enum vehiculo {moto, coche, carruaje, autobus, bicicleta, motocicleta};
enum transporte {avion, barco, coche, ferrocarril, tranvia};

Solución
No es válida.
En la definición de una enumeración, los nombres de las constantes deben ser todos diferentes
y distintos a los nombres de otros identificadores cuyo ámbito sea el mismo que el de la
enumeración.
En este caso se producirá un error de compilación porque se detectará una doble declaración
del identificador “coche”.

EJERCICIO 4
Escribir una función que devuelva en un tipo enum estaciones, declarado anteriormente, la
estación del año que se ha introducido por teclado.
Solución
El tipo enumerado asocia constantes enteras a los nombres simbólicos, pero estos nombres
INFORMÁTICA II – GRADO EN MATEMÁTICAS
Tema II.- Tipos Abstractos de Datos - 12 -

simbólicos no pueden ser leídos de teclado desde una función estándar como scanf() o gets().
Por consiguiente lo que se podría hacer es leer un valor entero que asociar con la constante
simbólica, según la definición del tipo enumerado.

enum estaciones leerEstacion ()


{
int e;
gets("Introduzca un número para la estación del año");
gets(" 1 - Primavera");
gets(" 2 – Verano ");
gets(" 3 – Otoño ");
gets(" 4 – Invierno ");

do
{ printf("==> ");
scanf("%d", &e);
} while (e > 4 || e < 1);

swich (e)
{
case 1: return (PRIMAVERA); break;
case 2: return (VERANO); break;
case 3: return (OTOÑO); break;
case 4: return (INVIERNO); break;
}
}

Hay que destacar que para que la función compile correctamente, es necesario que el tipo
enumerado enum estaciones haya sido declarado a nivel global en el programa.

EJERCICIO 5
¿Con typedef se declaran nuevos tipos de datos, o bien permite cambiar el nombre de tipos de
datos ya declarados?.
Solución
La sentencia no añade ningún tipo de dato nuevo a los ya definidos en el lenguaje C.
Simplemente permite renombrar un tipo ya existente, incluso aunque sea un nuevo nombre
para un tipo de dato básico del lenguaje como int o float.

EJERCICIO 6

Se presenta como recibir una estructura como parámetro por valor y por referencia, y como devolverla como
parámetro por referencia o como valor de retorno de la función

A) Declarar un tipo de dato estructura para representar un alumno. Los campos de los que
debe de disponer son:
§ Nombre completo, cadena de caracteres
§ Curso, entero
§ Fecha nacimiento, estructura de tres campos enteros para el día, mes y año
§ Dirección completa, cadena de caracteres
§ 10 notas parciales, vector de 10 números reales
Definir una variable del tipo estructura anterior.

Definiciones en C
#define MAXN 10
INFORMÁTICA II – GRADO EN MATEMÁTICAS
Tema II.- Tipos Abstractos de Datos - 13 -

struct fecha {
int dia;
int mes;
int anio;
};
struct alumno {
char nombre[51];
int curso;
struct fecha fnac;
char direccion[61];
float notas[MAXN];
};
struct alumno alum;

B) Escribir una función que lea de teclado los campos de una estructura de tipo alumno y la
devuelva al módulo llamador como valor de retorno de la función.
Función codificada en C
Como ninguna función intrínseca de entrada por teclado permite leer en una única sentencia
toda la estructura, la función ha de leer por separado cada uno de sus campos, accediendo a
ellos mediante el operador punto. Algunos compiladores no permiten devolver una estructura
como valor de retorno de una función, por lo que en estos casos haría que utilizar el paso por
referencia, como se verá más adelante.

struct alumno leerAlumno() {


struct alumno aa;
int i;

printf("Introduzca el nombre: ");


fflush(stdin);
gets(aa.nombre);

printf("Introduzca el curso: ");


scanf("%d", &aa.curso);

printf("Introduzca la fecha de nacimiento:\n");


printf("Introduzca el día: ");
scanf("%d", &aa.fnac.dia);

printf("Introduzca el mes: ");


scanf("%d", &aa.fnac.mes);

printf("Introduzca el año: ");


scanf("%d", &aa.fnac.anio);

printf("Introduzca la dirección: ");


fflush(stdin);
gets(aa.direccion);

for (i=0; i<MAXN; i++)


{ printf("Introduzca la nota %2d: ", i+1);
scanf("%f", &aa.notas[i]);
}

return aa;
}
INFORMÁTICA II – GRADO EN MATEMÁTICAS
Tema II.- Tipos Abstractos de Datos - 14 -

El prototipo de la función es struct alumno leerAlumno(void);


y la forma de llamarla alum = leerAlumno();

C) Escribir una función que lea de teclado los campos de una estructura de tipo alumno y la
devuelva al módulo llamador a través de un parámetro que se le haya pasado por
referencia.

Función codificada en C
Al pasar una estructura por referencia, por medio de un puntero a la misma, hay que utilizar el
operador flecha (->) para acceder a cada uno de sus campos. En este caso la estructura no es
una variable local, sino que se están utilizando las posiciones de memoria originales del
parámetro real del módulo llamador.

void leerAlumno(struct alumno *aa) {


int i;

printf("Introduzca el nombre: ");


fflush(stdin);
gets(aa->nombre);
printf("Introduzca el curso: ");
scanf("%d", &aa->curso);
printf("Introduzca la fecha de nacimiento:\n");
printf("Introduzca el día: ");
scanf("%d", &aa->fnac.dia);
printf("Introduzca el mes: ");
scanf("%d", &aa->fnac.mes);
printf("Introduzca el año: ");
scanf("%d", &aa->fnac.anio);
printf("Introduzca la dirección: ");
fflush(stdin);
gets(aa->direccion);
for (i=0; i<MAXN; i++)
{ printf("Introduzca la nota %2d: ", i+1);
scanf("%f", &aa->notas[i]);
}
}

El prototipo de la función es void leerAlumno(struct alumno *);


y la forma de llamarla leerAlumno(&alum);
D) Escribir una función que reciba una estructura de tipo alumno por valor, y presente sus
campos en pantalla.

Función codificada en C
Como ninguna función intrínseca de salida por pantalla permite mostrar en una única sentencia
toda la estructura en pantalla, utilizaremos la función printf para mostrar uno a uno los campos
de la misma.
void mostrarAlumno(struct alumno aa) {
int i;
printf("Nombre: %s\n", aa.nombre);
printf("Curso : %d\n", aa.curso);
printf("Fecha de nacimiento: %d/%02d/%d\n",
INFORMÁTICA II – GRADO EN MATEMÁTICAS
Tema II.- Tipos Abstractos de Datos - 15 -

aa.fnac.dia, aa.fnac.mes, aa.fnac.anio);


printf("Dirección: %s\n", aa.direccion);
for (i=0; i<MAXN; i++)
printf("Nota %2d: %5.2f\n", i+1, aa.notas[i]);
}

El prototipo de la función es void mostrarAlumno(struct alumno);


y la forma de llamarla mostarAlumno(alum);

E) Escribir una función que reciba una estructura de tipo alumno por referencia, y presente
sus campos en pantalla.
Función codificada en C
void mostrarAlumno(struct alumno *aa) {
int i;
printf("Nombre: %s\n", aa->nombre);
printf("Curso : %d\n", aa->curso);
printf("Fecha de nacimiento: %d/%02d/%d\n",
aa->fnac.dia, aa->fnac.mes, aa->fnac.anio);
printf("Dirección: %s\n", aa->direccion);
for (i=0; i<MAXN; i++)
printf("Nota %2d: %5.2f\n", i+1, aa->notas[i]);
}

El prototipo de la función es void mostrarAlumno(struct alumno *);


y la forma de llamarla mostarAlumno(&alum);

Hay que destacar que en todas las funciones anteriores, para que la compilen correctamente,
es necesario que el tipo struct alumno haya sido declarado a nivel global en el programa.

EJERCICIO 7

Escribir tres funciones que permitan hacer las operaciones de suma, resta y multiplicación de
números complejos. El tipo complejo deberá definirse como una estructura.
Escribir además una función para leer un complejo de teclado y otra para mostrarlos en
pantalla.
Escribir finalmente un programa para comprobar el correcto funcionamiento de las funciones.

Análisis del problema


Un número complejo está formado por dos números reales, uno de ellos denominado parte
real y el otro parte imaginaria. La forma normal de representar en matemáticas un número
complejo s la siguiente: real + i * imaginaria, donde el símbolo i se denomina unidad
imaginaria y simboliza la raíz cuadrada de –1.
Debido a su naturaleza compuesta, un número complejo se puede representar de forma natural
por una estructura de dos campos de tipo real que contendrán la parte real y la imaginaria
respectivamente. Las funciones que siguen traducen las operaciones matemáticas tal y como
se definen en la aritmética de números complejos.

Funciones codificadas en C
struct complejo {
float real;
float imag;
};

struct complejo sumaComplejo (struct complejo a, struct complejo b)


{
INFORMÁTICA II – GRADO EN MATEMÁTICAS
Tema II.- Tipos Abstractos de Datos - 16 -

struct complejo c;
c.real = a.real + b.real;
c.imag = a.imag + b.imag;
return c;
};

struct complejo restaComplejo (struct complejo a, struct complejo b)


{
struct complejo c;
c.real = a.real - b.real;
c.imag = a.imag - b.imag;
return c;
};
struct complejo multiplicaComplejo (struct complejo a, struct complejo b)
{
struct complejo c;
c.real = a.real * b.real – a.imag * b.imag;
c.imag = a.real * b.imag + a.imag * b.real;
return c;
};

void leerComplejo (struct complejo *a)


{
struct complejo c;
printf("Introduzca la parte real : ");
scanf("%f", &c.real);
printf("Introduzca la parte imaginaria: ");
scanf("%f", &c.imag);
*a = c;
};

void mostrarComplejo (struct complejo a)


{
printf("%.2f", a.real);
if (a.imag < 0)
printf(" - %.2fi", -a.imag);
else printf(" + %.2fi", a.imag);
};

Hay que destacar que en todas las funciones anteriores, para que la compilen correctamente,
es necesario que el tipo struct complejo haya sido declarado a nivel global en el programa.

Programa completo codificado en C

Ver fuente COMPLEJO.C

EJERCICIO 8
Se desea calcular la edad y estatura máxima, mínima y media de la alineación inicial de un
equipo de fútbol.
Para ello se realizará un programa que pida por teclado el nombre, la edad y la estatura de los
11 jugadores. Una vez introducidos los datos, el programa presentará en pantalla:
〉 La estatura y edad media del equipo.
〉 La edad mínima del equipo y el número de jugadores con su nombre y estatura que la
poseen.
INFORMÁTICA II – GRADO EN MATEMÁTICAS
Tema II.- Tipos Abstractos de Datos - 17 -

〉 La estatura máxima del equipo y el número de jugadores con su nombre y edad que la
poseen.
Análisis
Se definirá una estructura llamada jugador, que contendrá los datos que recoge el programa
de cada jugador del equipo: su nombre, su edad y su estatura. Posteriormente se definirá un
vector, llamado equipo, de elementos de esta estructura. La dimensión de este vector se
definirá en función de una constante DIM, cuyo valor se fija en 11 (según el enunciado del
problema).
#define DIM 11
struct jugador {
char nombre [81];
int edad;
float talla;
};
struct jugador equipo[DIM];

equipo[0].nombre
equipo[0] equipo[0].edad
equipo[0].talla
equipo[1].nombre
equipo[1] equipo[1].edad
equipo[1].talla

equipo[DIM-1].nombre
equipo[DIM-1] equipo[DIM-1].edad
equipo[DIM-1].talla

Figura 4. Representación
gráfica del vector de estructuras equipo y sus miembros

Programa codificado en C

Ver fuente EQUIPO.C

Observaciones al programa anterior:


- strlen() es la función que calcula la longitud de una cadena de caracteres. Su archivo de
cabecera es string.h
- la sentencia for (i=1; i<=strlen(nombre_equipo); i++) printf("=");
escribe una línea de sobre subrayado (=) de la misma longitud que la cadena de
caracteres nombre_equipo.
- el especificador de formato printf ("%-30s %7d\n", nombre[i], edad[i])
permite mostrar en pantalla la cadena de caracteres nombre[i] en 30 posiciones y
justificada a la izquierda.
INFORMÁTICA II – GRADO EN MATEMÁTICAS
Tema II.- Tipos Abstractos de Datos - 18 -

Ejercicios propuestos

EJERCICIO 9
Un punto en el plano se puede representar mediante una estructura con dos campos. Escribir
un programa que mediante funciones que manejen estructuras que representen los puntos del
plano realice las siguientes operaciones.
§ Leer un punto de teclado
§ Presentar un punto en pantalla
§ Dados dos puntos, calcular la distancia entre ellos
§ Dados dos puntos, determinar el punto medio de la línea que los une.

Análisis del problema


Las coordenadas de un punto en el plano de dos dimensiones son dos números reales que se
representarán en forma de estructura. Es decir, por cada punto se define una estructura.
La distancia entre dos puntos se calcula como la raíz cuadrada de la suma del cuadrado de la
diferencia de sus coordenadas, es decir sqrt(pow(p1.x-p2.x, 2) + pow(p1.y-p2.y, 2))
El punto medio de la línea que los une se calcula
p3.x = (p1.x + p2.x) / 2
p3.y = (p1.y + p2.y) / 2

EJERCICIO 10
Escribir un programa para realizar aritmética fraccional. El usuario introduce una fracción
(numerador y denominador), una operación ( +, -, / ó * ) y otra fracción (numerador y
denominador); por ejemplo:
1 15 / 1 3
Debería dar lugar al resultado 3/15 (no 0.2).
Utilizar estructuras para trabajar con los números fraccionarios (numerador y denominador).

EJERCICIO 11

Diseñar un patrón de estructura, a nivel global, con los miembros adecuados para poder
almacenar
- el nombre de un mes
- una abreviatura de tres letras para el mismo
- el número de días del mes
- el orden de éste en el año

Escribir una función que defina localmente un array de 12 estructuras del tipo anterior,
iniciándolo para un año no bisiesto.

La función deberá recibir el número del mes, y el día dentro del mismo, y deberá devolver el
número total de días transcurridos en el año hasta a ese día.

También podría gustarte