referencias111

Anuncio
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
FUNDAMENTOS DE PROGRAMACIÓN
Tema 5
Estructuras Estáticas
1º Administración de Sistemas Informáticos
I.E.S. Francisco Romero Vargas
Departamento de Informática
__________________________________________________________________________________________________________
Estructuras Estáticas
0
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
1. INTRODUCCIÓN.
Hasta ahora, los datos manejados en los programas han sido los denominados
datos simples (numéricos, carácter, ...). En numerosas ocasiones es necesario utilizar un
conjunto de datos relacionados entre sí. Por ejemplo, si se quiere manipular una lista de
100 edades de personas, es conveniente tratar este conjunto de datos de forma unitaria
en lugar de utilizar 100 variables, una para cada edad.
Un conjunto de datos homogéneos (del mismo tipo) que se tratan como una sola
unidad se denomina estructura de datos.
Si una estructura de datos reside en la memoria central del ordenador se
denomina estructura de datos interna. Recíprocamente, si reside en un soporte
externo, se denomina estructura de datos externa.
Las estructuras de datos internas pueden ser de dos tipos:
- Estáticas:
Tienen un número fijo de elementos que queda determinado desde
la declaración de la estructura en el comienzo del programa.
- Dinámicas: Tienen un número de elementos que varía a lo largo de la
ejecución del programa.
La estructura de datos interna más importante, desde el punto de vista de su
utilización, es la tabla (array o arreglo), que existe en casi todos los lenguajes de
programación.
Esta estructura se corresponde con los conceptos matemáticos de vector (1
dimensión), matriz (2 dimensiones) y poliedro (3 o más dimensiones).
Una tabla consiste en un número fijo y finito de elementos, todos del mismo
tipo y bajo un nombre común para todos ellos.
Nombre
0
1
2
3
4
5
6
7
...
N-1 (índice)
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│Val.1│Val.2│Val.3│Val.4│Val.5│Val.6│Val.7│Val.8│ ... │Val.N│
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
↑
↑
1.er elemento
enésimo elemento
El nombre de la tabla es un identificador común para todos sus elementos
distinguiéndose cada uno por una lista de índices que complementan a dicho nombre
para referenciarlos individualmente.
Se denomina componentes a los elementos de una tabla.
Una tabla se puede estructurar en una, dos o más dimensiones, según el número
de índices necesarios para acceder a sus elementos. Por tanto, la dimensión de una tabla
coincide con el número de índices que utiliza.
Longitud o tamaño de una tabla es el número de componentes que contiene.
El tipo de una tabla es el tipo de sus componentes (numéricos, carácter, cadena,
etc).
Los componentes de una tabla se utilizan de la misma forma que cualquier otra
variable de un programa, pudiendo por tanto intervenir en instrucciones de asignación,
entrada/salida, etc.
Antes de utilizar una tabla habremos de definirla en el entorno.
Las tablas se clasifican según su dimensión en:
__________________________________________________________________________________________________________
Estructuras Estáticas
1
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
- Unidimensionales
- Bidimensionales
- Multidimensionales
2. DEFINICIÓN Y CONCEPTO DE TABLA.
Cuando en un programa el número de datos del mismo tipo, que mantengan una
relación “ordenada” entre ellos, aumenta un poco, no interesa definir una variable para
cada uno de ellos ya que la proliferación de las mismas llevaría a la confusión y
resultaría dificultoso su manejo. Por ejemplo, para hallar la media de diez notas no sería
eficiente definir diez variables de la forma n1, n2, n3 ...n10. Por tanto, para manejar en
memoria interna un número mediano o grande de datos es conveniente recurrir a
estructuras complejas de datos como son las tablas.
Se denomina tabla a un conjunto finito y fijo de elementos del mismo tipo,
que se hallan almacenados en posiciones consecutivas de memoria.
1. Cada uno de los elementos de una tabla se referencia por un nombre común a
todos ellos y por uno o varios índices particulares, que determinan su posición
relativa en la memoria, dentro del conjunto de elementos de la tabla. Hay que
tener en cuenta que en C el primer índice que se puede utilizar es el que tiene el
valor 0 y que el nombre de una tabla es un puntero a la dirección de
memoria de comienzo de la tabla .
Ejemplo:
Para guardar diez notas emplearemos el vector notas[10] con
capacidad para 10 notas. La primera nota se guarda en notas[0],
la segunda en notas[1],...y la décima en notas[9].
2. Todos los elementos de la tabla son del mismo tipo.
3. El nombre de una tabla (idéntico al de cada uno de sus elementos) sigue las
mismas reglas de formación que conocemos para identificadores de variables.
4. Los índices, dependiendo del lenguaje de programación que se utilice, pueden ir
encerrados entre paréntesis o entre corchetes. Concretamente, el lenguaje C
utiliza corchetes.
5. Los índices deben ser números enteros; señalan el orden relativo en que están
almacenados los elementos de la tabla. El número de índices determina la
dimensión de la tabla:
1 sólo índice = unidimensionales o vectores.
2 índices
= bidimensionales o matrices.
3 índices
= tridimensionales o poliedros.
6. Se llama longitud o tamaño de la tabla al número total de sus elementos.
Ejemplo:
Supongamos que en un programa necesitamos operar con la
cantidad de lluvia caída en una ciudad (en litros por metro
cuadrado) durante un mes. Para ello declaramos una tabla
__________________________________________________________________________________________________________
Estructuras Estáticas
2
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
unidimensional (vector) numérico real de 31 elementos que se
llamará ltrs_dia.
Se podría representar así:
10.455
ltrs_dia[0]
0.389
ltrs_dia[1]
1.923
ltrs_dia[2]
5.299
...
ltrs_dia[3] ...
Para acceder a la lluvia caída el 4º día escribiríamos ltrs_dia[3]
7. La tabla es una estructura interna, es decir, existe como tal estructura en la
memoria principal del ordenador. Como ya sabemos, la memoria principal tiene
una capacidad limitada, por tanto, las tablas serán conjuntos finitos.
8. La tabla es un conjunto fijo de elementos y, evidentemente, el número de
estos elementos depende del valor definido en el programa. Dicho en otras
palabras, el espacio que ocupará en memoria la tabla cuando el programa se esté
ejecutando no podrá cambiarse. Si se necesitara un número distinto de elementos
(otro tamaño) sería necesario editar el programa fuente, cambiar la definición de
la tabla y volver a traducir el programa. Por esto se dice que las tablas son
estructuras estáticas.
Ejemplo:
Si un programa necesitase operar con la temperatura media en
una ciudad a lo largo del año necesitaría una tabla bidimensional
(matriz) numérico real de 12 x 31 elementos que podría llamarse
Tmp. Podría representarse como una matriz matemática, donde
cada fila correspondería a un mes y cada columna a un día.
Los nombres de los elementos representados en la tabla son:
0
1
2
3
MESES
11
Tmp[0][0]
Tmp[1][0]
Tmp[2][0]
Tmp[3][0]
...
Tmp[11][0]
DIAS
0
1
Tmp[0][1]
Tmp[1][1]
Tmp[2][1]
Tmp[3][1]
...
Tmp[11][1]
2
Tmp[0][2]
Tmp[1][2]
Tmp[2][2]
Tmp[3][2]
...
Tmp[11][2]
...
...
...
...
...
...
...
30
Tmp[0][30]
Tmp[1][30]
Tmp[2][30]
Tmp[3][30]
...
...
Tmp[11][30]
El 1º índice representa la fila, y el 2º, la columna a que pertenece.
Para referenciar a la temperatura media del 3º día del 4º mes escribiríamos:
Tmp[3][2].
Sin embargo, la distribución de datos realizada en este ejemplo
no es obligatoria y se podía haber elegido otra: una matriz de 31 x 12
donde las filas corresponderían a los días y las columnas a los meses.
9. El hecho de que la tabla sea una estructura estática no representa ningún
problema si el número de elementos que se van a necesitar está predeterminado.
__________________________________________________________________________________________________________
Estructuras Estáticas
3
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
Ejemplo:
Para almacenar las ventas mensuales durante un año se
necesitará siempre un vector de 12 elementos: cada uno de los
elementos almacenará la venta realizada en un determinado mes.
Pero habrá muchas ocasiones en que no se conoce de antemano el
número de elementos necesario; en este caso se deberá prever una tabla con un
número suficiente de elementos, tendiendo siempre a sobredimensionar.
Ejemplo:
Un programa necesita guardar en un vector los nombres de los
distintos autores de los libros de que dispone una biblioteca de
1.000 volúmenes. No se sabe el número de autores distintos:
puede que cada libro sea de un autor distinto o puede que sólo
haya 100 autores distintos cada uno de los cuales haya escrito 10
de los libros que hay en esa biblioteca. Por ello, suponiendo que
se de el caso más desfavorable, habrá que declarar un vector de
1.000 elementos de tipo cadena. Obsérvese que si se da el otro
caso descrito se utilizará sólo el 10 % del tamaño del vector.
De todos modos, este tamaño del vector servirá sólo si el
programa se aplica a esa biblioteca; es decir, para otra
biblioteca distinta, con un número distinto de volúmenes, habría
que modificar el programa fuente para adecuar ese valor
máximo. Es conveniente pues declarar el valor que indica el
tamaño de la tabla como una constante de modo que sólo haya
cambiar un valor.
10. Hay que tener en cuenta que, al sobredimensionar, se está desperdiciando
memoria, sobre todo, si habitualmente no se utilizan todos los elementos de la
tabla.
Ejemplo:
Un programa debe almacenar en una tabla los nombres de las
asignaturas que imparte cada profesor de una ciudad y el curso a
quien lo imparte. Supongamos que hay, como mucho, 1000
profesores y cada uno puede tener asignadas un máximo de 10
asignaturas distintas. Se necesitará, por tanto, una tabla
bidimensional (matriz) de tipo cadena de 15 caracteres de 1000
filas (una por profesor) y de 10 columnas.
Si el número medio de asignaturas distintas asignadas a cada
profesor es 5, realmente se utilizará el 50 % del espacio ocupado
en memoria por la tabla; es decir, se desperdician un total de 5 *
1000 * 15 bytes = 75 Kb, aproximadamente. Seguramente la
estructura elegida no es la más adecuada.
11. Las operaciones que se suelen realizar habitualmente sobre una tabla son:
 Recorrido:
 Búsqueda:
Procesamiento de cada elemento de la tabla.
Obtener la posición ocupada por un elemento con un
determinado valor.
__________________________________________________________________________________________________________
Estructuras Estáticas
4
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
 Ordenación:
Organizar los elementos de la tabla de acuerdo con algún
criterio. Solo se realiza sobre tablas unidimensionales:
vectores.
También se pueden insertar y/o borrar elementos de la tabla, pero sólo de una
forma lógica, nunca física.
Puesto que las tablas son habitualmente fáciles de recorrer y de buscar en ellas y
de ordenar, suelen utilizarse para almacenar conjuntos de datos relativamente fijos.
3. TABLAS UNIDIMENSIONALES:VECTORES.

Concepto
Los vectores son tablas de una sola dimensión, es decir, cada elemento del
vector se referencia mediante el nombre de la tabla y un solo índice.
Los índices son números enteros y consecutivos que indican la posición relativa
de cada uno de los elementos dentro del vector. El valor del primer índice (en el
lenguaje C) es el 0 y no se puede variar.
El identificador de cada elemento (nombre e índice) determina la posición de
memoria donde se encuentra almacenado su contenido o valor.
El vector se denomina tabla unidimensional porque tiene un sólo índice de
referencia, es decir, una sola dimensión.

Definición
Para definir un vector es necesario indicar:
-
Clase de almacenamiento
Tipo de cada uno de los elementos
Identificador del vector
Número de elementos (entre corchetes, en C).
El formato es:
clase tipo identificador[num_elementos]
Ejemplo:
int meses[12];
Se está definiendo meses[] como un vector de tipo entero con 12 elementos.
Para referenciar cada uno de ellos se usarán los índices desde 0 hasta 11.
Es importante, pues, recordar que el 1º elemento de un vector corresponde al
índice 0.
La definición de un vector sirve, evidentemente, para indicar al compilador la
cantidad de memoria que tiene que reservar para los datos que vaya a contener. El
__________________________________________________________________________________________________________
Estructuras Estáticas
5
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
compilador lo calcula multiplicando el número de elementos por el espacio que ocupa
cada uno que dependerá del tipo del vector.
Pueden inicializarse tanto vectores globales (externos) como locales, sean
estáticos o no. Las tablas estáticas y las externas son inicializadas a 0 por defecto; o sea,
si no se les da ningún valor todos los elementos valdrán 0. Para inicializarlos se coloca
la lista de valores entre llaves y separados por comas.
Ejemplo:
short int meses[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
Cuando el número de valores es menor que el tamaño del vector, el resto de los
elementos no inicializados lo hacen a 0. En cambio, si el número de valores es mayor
que el tamaño declarado se produce un error.
Si se emplean corchetes vacíos cuando se inicializa un vector, el compilador
cuenta el número de valores de la lista, y ese será su tamaño.
short int meses[] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
Por otra parte, el operador sizeof proporciona el tamaño en bytes del vector.
Por ejemplo:
tam_array = sizeof meses;
//asignaría 24, ya que cada entero corto ocupa 2 bytes
Luego, para obtener el número de elementos de cualquier vector se usará en
general:
sizeof
identif_array
/ (sizeof
(tipo_array))
#include <stdio.h>
#include <conio.h>
short int meses[]={31,28,31,30,31,30,31,31,30,31,30,31};
void main(void)
{
int indice;
extern short int meses[]; //declaracion opcional
for(indice=0; indice < sizeof meses/(sizeof(short int));indice++)
printf ("Mes %2d = %d dias.\n", indice+1, meses[indice]);
getch();
}
En C no se comprueban los límites de las tablas: Cuando en un programa
queremos hacer referencia a un elemento de una tabla tenemos que colocar una
expresión entre los corchetes; pues bien, se supone que el programador habrá colocado
una expresión tal que no pueda tomar valores fuera del rango definido. El compilador
no se va a entretener en comprobar que el valor que toma esa expresión está dentro de
esos límites.

Paso de vectores a funciones.
Cuando se quiere pasar una tabla unidimensional a una función hay que pasarle
la dirección del primer elemento pues en C no se puede pasar el vector completo como
argumento a una función. El parámetro actual puede ser el nombre del vector o la
__________________________________________________________________________________________________________
Estructuras Estáticas
6
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
dirección de memoria del primer elemento. El parámetro formal se puede declarar como
un vector no delimitado (aunque también puede ser el puntero constante
correspondiente al nombre del vector –que estudiaremos más adelante- o un vector
delimitado). Las tres formas de hacerlo producen igual resultado, es decir, indican a la
función que se va a recibir un puntero al primer elemento de un vector.
A continuación se implementa una función que halla una media aritmética:
#include <stdio.h>
#include <conio.h>
#define NUM_ALUMNOS 10
float fmedia2 (float vector[] , int);
float fmedia (float vector[] , int);
void main(void)
{
float notas[NUM_ALUMNOS], nota_media;
int i;
for (i=0; i < NUM_ALUMNOS; i++ )
{
printf("NOTA %d : ",i+1);
scanf("%f", &notas[i]);
// scanf necesita la dirección
}
nota_media = fmedia (&notas[0], NUM_ALUMNOS);
//Tb. nota_media=fmedia(notas,NUM_ALUMNOS);
printf("Nota media = %5.2f ", nota_media );
getch();
}
/* fmedia es una función general que halla la media de los elementos
de cualquier vector de tipo entero. También es válido:
float fmedia (float vector[10], int num_elem )*/
float fmedia ( float vector[] , int num_elem )
{
float totnotas;
int indice;
for (indice=0, totnotas=0.0; indice<num_elem ; indice++)
totnotas += vector[indice];
return ( totnotas / num_elem ) ;
El vector notas[] es un vector de reales, local a la función principal y cuyo
tamaño es de 10 elementos. Sin embargo, el vector vector[] NO EXISTE. La
llamada a la función fmedia le pasa como argumento un puntero -una dirección-:
notas, o lo que es lo mismo, &notas[0]. Por tanto, todas las operaciones que
afectan a vector[] están trabajando realmente sobre el vector notas[].
Hay que tener en cuenta que la función fmedia no tiene forma de conocer el
tamaño del vector que se le ha pasado como parámetro. Luego la llamada a la función
fmedia tiene también que incluir como argumento el tamaño del vector.
Mejorando la función fmedia anterior.....
// continúa el Ejemplo anterior */
float fmedia2 ( float vector[] , int num_elem )
{
int indice;
float totnotas;
for (indice=0, totnotas = 0.0 ; indice < num_elem ; indice++)
totnotas+=vector[indice];
if (num_elem)
__________________________________________________________________________________________________________
Estructuras Estáticas
7
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
return ( totnotas / num_elem ) ;
else
return 0.0;
}
Nota:
Comunmente, en C se realiza el tratamiento de tablas mediante punteros, ya
que, como se ha mencionado anteriormente, el nombre de la tabla es, en realidad, un
puntero al primer elemento de la tabla. Con el fin de no confundir el uso de tablas con
el uso de punteros (algo más engorroso), por ahora sólo hemos usado las tablas de la
forma convencional. Al final de este tema, y cuando el alumno maneje sin dificultad las
tablas, se hará un extenso estudio del uso de punteros con ellas.
4. BÚSQUEDA Y ORDENACIÓN INTERNAS.
Una de las operaciones más utilizadas con colecciones de datos es la búsqueda
de un dato concreto de entre todos ellos. La eficiencia de una búsqueda dependerá
enormemente del grado de ordenación previa de la que dispongan los datos o de la idea
que podamos tener sobre la ubicación de la información a buscar; no es lo mismo
encontrar un libro en una biblioteca bien organizada que en un almacén de libros sin
clasificar. En cada caso debemos encontrar el método que mejor se adapte a nuestras
necesidades, sin embargo, existen una serie de algoritmos comunes tanto para la
búsqueda de un dato como para la ordenación de una colección de ellos. No hay que
desarrollar un algoritmo que funcione, hay que buscar el que lo haga de la mejor forma
posible. Entre los métodos de búsqueda estudiaremos los más clásicos:
Los algoritmos de búsqueda pueden ser:
- Para datos no ordenados:
Búsqueda lineal
- Para datos ordenados.
Búsqueda lineal
Búsqueda binaria o dicotómica
Los métodos de ordenación se pueden dividir, en una primera aproximación, en
dos tipos:
- Ordenación interna.- Ordenación externa.-
La que tiene lugar en la memoria del ordenador
utilizando estructuras tipo tabla.
Se realiza sobre elementos (registros de ficheros de
datos) almacenados en un dispositivo externo (no
en memoria), como pueden ser discos duros,
disquetes, etc.
Nosotros abordaremos en este tema tres métodos de ordenación interna sobre
vectores de elementos (aunque pueden aplicarse perfectamente sobre estructuras de
datos más complejas). La eficiencia de un método de ordenación suele determinarse en
base a dos factores: el número de comparaciones, C, y el número de movimientos de las
mismas, M. Ambos son función del número N de elementos que componen el vector a
ordenar.
Una clasificación de estos algoritmos puede ser la siguiente:
__________________________________________________________________________________________________________
Estructuras Estáticas
8
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
- Métodos directos:
Suelen ser algoritmos cortos y fáciles de entender, aunque
algo lentos. De entre ellos se estudiarán los señalados en
negrita:
- Método de inserción directa
- Método de selección directa
- Métodos de intercambio
- burbuja
- burbuja con switch
- sacudida
- con incrementos decrecientes. Método Shell.
- Métodos Avanzados:
Mucho más complejos que los anteriores. Entre
ellos encontramos el método QuickSort (qsort()),
basado en un algoritmo recursivo (técnica de
programación que permite la llamada de funciones
a sí mismas), que veremos en temas posteriores.
Todos los métodos relacionados aquí se utilizan con estructuras de datos internas
unidimensionales (tablas), es decir, no se utilizan para el caso de ficheros en disco.
Además, por claridad se utilizan datos numéricos en las tablas, lo cual no quiere decir
que no pueda hacerse con cualquier otro tipo de datos donde pueda establecerse una ley
de ordenación (caracteres, cadenas, etc).
Se considera que en los vectores no hay valores repetidos (considérense las
diferencias que puedan haber en cada caso si no se cumple esta premisa).

Algoritmos de búsqueda: Búsqueda lineal.
Las siguientes declaraciones las utilizaremos para la elaboración de todos los
algoritmos aquí descritos:
#define N 10
int v[N];
siendo N el número de elementos y v el vector.
Todos los algoritmos están expresados en forma de función, que devuelve el
índice del elemento a buscar o –1 en caso de que el elemento no se encuentre en el
vector.
Intuitivamente, el algoritmo de búsqueda lineal es el siguiente:
“Se recorre el vector desde el primer elemento al último hasta encontrar un
elemento cuyo valor coincida con el buscado o hasta que se acabe el vector. En este
último caso, el algoritmo debe indicar la no existencia de dicho valor en el vector”
int
Busqueda_Lineal_Desordenado(int
v[],int
elementos,
valor_a_buscar)
{
int i;
for (i=0;v[i]!=valor_a_buscar && i<elementos-1;i++);
if (v[i]==valor_a_buscar)
int
__________________________________________________________________________________________________________
Estructuras Estáticas
9
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
return (i);
else
return -1;
}
Para llamar a la función, y como ejemplo, podríamos usar el siguiente programa:
//Búsqueda Lineal en vectores desordenados
#include <stdio.h>
#define N 10
int
Busqueda_Lineal_Desordenado(int
v[],int
elementos,
valor_a_buscar)
{
int i;
for (i=0;v[i]!=valor_a_buscar && i<elementos-1;i++);
if (v[i]==valor_a_buscar)
return (i);
else
return -1;
}
main()
{
int v[N]={22,14,88,11,6,15,4,33,52,1};
int valor = 14;
int posicion=Busqueda_Lineal_Desordenado(v,N,valor);
if (posicion>-1)
printf("Encontrado en la posicion %d",posicion);
else
printf("No encontrado");
getchar();
}
int
Cuando el vector de búsqueda está ordenado se consigue un algoritmo más
eficiente con sólo modificar la condición de terminación de la instrucción for:
int
Busqueda_Lineal_Ord_Ascen(int
v[],int
elementos,
valor_a_buscar)
{
int i;
for (i=0;v[i]<valor_a_buscar && i<elementos-1;i++);
if (v[i]==valor_a_buscar)
return (i);
else
return -1;
}
int
La ventaja que se obtiene es que, una vez sobrepasado el valor buscado, no es
necesario recorrer el resto del vector para saber que el valor no existe.
En caso de haber valores repetidos, se encontrará el valor situado en primer
lugar según el orden ascendente del vector.
Sin embargo, para realizar una búsqueda sobre un vector ya ordenado es mucho
más ventajoso utilizar el algoritmo de búsqueda binaria o dicotómica pues el número
de intentos para encontrar un valor dado es drásticamente más bajo con la consecuente
mejora en velocidad, si bien, en caso de que el vector sea pequeño (10 elementos o
menos) una búsqueda lineal no es un mal recurso.
__________________________________________________________________________________________________________
Estructuras Estáticas
10
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________

Algoritmos de búsqueda: Búsqueda binaria o dicotómica.
Este algoritmo es válido sólo y exclusivamente para vectores ordenados y
consiste en “comparar en primer lugar con el componente central del vector que,
si no es igual al valor buscado, se reduce el intervalo de búsqueda a la mitad
derecha o izquierda, según donde pueda encontrarse el valor a buscar. El
algoritmo termina si se encuentra el valor buscado o si el tamaño del intervalo de
búsqueda queda anulado”.
En los casos en que existan repeticiones en el vector, del valor buscado, este
algoritmo obtendrá uno de ellos aleatoriamente según los lugares que ocupen, los cuales
necesariamente son consecutivos.
Se trata de una búsqueda similar a la de una palabra en un diccionario, donde
aprovechamos el orden alfabético para dirigirnos con rapidez al lugar donde puede estar
la palabra buscada.
Para su realización utilizamos tres variables que nos indican en qué zona del
vector nos encontramos. Son estas variables:
int izq, der, cen;
El vector v se supone ordenado ascendentemente:
int Busqueda_Dicotomica(int v[],int elementos, int valor_a_buscar)
{
int izq=0, der=elementos-1, cen=(izq+der)/2;
while (v[cen]!=valor_a_buscar && izq<der)
{
if (v[cen]>valor_a_buscar)
der=cen-1;
else
izq=cen+1;
cen=(izq+der)/2;
}
if (v[cen]==valor_a_buscar)
return cen;
else
return -1;
}

Ordenación por inserción: Inserción directa
También llamado método de la baraja. El método consiste en “tomar los
elementos del vector desde el segundo hasta el último y con cada uno de ellos
repetir el siguiente conjunto de operaciones:
1.- Se saca del vector el elemento I-ésimo (aux es una variable que lo
recibe).
2.- Desde el anterior al que estamos tratando y hasta el primero,
desplazamos un lugar a la derecha todos los que sean mayores para buscar su
hueco.
__________________________________________________________________________________________________________
Estructuras Estáticas
11
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
3.- Encontrado el hueco del elemento, lo insertamos en él.
Conviene observar que, cuando tratamos al elemento i-ésimo, todos los
anteriores se encuentran ordenados.”
- aux es una variable auxiliar del mismo tipo que los elementos del vector que
contendrá el valor del elemento i-ésimo que vamos a tratar.
- i apunta al elemento que vamos a tratar.
- j apunta a los elementos anteriores.
void Ordena_Insercion(int v[], int elem)
{
int i,j,aux;
for (i=1;i<elem;i++)
{
aux=v[i];
j=i-1;
while (v[j]>aux && j>0)
{
v[j+1]=v[j];
j--;
}
if (v[j]>aux)
{
v[j+1]=v[j];
v[j]=aux;
}
else
v[j+1]=aux;
}
}

Ordenación por intercambio: Intercambio directo o “burbuja”
Este método tiene dos versiones basadas en la misma idea, que consiste en
“recorrer sucesivamente el vector comparando los elementos consecutivos e
intercambiándolos cuando estén descolocados”. El recorrido del vector se puede
hacer de izquierda a derecha (desplazando los valores mayores hacia su derecha) o de
derecha a izquierda (desplazando los valores menores hacia su izquierda), ambos para la
clasificación en orden ascendente. A continuación veremos el método con recorrido
izquierda-derecha.
Consiste en realizar pasadas sucesivas direccionando desde el primer elemento
hasta el penúltimo, comparando cada uno de ellos con el siguiente.
Esta versión del método va colocando en cada pasada el menor elemento de los
tratados en la primera posición, quedando colocado y por tanto excluido de los
elementos a tratar en la siguiente pasada:
- i cuenta el número de pasadas.
- j apunta al elemento a tratar.
- aux se utiliza para los intercambios.
void Ordena_Burbuja(int v[], int elem)
{
__________________________________________________________________________________________________________
Estructuras Estáticas
12
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
int i,j,aux;
for (i=0;i<elem-1;i++)
for (j=elem-1;j>i;j--)
if (v[j]<v[j-1])
{
aux=v[j];
v[j]=v[j-1];
v[j-1]=aux;
}
}

Ordenación por intercambio: Intercambio directo mejorado o “burbujaswitch”
Es una mejora de los métodos de intercambio directo en la que se comprueba
mediante un switch (interruptor o bandera) si el vector está totalmente ordenado
después de cada pasada, terminando la ejecución en caso afirmativo.
La comprobación de la ordenación en cada pasada consiste en detectar si se han
producido intercambios o no, de tal forma que sólo se realizarán las pasadas necesarias
que dependerán del grado de desorden existente en los datos iniciales.
void Ordena_Burbuja_Switch(int v[], int elem)
{
int i,j,aux,sw;
i=0;
sw=1;
while (i<elem-1 && sw)
{
sw=0;
for (j=elem-1;j>i;j--)
if (v[j]<v[j-1])
{
aux=v[j];
v[j]=v[j-1];
v[j-1]=aux;
sw=1;
}
i++;
}
}

Ordenación por intercambio: Intercambio con incrementos decrecientes o
“Shell”
El método burbuja acerca cada elemento a la posición que le corresponde paso a
paso. Su tiempo de ejecución para vectores pequeños puede ser aceptable.
Un algoritmo mucho más eficaz y más apropiado para la ordenación de grandes
vectores es la ordenación Shell, denominado así en honor a su inventor. Consiste en
comparar, no elementos consecutivos como lo hacía el de la burbuja, sino los que están
separados por un intervalo grande, de modo que cada uno se acerca al lugar que le
corresponde de forma más rápida. Inicialmente, ese intervalo o salto corresponde con la
mitad de la longitud del vector. Posteriormente, cuando ya todos los elementos
separados por esa distancia están ordenados, se divide ese intervalo por dos y se opera
__________________________________________________________________________________________________________
Estructuras Estáticas
13
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
de igual forma hasta que, finalmente, el salto se reduzca a 1. Entonces, el proceso de
ordenación funciona exactamente como el de la burbuja: comparando elementos
adyacentes.
Los elementos que vamos a utilizar dentro de nuestro algoritmo son los
siguientes:
d es una variable que indica la distancia de comparación.
sw comprueba la ordenación a distancia d.
1 = desordenado a distancia d.
0 = ordenado a distancia d.
void Ordena_Shell(int v[], int elem)
{
int i,d,sw,aux;
d=elem;
while (d!=1)
{
d/=2;
sw=1;
while (sw)
{
sw=0;
for (i=0;i<elem-d;i++)
if (v[i]>v[i+d])
{
aux=v[i];
v[i]=v[i+d];
v[i+d]=aux;
sw=1;
}
}
}
}
EJERCICIO.Como ejercicio de tratamiento de vectores, el alumno debe implementar un
algoritmo de ordenación que no se ha visto anteriormente: la ordenación por Selección
Directa. A continuación se expresa con palabras su funcionamiento:
El método consiste en “repetir el siguiente proceso desde el primer elemento
hasta el penúltimo: se selecciona el componente de menor valor de todos los
situados a la derecha del tratado y se intercambia con éste”.
En realidad se trata de sucesivas búsquedas del menor de los elementos que
quedan por ordenar.
Para la realización del intercambio se utiliza una variable auxiliar aux.
5. CADENAS.
El lenguaje C no dispone de un tipo especial para cadenas, sino que las cadenas
son vectores de caracteres (de tipo char) que terminan con el carácter nulo, o sea,
‘\0‘ .
De todos modos, el lenguaje C soporta la mayoría de las funciones más potentes
de manipulación de cadenas que aparecen en cualquier lenguaje.
Existen muchas formas diferentes de definir en C una cadena o tira. Veámoslas.
__________________________________________________________________________________________________________
Estructuras Estáticas
14
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________

Cadenas constantes
Cualquier conjunto de caracteres encerrados entre comillas es una cadena
constante. Los caracteres que estén encerrados entre las comillas, junto con un carácter
'\0', se almacenan en posiciones adyacentes de memoria. No es necesario añadir de
forma manual el carácter nulo al final de las constantes de cadena: el compilador de C lo
hace de forma automática; de igual modo, cuenta el número de caracteres de la cadena
de forma que conoce de antemano cuánta memoria va a necesitar para su
almacenamiento. El modo de almacenamiento es static.
Se utilizan cadenas constantes como argumentos de las funciones puts(),
printf(), etc..
Nota:
La función puts() muestra en pantalla la cadena que se le pasa
como argumento seguida de un carácter de salto de línea.
También las constantes cadena pueden ser asignadas a macros:
Ejemplo:
#define VOCALES "aeiou"
.........
puts(VOCALES);
puts("Esta es una tira");
printf(“%s\n%s\n”, VOCALES, "Esta es otra tira");
La frase entera entrecomillada actúa como puntero al lugar donde se ha
almacenado la misma.
Ejemplo:
printf("%s ,%u, %c\n","Domínguez","Delgado",*"a tí dedicado");
dará como resultado: Domínguez,
4239842, a
Al representar la cadena "Delgado" como entero sin signo obtenemos la
dirección a partir de la cual está almacenada. Por otra parte, si aplicamos el operador
de indirección (*) a la 3ª cadena obtenemos el contenido de la dirección donde apunta
dicha cadena, o sea, el primer carácter de la propia cadena.

Vectores de caracteres.
Para inicializar un vector de caracteres se escribe...
char tira1[]= {'L','e','n','g','u','a','j','e',' ','C','\0'};
static char tira2[]= {'L','e','n','g','u','a','j','e',' ','B','\0'};
extern char tira3[]= {'L','e','n','g','.',' ','C',’+’,’+’,'\0'};
Observe el carácter nulo al final de la cadena.
Sin embargo, existe una forma más corta de inicialización:
char tira1[] = "Lenguaje C";
static char tira2[] = "Lenguaje B";
__________________________________________________________________________________________________________
Estructuras Estáticas
15
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
extern char tira3[]
= "Leng. C++”;
Al igual que en otro tipo de vectores, tampoco aquí es necesario indicar el
tamaño del vector puesto que el compilador cuenta los caracteres y prepara el tamaño
correspondiente.
Si al declarar un vector de caracteres se especifica su tamaño, hay que tomar la
precaución de que el número de elementos declarados sea como mínimo superior en 1
(el correspondiente al carácter nulo) a la longitud de la cadena con que se inicializa. Si
el tamaño es inferior a dicho mínimo se producirá un error; si es superior, los elementos
sobrantes se inicializan a '\0'.
Habrá casos en que se declare un vector y no se inicialice, por ejemplo:
char nombre[81];
donde nombre es un vector para ser leído en tiempo ejecución. Aquí se tiene que
declarar obligatoriamente el tamaño, y se deberá controlar la entrada de caracteres para
que su número no sobrepase el espacio reservado (el tamaño menos 1). En el ejemplo
anterior, nombre puede almacenar hasta 80 caracteres como máximo más el carácter
nulo; en total, 81 caracteres.
6. FUNCIONES DE E/S PARA CADENAS.
Anteriormente hemos estudiado y usado las funciones scanf() y printf(),
que permiten la entrada y la salida, respectivamente, de diferentes tipos de datos, entre
ellos, de las cadenas. Ahora estudiaremos la funciones gets() y puts() cuya misión
es, respectivamente, leer y escribir cadenas de caracteres.

Función gets()
La función gets() captura cadenas desde el teclado; la entrada termina al
pulsar INTRO. Los errores cometidos al teclear la cadena pueden ser borrados
utilizando la tecla de retroceso antes de pulsar la tecla Intro.
La cadena es colocada en la dirección apuntada por su argumento, un puntero a
carácter. El último carácter pulsado, o sea, el retorno de carro ( ‘\r’ ) no pasa a formar
parte de la cadena, siendo sustituido por el carácter nulo ( ‘\0’ ).
A diferencia de scanf(), la función gets() sí permite que se introduzcan
espacios en blanco al entrar la cadena.
Su prototipo es:
char *gets (char *cadena) ;
Como se puede apreciar, esta función devuelve un puntero a la cadena leída.
Un problema importante que puede aparecer al usar esta función es sobrepasar
los límites de la tabla que se le pasa como argumento, ya que la función no tiene forma
de saber cuando se alcanzan los limites de la tabla. Si, por ejemplo, se introducen 21
caracteres (contando el nulo) cuando sólo se han reservado para la cadena 20, se
producirán errores, incluso la caída del sistema. Como alternativa, y para evitar este tipo
de problemas, se puede usar la función fgets() que se estudiará más adelante.
__________________________________________________________________________________________________________
Estructuras Estáticas
16
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________

Función puts()
La función puts() da salida sólo a cadenas y por ello es más simple que
printf() por lo que deberemos emplearla siempre que sea posible pues así se añade
menos código a nuestro programa y se ejecuta más rápidamente que si se emplea esta
última.
Hay que tener en cuenta que puts() añade automáticamente un retorno de
carro, lo que no hace printf()
Su prototipo es:
int
puts (char * cadena) ;
Esta función devuelve 0 si se ejecuta correctamente y otro valor en caso
contrario.
#include <stdio.h>
#include <conio.h>
void main (void)
{
char nom_mes[16], nom_dia[21], nom_ape[51];
puts("Introduzca cada dato seguido de INTRO");
puts("(si se permiten espacios)");
puts("");
puts("Nombre y apellidos (max. 50 car.): ");
gets(nom_ape);
puts("Nombre de un mes (max. 15 car.): ");
gets(nom_mes);
puts("Nombre de un día de la semana (max. 20 car.): ");
gets(nom_dia);
printf("\n\n");
puts(nom_ape);
puts("encuentre los días de este año que caen en ...");
puts (nom_dia);
puts ("y pertenecen al mes...");
puts (nom_mes);
getch();
}
7. FUNCIONES PARA TRATAMIENTO DE CADENAS.
Las siguientes funciones utilizan el archivo de cabecera string.h donde se
encuentra las declaraciones de sus prototipos.

Función strcat()
char *strcat (char *cad1, const char *cad2);
Esta función concatena una copia de cad2 al final de cad1 y añade al final de
cad1 un carácter nulo. El carácter nulo que inicialmente finalizaba la cadena cad1 es
sobrescrito por el primer carácter de cad2. La cadena cad2 no se modifica con esta
operación. Esta función devuelve cad1. Resumiendo, al final en cad1 queda: cad1 +
cad2.
__________________________________________________________________________________________________________
Estructuras Estáticas
17
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
Téngase en cuenta que no se realizan comprobaciones de límites y, por tanto, es
responsabilidad del programador asegurar que cad1 es lo suficientemente grande como
para almacenar su contenido original y el contenido de cad2.

Función strcmp()
int strcmp (const char *cad1, const char *cad2);
Esta función compara de forma lexicográfica (tiene en cuenta el orden
establecido por la tabla ASCII) dos cadenas que finalizan con un carácter nulo y
devuelve un entero que se interpreta así:
Menor que 0
cad1 es menor que cad2
0
cad1 es igual que cad2
Mayor que 0
cad1 es mayor que cad2

Función strcpy()
char *strcpy (char *cad1, const char *cad2);
Esta función se utiliza para copiar el contenido de cad2 en cad1; cad2 debe ser
un puntero a una cadena que termine en un carácter nulo. Además, devuelve un puntero
a cad1.
Si cad1 y cad2 se solapan, el comportamiento de la función es indefinido.

Función strncat()
char *str ncat(char* cad1,const char* cad2,size_t cuenta);
El tipo size_t está definido, mediante typedef, como un entero sin signo.
Esta función concatena, a la cadena apuntada por cad1, un máximo cuenta
caracteres de la cadena apuntada por cad2 y coloca al final de cad1 un carácter nulo. El
carácter nulo de fin de cadena que, inicialmente, finalizaba cadena cad1 se sustituye por
el primer carácter de cad2.
Esta función no modifica la cadena cad2.
La función strncat devuelve cad1.
Recuérdese que no se realizan comprobaciones de límites y, por tanto, es
responsabilidad del programador asegurar que cad1 tiene el tamaño suficiente
almacenar su contenido original y el de cad2.

Función strncpy()
char *strncpy(char *dest,const char *fuente,size_t cuenta);
Esta función se utiliza para copiar un máximo de cuenta caracteres de la cadena
apuntada por fuente a la cadena apuntada por dest. La cadena fuente debe ser un puntero
a una cadena terminada con un carácter nulo.
La función strncpy devuelve un puntero a dest.
__________________________________________________________________________________________________________
Estructuras Estáticas
18
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
Cuando se solapan las cadenas dest y fuente, el comportamiento de la función
strncpy es indefinido.
Si la cadena apuntada por fuente tiene un número de caracteres menor que
cuenta, se añaden caracteres nulos al final de dest hasta que se hayan copiado los cuenta
caracteres.
Alternativamente, cuando la cadena apuntada por fuente tiene un número de
caracteres superior a cuenta, se copian cuenta caracteres al principio de dest;
evidentemente, a continuación del último copiado están los caracteres que contenía
inicialmente la cadena fuente.

Función strnset()
char *str nset (char *cad, int c, size_t cuenta);
Esta función define los primeros cuenta caracteres de la cadena apuntada por cad
con el valor de c. Esta función devuelve cad.

Función strstr()
char *strstr (const char *cad1, const char *cad2);
Esta función devuelve un puntero a la primera ocurrencia de la cadena apuntada
por cad2 (sin considerar el carácter nulo de fin de cadena) dentro de la cadena apuntada
por cad1. Devuelve un puntero nulo si no encuentra ninguna coincidencia.
8. MACROS Y
CARACTERES.
FUNCIONES
PARA
TRATAMIENTO
DE
Las siguientes macros, y también las funciones, que se describen a continuación,
necesitan incluir el archivo de cabecera ctype.h. En éste se encuentra las
declaraciones de sus prototipos.

Macro isalnum ( )
int isalnum (int c);
Devuelve un valor distinto de 0 si su argumento es una letra del alfabeto
(mayúscula o minúscula) o un dígito; en caso contrario, o sea, si el carácter no es
alfanumérico devuelve 0.

Macro isalpha ( )
int isalpha (int c);
Devuelve un valor distinto de 0 si su argumento es una letra del alfabeto
(mayúscula o minúscula); en caso contrario, o sea, si el carácter no es una letra devuelve
0.

Macro isdigit ( )
__________________________________________________________________________________________________________
Estructuras Estáticas
19
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
int isdigit (int c);
Devuelve un valor distinto de 0 si su argumento es un dígito (un valor del ‘0' al
‘9'); en caso contrario, devuelve 0.

Macro islower ( )
int islower (int c);
Devuelve un valor distinto de 0 si su argumento es una letra minúscula (de la
«a» a la «z»); en caso contrario, devuelve 0.

Macro ispunct ( )
int ispunct (int c);
Devuelve un valor distinto de 0 si su argumento es un carácter de puntuación o
un espacio en blanco; en caso contrario, devuelve 0.

Macro isspace ( )
int isspace (int c);
Devuelve un valor distinto de 0 si su argumento es un espacio en blanco, un
retorno de carro, un tabulador horizontal, un tabulador vertical, un carácter de salto de
línea o un carácter de nueva línea; en caso contrario, devuelve 0.

Macro isupper ( )
int isupper (int c);
Devuelve un valor distinto de 0 si su argumento es una letra mayúscula (de la
«A» a la «Z»); en caso contrario, devuelve 0.

Función tolower ( )
int tolower (int c);
Si el argumento «c» es un letra mayúscula, esta función devuelve la letra
minúscula equivalente a «c»; en cualquier otro caso, devuelve «c» sin modificar.

Función toupper ( )
int toupper (int c);
Si el argumento «c» es un letra minúscula, esta función devuelve la letra
mayúscula equivalente a «c»; en cualquier otro caso, devuelve «c» sin modificar.
__________________________________________________________________________________________________________
Estructuras Estáticas
20
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
9. TABLAS BIDIMENSIONALES: MATRICES.

Definición. Inicialización. Acceso.
Las tablas bidimensionales o matrices se declaran utilizando el formato general:
tipo nombre_array[tamaño_primera_dimension][tamaño_segunda_dimension];
Ejemplo: Para almacenar datos de la lluvia caída cada mes durante 5 años definimos:
float lluvia [5][12];
donde el vector principal tendría 5 elementos, que serían a su vez, vectores de 12
elementos.
Para inicializar una matriz se colocan los valores de cada fila entre llaves y
separados por comas. Los valores de diferentes filas se separan por comas. Todo el
conjunto se encierra entre un par de llaves externo.
Ejemplo:
La definición...
int puntos[3][4]={{1,9,3,8},{2,6,4,6},{9,0,1,2}};
dará como resultado la siguiente matriz:
F
I
L
A
S
COLUMNAS
0
0
1
1
2
2
9
1
9
6
0
2
3
4
1
3
8
6
2
Ocurre que si entre un par de llaves hay más elementos de los declarados se
producirá un error; pero si hay menos, los elementos restantes se incializarán a 0 por
defecto.
Ejemplo:
La definición...
int puntos [4][5]={ {1,2} , {5,6,7,2,0} , {9,0,4} };
dará como resultado la siguiente matriz:
0
1
2
3
0
1
5
9
0
1
2
6
0
0
2
0
7
4
0
3
0
2
0
0
4
0
0
0
0
Es posible inicializar la matriz colocando sólo el par de llaves externos.
Ejemplo:
La definición equivalente a la anterior es...
int puntos [4] [5] = { 1,2,0,0,0,5,6,7,2,0,9,0,4};
__________________________________________________________________________________________________________
Estructuras Estáticas
21
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
Hay que tener en cuenta que cuando no se colocan llaves internas la tabla
bidimensional se va llenando en orden por filas.
Ejemplo:
La definición...
int puntos [3] [4] = {1,2,5,6,7,2};
dará como resultado la siguiente matriz:
0
1
7
0
0
1
2
1
2
2
0
2
5
0
0
#include <stdio.h>
#include <conio.h>
#define MAX_ALUMNOS 15
#define MAX_ASIGNATURAS
void main(void)
{
3
6
0
0
6
int i, j, notas[MAX_ALUMNOS][MAX_ASIGNATURAS]={{6,7,6},{5,3,2},{7,5,4,2,3}};
printf("ALUMNO
RAL
FP
SMM
FOL
REL
for (i = 0 ; i < MAX_ALUMNOS ; i++)
{
printf("\n%4d) ", i+1); //numero del alumno
for (j = 0 ; j < MAX_ASIGNATURAS ; j++)
printf("%8d", notas[i][j]);
}
getch();
}

IEA\n\n");
Almacenamiento en memoria de tablas multidimensionales
En la representación gráfica anterior hemos podido observar la forma en que las
tablas bidimensionales se almacenan en memoria: ordenadamente por filas, es decir, que
cuando se accede a sus elementos de forma consecutiva, el índice de más a la derecha
cambia más rápido que el de la izquierda. Lo mismo se puede decir para las tablas de
más dimensiones. Por ejemplo: para una tabla tridimensional trid [3][5][2] el orden en
que se guardarían en memoria sus elementos sería...
trid [0][0][0] trid [0][0][1] trid [0][1][0] trid [0][1][1] trid [0][2][0] trid [0][2][1]...

Paso de tablas bidimensionales a funciones
Cuando se utiliza una tabla bidimensional como argumento de una función, se
pasa un puntero al primer elemento del mismo. Sin embargo, una función que recibe
como argumento una tabla bidimensional debe definir como mínimo la longitud de la
segunda dimensión, debido a que el compilador necesita conocer la longitud de cada fila
para indexar la tabla correctamente: Si no se conoce la longitud de las filas, es imposible
saber dónde comienza la siguiente fila. También se puede especificar la primera
dimensión, pero no es necesario.
#include <stdio.h>
__________________________________________________________________________________________________________
Estructuras Estáticas
22
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
#include <conio.h>
#include <ctype.h>
#define ASIGNAT 3
#define ALUMNOS 5
void ver_notas(int n[][ALUMNOS]);
void leer_notas(int n[][ALUMNOS]);
void main(void)
{
char ch;
int notas[ASIGNAT][ALUMNOS]={0};
do
{
do
{
clrscr();
printf("(E)ntrar notas\n");
printf("(M)ostrar notas\n");
printf("(S)alir\n");
ch = toupper(getch());
}
while(ch!='E' && ch!='M' && ch!='S');
clrscr();
switch(ch)
{
case 'E':
leer_notas(notas);
break;
case 'M':
ver_notas(notas);
break;
}
}
while (ch != 'S');
}
//*****************************************************
void leer_notas(int n[][ALUMNOS])
{
int asig, i, nota;
for(asig=0; asig < ASIGNAT; asig++)
{
printf("\n\nAsignatura %d: \n", asig + 1);
for(i=0; i< ALUMNOS; ++i)
{
do
{
printf("\nAlumno %d : ", i+1);
nota = getche();
}
while (nota <'0' || nota >'9');
n[asig][i] = nota -'0';
//Equivale scanf("%d", n[asig]+i);
}
}
}
//*****************************************************
void ver_notas (int g[][ALUMNOS])
{
int asig, i;
for(asig=0; asig < ASIGNAT; ++asig)
{
printf("\n\nAsignatura %d: \n", asig + 1);
for(i=0; i < ALUMNOS; ++i)
printf("%d) %d ",i+1, g[asig][i]);
}
__________________________________________________________________________________________________________
Estructuras Estáticas
23
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
getch();
}
10. TABLAS TRIDIMENSIONALES: POLIEDROS.
Las tablas tridimensionales se declaran utilizando el formato general:
tipo nombre_array [tamaño_1ra_dim] [tamaño_2da_dim] [tamaño_3ra_dim];
#define FILA 3
#define COLU 4
#define PAGI 2
void ver_array( int [][COLU][PAGI], int , int , int );
void main(void)
{
int tridi[FILA][COLU][PAGI]={{{9,10},{11,12},{13,14},{15,16}},
{{17,18},{19,20},{21,22},{23,24}},
{{25,26},{27,28},{29,30},{31,32}}};
int f, c, p ;
for (p=0; p< PAGI; p++)
//Muestra el poliedro por páginas
{
printf("PAGINA %d\n", p);
for (f=0; f < FILA; f++)
{
for (c=0; c < COLU ; c++ )
printf("%5d", tridi[f][c] [p]);
printf("\n");
}
}
for (p=0; p< PAGI; p++)
//los bucles se pueden poner en
for (f=0; f< FILA; f++)
// cualquier orden
for (c=0; c < COLU ; c++ ) tridi[f][c][p] += 5 ;
//Suma 5 a cada elemento
printf("\n\nEl array modificado es...\n");
ver_array (tridi, FILA, COLU, PAGI);
getch();
}
//*****************************************
void ver_array(int arr[][COLU][PAGI], int fil, int col, int pag )
{
int p,f,c;
for (p=0; p< pag; p++) //Muestra el poliedro por páginas
{
printf("PAGINA %d\n", p);
for (f=0; f < fil; f++)
{
for (c=0; c < col ; c++ )
printf("%5d", arr[f][c] [p]);
printf("\n");
}
}
}
Al igual que ocurre con las tablas bidimensionales, cuando se pasa una tabla
tridimensional a una función, el argumento efectivo es el nombre de la tabla y en los
argumentos formales se puede especificar una tabla en la que hay que especificar
obligatoriamente todas las dimensiones, excepto la primera.
__________________________________________________________________________________________________________
Estructuras Estáticas
24
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
11. CONCEPTO Y DEFINICIÓN DE ESTRUCTURAS.
Una estructura es un conjunto de variables a las que se hace referencia bajo
un mismo nombre, siendo una forma eficaz de mantener agrupada una información
relacionada. Las variables que componen la estructura se llaman miembros de la
estructura, o también, elementos o campos.
Una declaración de estructura forma una plantilla que puede utilizarse para crear
estructuras de objetos.
La palabra reservada struct indica al compilador que se va a definir una
estructura.
En general, cada miembro de la estructura está relacionado con el resto.
Ejemplo:
En una lista de personas la información relativa al nombre, dirección, etc. se
representa, normalmente, como una estructura. En el siguiente fragmento de
código se muestra cómo declarar una estructura como una plantilla que
contenga dichos campos.
struct agenda
{
char nombre[30];
char calle[40];
char ciudad[20];
char provincia[15];
char codigo[5];
char telefono[9];
int importe;
};
La declaración termina con un punto y coma ya que la declaración de una
estructura es una instrucción.
El nombre de la estructura (agenda, en nuestro ejemplo) identifica esta estructura
de datos concreta y su identificador de tipo. El nombre de la estructura también se
denomina etiqueta.
Hasta ahora no se ha creado ninguna variable, sólo se ha definido la forma de los
datos. Para declarar una variable con la estructura anterior, se debería escribir...
struct agenda clientes_morosos;
Esto declara una variable llamada clientes_morosos del tipo de la
estructura agenda.
Cuando se declara una estructura, se está definiendo un tipo de variable
compuesta. Hasta que no se declara una variable de ese tipo, realmente no existe
ninguna.
Cuando se declara una variable del tipo de estructura, el compilador reserva
automáticamente el espacio de memoria necesario para cada uno de sus miembros.
Al definir una estructura, también se pueden declarar una o más variables.
__________________________________________________________________________________________________________
Estructuras Estáticas
25
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
Ejemplo:
struct mini_agenda
{
char nombre[30];
char telefono[9];
} amigos, clientes, colegas;
Es importante tener siempre presente que cuando se crea una variable de un tipo
estructura, se mantiene una copia de cada miembro de la misma. Por ejemplo, el campo
telefono de clientes está en una zona de memoria distinta y es diferente al campo
telefono de amigos. De hecho, la única relación que existe entre amigos y clientes es
que ambos son una instancia del mismo tipo de estructura. No existe ninguna otra
relación entre ambas.
Si sólo se necesita una variable de un tipo de estructura, no es necesario indicar
la etiqueta al definir la estructura. Esto significa que
struct
{
char titulo[100];
char director[50];
int precio;
} pelicula ;
declara una variable llamada pelicula del tipo de estructura que le precede.
El formato general de declaración de una estructura es
struct etiqueta
{
tipo nombre_variable;
tipo nombre_variable;
tipo nombre_variable;
.............
} variables_de_estructura ;
La etiqueta es un nombre del tipo de la estructura, no un nombre de variable. Por
otra parte, variables_de_estructura es una lista de variables separadas por comas.
Recuérdese que, aunque la etiqueta y las variables_de_estructura son opcionales, es
obligatorio especificar, al menos, una de ellas.

Referencia a los miembros de una estructura.
Para hacer referencia a cada miembro de una estructura se utiliza el operador .
(«punto»).
Ejemplos:
strcpy (cliente_morosos.codigo, “11995");
__________________________________________________________________________________________________________
Estructuras Estáticas
26
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
strcpy (amigos.telefono , “956998877");
pelicula.precio=3000;
gets(pelicula.titulo);
puts(cliente.nombre);
scanf(“%d”, &pelicula.precio);
scanf(“%s”, pelicula.director);
Un miembro de la estructura se referencia indicando el nombre de variable de la
estructura, seguido por un punto y, por último, el nombre del miembro. El formato
general es, por tanto:
nombre_de_estructura . nombre_de_miembro

Asignaciones de estructuras.
La información contenida en una estructura se puede asignar a otra del mismo
tipo mediante una única instrucción de asignación. Es decir, no es necesario asignar
valor a valor cada miembro de la estructura.
Ejemplo:
colegas = amigos;
Esto hace que los miembros de colegas tengan los mismos valores que los
miembros de amigos.

Tablas de estructuras.
Posiblemente, la utilización más común de las estructuras son las tablas de
estructuras. Para declarar una tabla de estructuras, se debe definir primero la estructura
y, a continuación, declarar una variable tabla de dicho tipo. Por ejemplo, para declarar
un vector de 100 elementos del tipo pelicula (declarado anteriormente) se debería hacer
de la siguiente forma:
struct pelicula peli_cienciaficc [100];
Esto crea 100 variables con la organización de la estructura de tipo pelicula.
Para acceder a una determinada estructura del vector peli_cienciaficc, se indexa
el nombre de la variable vector. Por ejemplo, para mostrar el precio de la tercera
estructura, se puede hacer lo siguiente
printf (“%d”, peli_cienciaficc[2].precio);
Como ocurre con todas las variables de tipo array, los arrays de estructuras
comienzan con índice 0.
__________________________________________________________________________________________________________
Estructuras Estáticas
27
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________

Paso de estructuras a funciones.
Cuando se pasa un miembro de una estructura a una función, lo que realmente se
está pasando a la función es el valor de dicho miembro. Por tanto, se está pasando una
variable simple. Sin embargo, si se desea pasar la dirección de un miembro de la
estructura, para conseguir el paso de un parámetro por referencia, se debe colocar el
operador & delante del nombre de la estructura.
Ejemplos:
fsuma (pelicula.precio);
fdescuento (&pelicula.precio);
fimprime (pelicula.titulo[i]);
fmayusculas (&pelicula.titulo[i]);
fquitaespacios (pelicula.titulo);
//pasa el valor de precio
//pasa la dirección de precio
//pasa el valor de titulo[i]
//pasa la dirección de titulo[i]
//pasa la dirección de la cadena
//titulo
Obsérvese que el operador & precede al nombre de la estructura, no al
nombre del miembro. También se puede apreciar que el vector titulo ya indica una
dirección, de forma que no es necesario el &. Sin embargo, cuando se accede a un
carácter concreto de la cadena titulo, el operador & es necesario.
Cuando se utiliza una estructura como argumento de una función, ésta se pasa de
forma íntegra mediante el método estándar de llamada por valor. Esto significa que
cualquier modificación del contenido de la estructura que se realice dentro de la función
a la que se pasa, no afectará a la estructura utilizada como argumento.
Cuando se utilice una estructura como parámetro, el aspecto más importante a
tener en cuenta es que el tipo del argumento debe coincidir con el tipo del parámetro. La
mejor forma de conseguir esto consiste en definir una estructura global y, a
continuación, utilizar su nombre de etiqueta para declarar variables de estructura y
parámetros cuando se necesiten.
#include <stdio.h>
#include <conio.h>
#include <math.h>
#define PI 3.14159265358979
struct circulo
{
double xi, yi, xf, yf;
};
void calculos_circulo(struct circulo);
void main(void)
{
struct circulo c1;
clrscr();
printf("Coordenadas del circulo: \n");
printf("
Centro x: ");
scanf("%lf", &c1.xi);
printf("
Centro y: ");
scanf("%lf", &c1.yi);
printf("Pto. exterior x: ");
scanf("%lf", &c1.xf);
printf("Pto. exterior y: ");
scanf("%lf", &c1.yf);
calculos_circulo (c1);
getch();
}
__________________________________________________________________________________________________________
Estructuras Estáticas
28
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
void calculos_circulo( struct circulo circ)
{
double radio, area, proy_x, proy_y, circunferencia;
proy_x = (circ.xf - circ.xi);
proy_y = (circ.yf - circ.yi);
radio = sqrtl( proy_x * proy_x + proy_y * proy_y );
//sqrtl calcula la raíz cuadrada de un double
area = PI * radio * radio;
circunferencia = 2 * PI * radio;
printf("\nRadio: %.3lf\nArea : %.3lf\n", radio, area);
printf("Circunferencia: %.3lf\n", circunferencia);
}

Tablas y estructuras dentro de estructuras.
Un miembro de una estructura puede ser de un tipo simple (cualquier tipo
predefinido) o compuesto (tablas, estructuras, etc.) .
#include <stdio.h>
#include <conio.h>
#include <string.h>
struct datosmotor
{
int cilindros;
float potencia, ccubicos;
};
struct equipamiento
{
char nombre_eq[21];
int precio_eq;
};
struct autos_venta
{
char marca[31];
char modelo[31];
struct datosmotor motor;
int precio;
struct equipamiento opciones[10];
int puertas;
};
void main(void)
{
struct autos_venta coche;
clrscr();
strcpy(coche.marca, "SEAONOSEA");
coche.motor.cilindros = 8;
coche.motor.potencia = 100.5;
strcpy(coche.opciones[0].nombre_eq, "AIRE ACONDICIONADO");
coche.opciones[0].precio_eq = 300000;
printf("Completa los datos\n\n");
printf("Marca %s
Modelo: ", coche.marca);
scanf("%s", coche.modelo);
printf("Potencia %.1f
Cent. cubicos: ", coche.motor.potencia);
scanf("%d", &coche.motor.ccubicos);
printf("Precio: ");
scanf("%d", &coche.precio);
printf("Tipo de extra: ");
scanf("%s", coche.opciones[1].nombre_eq);
printf("Precio extra: ");
scanf("%d", &coche.opciones[1].precio_eq);
getch();
}
__________________________________________________________________________________________________________
Estructuras Estáticas
29
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
APÉNDICE. Tratamiento de TABLAS y ESTRUCTURAS mediante
PUNTEROS.
En realidad, la notación de tablas es un método disfrazado de empleo de
punteros. Dicho de otro modo, si se utiliza notación de tablas en el programa fuente,
tendrá que ser traducida a notación de punteros a la hora de obtener el programa
ejecutable.
Por ejemplo: Sea un vector (no importa su tipo) como meses[12]. Se
cumple que
meses == &meses[0]
Es decir, el nombre del vector representa un puntero (constante) dirigido al
primer elemento del vector. Dicho de otra forma: el nombre del vector representa la
dirección de memoria del primer elemento del vector (en realidad, de su primer
byte).
Los dos términos de la igualdad del ejemplo anterior son constantes punteros.
Por tanto, no tiene sentido incrementarlos; o sea, no se puede usar la expresión:
meses++
Algo semejante sería intentar incrementar una constante numérica, por ejemplo,
el 5, de la forma 5++. Sin embargo, si es factible operar de la siguiente forma:
meses + 1
al igual que lo sería emplear la expresión 5 + 1.
Insistiendo en este punto y para comprender que el nombre del vector es un
puntero -representación simbólica de una dirección constante- diremos que: del mismo
modo que una variable no cambia su dirección (su lugar de almacenamiento) a lo largo
de un programa aunque sí es posible que cambie su contenido, el nombre de un vector
es una constante pues no puede cambiar su valor.
Por otra parte, es posible asignar el nombre del vector a un puntero variable, el
cual sí puede incrementarse o decrementarse. Por ejemplo:
pt = meses;
y luego...
pt++;
El ordenador direcciona cada byte individualmente, pero cuando sumamos 1 a
un puntero (a una dirección), no se suma 1 byte, sino una unidad de almacenamiento del
tipo al que pertenece el puntero. Por eso, al declarar un puntero hay que especificar al
tipo de elementos al que va a referirse.
Esto significa que, para vectores, al sumar 1 a un puntero (constante o variable)
a ese vector, la dirección cambia al siguiente elemento del vector.
Así pues, para utilizar los elementos del vector se puede emplear notación de
tablas, pero es más efectiva la notación con punteros:
__________________________________________________________________________________________________________
Estructuras Estáticas
30
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
ELEMENTO
1º
2º
3º
.....
Nº
DIRECCIONES
meses
== &meses[0]
meses + 1 == &meses[1]
meses + 2 == &meses[2]
.................
.................
meses+N - 1 == &meses[N-1]
VALORES
*(meses)
== meses[0]
*(meses + 1) == meses[1]
*(meses + 2) == meses[2]
....................
.............
*(meses+N -1) == meses[N-1]
Por tanto, para referirnos a un elemento del vector id_array deberemos usar la
expresión
*(id_array + N - 1)
siendo N el número de orden de ese elemento, considerando que el 1º elemento tiene nº
de orden 1.
Hay que tener en cuenta que el operador de indirección * tiene una prioridad
muy alta, mayor que el operador suma +, por lo que hay que usar paréntesis cuando se
quieren obtener los sucesivos elementos del vector.
Por ejemplo: *(meses + 1)
*meses + 1
hace referencia al valor del 2º elemento, y
hace referencia al valor del 1º elemento más 1.
#include <stdio.h>
#include <conio.h>
short int meses[]={31,28,31,30,31,30,31,31,30,31,30,31};
#define TOPE sizeof (meses) / (sizeof (short int))
void main(void)
{
// Si <indice> comenzara en 1, se emplearía la
int indice; // expresión:
* ( meses + indice - 1 )
for(indice=0; indice < TOPE ; indice++)
printf("Mes %2d = %d dias.\n", indice + 1, *(meses + indice) );
getch();
}
Ejemplo (repetido) de paso de vectores a funciones con parámetros puntero.
#include <stdio.h>
#include <conio.h>
#define NUM_ALUMNOS 10
float fmedia (float * , int); // Observe la declaración de prototipo
void main(void)
// especialmente, el puntero: float *
{
float notas[NUM_ALUMNOS], nota_media;
int i;
for (i=0; i < NUM_ALUMNOS; i++ )
{
printf("NOTA %d : ",i+1);
scanf("%f", notas+i); // scanf necesita la dirección
}
nota_media = fmedia (notas, NUM_ALUMNOS);
printf("Nota media = %5.2f ", nota_media );
getch();
}
float fmedia ( float *vector, int num_elem )
__________________________________________________________________________________________________________
Estructuras Estáticas
31
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
{
float totnotas;
int indice;
for (indice=0, totnotas=0.0; indice < num_elem ; indice++)
totnotas += *(vector+indice);
return ( totnotas / num_elem ) ;
}

Punteros y vectores de caracteres.
Siendo
char tira1[] = "Lenguaje C";
El nombre del vector tira1 es un puntero al primer elemento del mismo. Se
cumplen las siguientes equivalencias:
tira1==&tira1[0]
*tira1=='L'
*(tira1+1)==tira1[1]=='e'
#include <string.h>
#include <stdio.h>
#include <conio.h>
char m3[10];
void main(void)
{
char m1[30]={'L','e','n','g','u','a','j','e',' ','C','\0'};
static char m2[11]="Lenguaje C"; // longitud lógica= 10 caracteres
printf("m3=%s
Dir=%u \n\n", m3, m3 );
printf("m1=%s
Dir=%u \n", m1, m1 );
// Lenguaje C 4239660
printf("
%c %c\n\n", *m1, *(m1+3) );
// L g
printf("m2=%s
Dir=%u\n", m2, m2 );
// Lenguaje C 4239690
printf("
%c %c\n\n", *m2, m2[5] );
// L a
printf("\n\n
Long. fisica
Long. logica\n");
printf("m1=\t %d \t\t %d \n", sizeof m1, strlen(m1)); // 30 10
printf("m2=\t %d \t\t %d \n", sizeof m2, strlen(m2)); // 11 10
printf("m3=\t %d \t\t %d \n", sizeof m3, strlen(m3)); // 10
0
printf("\n\nAsignando nuevos valores:\n");
// Es ilegal
m1 = "aaaa";
// Es ilegal
m2 = "bbbbb";
// Es ilegal
m3 = "ccccc";
// En su lugar hay que utilizar la función
strcpy();
strcpy (m1, "aaaaa");
strcpy (m2, "bbbb");
strcpy (m3, "ccccc");
printf ("m1=%s \nm2=%s \nm3=%s \n ", m1, m2, m3);
getch();
}

Punteros a char
También se pueden usar punteros para definir una cadena:
char *pttira = "Lenguaje C";
Tal declaración es equivalente a la utilizada anteriormente:
__________________________________________________________________________________________________________
Estructuras Estáticas
32
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
char arraytira[] = "Lenguaje C";
pues ambas preparan un puntero a la cadena y reservan 11 elementos de
almacenamiento estático.
Sin embargo, existen notables diferencias...
-
pttira es una variable, luego se puede incrementar (pttira++) o
decrementar (pttira--). No hace falta que pttira sea estática,
aunque puede serlo. Además de las posiciones de memoria reservadas
para la cadena, existe otra reservada para el puntero: &pttira
............
printf("%c",pttira);
// L
pttira++;
printf("%c",pttira);
// e
*pttira = 'a';
printf("%s",pttira);
// anguaje C
..........................
-
Por su lado, arraytira es constante y ....
arraytira == &arraytira[0]
Luego no se puede incrementar (arraytira++ no es válido) aunque sí
podemos operar
*(arraytira + x)
para referenciar al elemento x+1 de la cadena.
....................
*(arraytira + 9) = 'B';
printf("%s",arraytira);
......................
// Lenguaje B
#include <stdio.h>
#include <conio.h>
int long_cad (char * );
void main (void)
{
int long1, long2;
char nombre[40];
char *comida="una hilera de hormigas..."; // 25 caracteres
printf("¿Cómo se llama el oso hormiguero? ");
gets(nombre); // nombre y comida actúan como punteros a cadenas
long1 = long_cad (nombre);
long2 = long_cad (comida);
printf("%s, que mide %d, se comió ", nombre, long1);
puts(comida);
printf("en total %d.", long2);
getch();
}
__________________________________________________________________________________________________________
Estructuras Estáticas
33
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
//*****************************************************************
int long_cad (char *cadena)
//esta función equivale a strlen()
{
char *ptrcad;
ptrcad = cadena;
while (*ptrcad != '\0')
ptrcad++;
return (ptrcad - cadena);
}

Punteros y tablas multidimensionales.
Una tabla de dos dimensiones se puede considerar como una tabla
unidimensional de tablas unidimensionales, osea, un vector de vectores.
Supongamos la definición:
int bid[3][5] = { {4, 9, 0}, {0}, {3, 1}
};
resulta que bid es el nombre de una tabla bidimensional, o sea, bid es un vector de
vectores. Dicho de otra forma: bid contiene 3 elementos, cada uno de los cuales es un
vector de 5 enteros.
4 9 0
bid[0]
0
0
0 0 0
bid[1]
0
0
3 1 0
bid[2]
0
0
Los punteros que apuntan a cada uno de estos 3 vectores son bid[0], bid[1] y
bid[2].
El nombre de la tabla bid apunta al primer elemento de la tabla que es un vector
de 5 enteros, o sea, a bid[0]. A su vez, bid[0] es un puntero a su primer elemento:
bid[0][0].
Resumiendo, bid apunta a bid[0] que es un vector de int, y bid[0] apunta a
bid[0][0] que es un entero. Por tanto, bid es un PUNTERO A UN PUNTERO . Sin
embargo, coinciden...
bid
==
bid[0] == &bid[0][0]
Del mismo modo:
bid[1] == &bid[1][0]
bid[2] == &bid[2][0]
.....................................
No obstante, hay una diferencia:
bid[0] apunta a un entero, o sea, a un objeto de 4 bytes de largo.
bid apunta a un vector de 5 enteros, o sea, a un objeto de 20 bytes de largo.
__________________________________________________________________________________________________________
Estructuras Estáticas
34
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
Por ello, al sumar 1 a bid[0] obtenemos una dirección 4 bytes superior (la del
elemento siguiente), pero al sumar 1 a bid obtenemos una dirección 20 bytes superior
(la del vector siguiente).
#include <stdio.h>
#include <conio.h>
#define FILA 3
#define COLU 5
void main(void)
{
int tabla[FILA][COLU]= {{21,23,25,27,29},{42,43,44,45,46},{1,2,3,4,5}};
int f,c ;
for (f=0; f< FILA; f++) //Duplica el valor de cada elmto tabla[f][c]
for (c=0; c < COLU ; c++ )
* ( *(tabla+f) + c ) *= 2 ;
for (f=0; f < FILA; f++)
{
for (c=0; c < COLU ; c++ )
printf("%5d", * ( *(tabla+f)+c)); //printf("%5d", tabla[f][c]);
printf("\n");
}
getch();
}
Al igual que bid, la tabla bidimensional tabla del ejemplo anterior se puede
considerar un vector de vectores. Así pues, tabla + 0 apunta a tabla[0] que es un
vector de 5 enteros y que a su vez apunta a tabla[0][0];tabla + 1 apunta a tabla[1]
que es otro vector de 5 enteros y que a su vez apunta a tabla[1][0], etc.
Al aplicar el operador de indirección:
* (tabla + f )
obtendremos la dirección de tabla[0], de tabla[1], etc. según «f » vaya tomando los
valores 0, 1, etc. Si a la expresión anterior le sumamos el valor «c » tendremos la
dirección del elemento de índice « f ,c ». Es decir,
*(tabla + 0 ) + 0 nos da la dirección de tabla[0][0]
*(tabla + 0 ) + 1 nos da la dirección de tabla[0][1]
...................
*(tabla + 1 ) + 0 nos da la dirección de tabla[1][0]
...................
Por último, para acceder al valor que guardan tales elementos, basta aplicar el
operador de indirección.
*( * ( tabla + f
) + c )
__________________________________________________________________________________________________________
Estructuras Estáticas
35
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________

Punteros a estructuras.
Los punteros a estructuras se declaran colocando el símbolo * delante del
nombre de la variable de estructura.
Para conocer la dirección de una variable de estructura se debe colocar el
operador & delante del nombre de la estructura.
Para acceder a los miembros de la estructura a través de un puntero a esa
estructura, se debe utilizar el operador flecha (símbolos menos y mayor que: ->) .
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
#define DELAY 960000
struct mi_tiempo
{
int horas, minutos, segundos;
};
void actualiza (struct mi_tiempo *t), muestra (struct mi_tiempo *t);
void retraso(void);
void resetea (struct mi_tiempo *t);
int main(void)
{
struct mi_tiempo crono;
unsigned char tecla;
crono.horas = 23;
crono.minutos = 58;
crono.segundos = 55;
while(1)
{actualiza(&crono);
gotoxy(1,1);
muestra(&crono);
if(kbhit())
{
tecla = toupper(getch());
if (tecla == 'R')
resetea(&crono);
else return 0;
}
}
}
void resetea (struct mi_tiempo *t)
{
t->horas
= t->minutos = t->segundos = 0;
}
void actualiza (struct mi_tiempo *t)
{
t->segundos++;
if(t->segundos==60)
{
t->segundos = 0;
t->minutos++;
}
if(t->minutos==60)
{
t->minutos = 0;
t->horas++;
}
if(t->horas==24)
t->horas = 0;
retraso();
}
void muestra(struct mi_tiempo *t)
{
printf("%02d:%02d:%02d", t->horas, t->minutos, t->segundos);
}
__________________________________________________________________________________________________________
Estructuras Estáticas
36
I.E.S. Francisco Romero Vargas –Departamento de Informática Fundamentos de Programación
__________________________________________________________________________________________________________
void retraso(void)
{
long int t;
for(t=1; t<DELAY; ++t) ;
}
#include <stdio.h>
#include <conio.h>
#include <math.h>
#define PI 3.14159265358979
struct circulo
{
double xi, yi, radio;
};
void pidedatos_circulo( struct circulo * );
void main(void)
{
struct circulo c1;
double area, circunferencia;
clrscr;
pidedatos_circulo ( &c1);
area = PI * c1.radio * c1.radio ;
circunferencia = 2 * PI * c1.radio;
printf("\n\nCirculo
(%.3lf
,
%.3lf)
Radio=%.3lf\n\n",
c1.xi,
c1.yi,
c1.radio);
printf("Area: %.3lf \nCircunferencia: %.3lf \n", area, circunferencia );
getch();
}
//*************************************************************************
void pidedatos_circulo ( struct circulo *c )
{
printf("Centro x: ");
scanf("%lf", &c->xi);
printf("Centro y: ");
scanf("%lf", &c->yi);
printf("
Radio: ");
scanf("%lf", &c->radio);
}
__________________________________________________________________________________________________________
Estructuras Estáticas
37
Descargar