Professional Documents
Culture Documents
TEMA 3: Sentencias
TUTOR DE C
TEMA 0: Introduccin
1.0 Introduccin
1.1 El programa HOLA MUNDO
1.2 Tipos de datos bsicos en C
1.3 Entrada de datos por teclado
2.0 Introduccin
2.1 Expresiones Condicionales
2.1.1 La instruccin if ... else
2.2 Control del Flujo del Programa
2.2.0 Introduccin
2.2.1 Creaccin de bucles de ejecucin
2.2.1.0 Concepto de bucle
2.2.1.1 Bucle for
2.2.1.2 Bucle while
2.2.1.3 Bucle do ... while
2.2.1.4 Modificadores del flujo de programa
2.2.2 Mens de opciones.
2.2.2.1 Introduccin
2.2.2.2 Sentencia switch-case-default
3.0 Introduccin
3.1 Matrices estticas
3.2 Tipos compuestos
3.2.0 Introduccin
3.2.1 Estructuras de datos
4.0 Introduccin
4.1 Punteros
4.1.1 Qu son los punteros?
4.1.2 Operadores que actan sobre punteros
4.1.3 Punteros y matrices
4.1.4 Punteros y cadenas de caracteres
4.2 Funciones
4.2.1 Introduccin
4.2.2 Definicin de funciones
4.2.3 Ms sobre funciones
5.0 Introduccin
5.1 Asignacin dinmica y esttica de memoria
5.2 Cmo se reserva memoria dinmicamente?
5.2.1 Reserva de memoria
5.2.2 Liberacin de memoria
5.2.3 Ventajas de la asignacin dinmica
5.3 Tipos de datos abstractos y encapsulado
5.3.0 Introduccin
5.3.1 Cdigo fuente, cdigo objeto. Libreras y enlazadores
5.3.2 Los ficheros de proyectos de Borland
5.3.4 Tipos Abstractos de Datos
6.0 Introduccin
6.1 Entrada y salida (E/S)
6.1.1 E/S estndar
6.2 Flujos y ficheros.
6.3 Tipos de flujos: flujos de texto y flujos binarios.
6.4 Programas C con flujos.
6.5 Resumen de los apartados anteriores
6.6 Pasos para operar con ficheros
6.7 Sistema de ficheros tipo UNIX.
6.7.1 Descriptores de ficheros.
EJEMPLOS
PERMUTACIONES DE UN VECTOR
ORDENACION RAPIDA (QSORT)
LAS OCHO REINAS
SALTO DEL CABALLO
COPIA DE UN FICHERO (SIMILAR AL COPY DEL DOS)
COMPARACION DE FICHEROS
ORDENACION DE UN FICHERO (SIMILAR AL SORT DEL DOS)
SHELL CRONOMETRADO
VISUALIZACION DE 256 BYTES DE MEMORIA
+-Algoritmo races
|
|
Variables reales a,b,c,x,y
|
|
Escribir "Introduzca los coeficientes de mayor a menor grado."
|
Leer a,b,c
|
| +-Si sqr(b)>= 4*a*c entonces
| |
x=(-b+sqrt(b^2-4*a*c))/2a
| +-Sino
| |
Escribir "No existen races reales."
| +-Finsi
|
+-Final
0.4 Organigramas.
Un organigrama o diagrama de flujos es una representacin
semigrfica del algoritmo en cuestin. Esto nos facilita la visin
descriptiva de la ejecucin del programa, as como la generacin de
la traza del algoritmo. Se denomina traza de un algoritmo a la
ejecucin manual de un programa obteniendo para cada paso un
resultado.
Smbolos generales:
*
*
*
*
Enteras
Reales
Carcter
Cadena
Lgicas
dbyte,
(Su
(Su
(Su
(Su
(Su
Existen
dword,
programacin profesional.
Las variables se caracterizan pues poseen una jerarqua que
viene definida por el nmero de bytes que se asignan para cada una.
As un carcter posee un longitud de un byte, (donde se almacena un
nmero al que se le ha asociado mediante la norma ASCII) sin embargo
un entero posee dos byte. Sera lgico pensar que una variable
entera contuviera a un carcter y de hecho esto puede ser as, sin
embargo el mezclar tipos
de
variables
es impropio de una
programacin ordenada y elegante. Es decir, no se debe mezclar
tipos de variables a no ser que se produzca a travs de una funcin
de conversin de tipos (convertir un entero a una cadena y
viceversa).
En el programa anterior se observa la declaracin de
variables despus de la cabecera, que es el orden que debe seguirse
en la elaboracin de un algoritmo y en un programa informtico.
1.2.2 Variables y Constantes.
La principal diferencia entre variables y constantes es que
las primeras pueden variar a lo largo de la ejecucin del programa,
mientras que las segundas
permanecen constantes siempre. Las
constantes se declaran despus de la cabecera y antes de las
variables.
Ejemplo:
+-Algoritmo Circunferencia
|
|
Constante real PI=3.1416
|
Variable real r,c
|
|
Escribir "Introduzca el radio de la circunferencia"
|
Leer r
|
c=2*Pi*r
|
Escribir "Su longitud es: ",c
|
+-Final
Se define Vector como una variable cuya estructura es una
sucesin de elementos del mismo tipo. As una variable de cadena es
un vector de caracteres, ya que esta formado por una sucesin de
variables del
tipo carcter. As podemos
crear vectores de
diferentes tipos.
Ejemplo: Producto
escalar
+-Algoritmo Producto_Escalar
|
|
Vector entero a[1..3], b[1..3]
|
Variable entera c
|
|
Escribir "Introduzca el vector A (x,y,z)"
|
Leer a[1],a[2],a[3]
|
Escribir "Introduzca el vector B (x,y,z)"
|
Leer b[1],b[2],b[3]
|
|
c=a[1]*b[1]+a[2]*b[2]+a[3]*b[3]
|
|
Escribir "El producto escalar es: ",c
|
+-Final
De igual forma tenemos
vectores que se define como:
que
una
matriz
es un vector de
| +-FinPara
|
+-FinFactor
2.2.1 Parmetros Formales y Actuales.
Como hemos visto,
entre los procedimientos (funciones
tambin) y su entorno se producen una relacin en base a un
intercambio de valores de las variables. Estas variables reciben
nombres diferentes segn este en el cdigo Padre o en el cdigo
Hijo. Vamos a definir como cdigo Padre, aquel desde el cual se
llama a una subrutina y, el cdigo Hijo, la subrutina que estamos
llamando.
Parmetros Actuales son los que utiliza el programa Padre
para relacionarse con una subrutina en concreto, y parmetro
Formales son los que posee el programa Hijo y que lo relaciona con
el Padre.
+-Algoritmo Factorial
|
|
Variable real num,valor
|
|
Escribir "Introduzca el nmero a factorizar:"
|
Leer num
|
|
Factor(num,valor) <- Llama al Procedimiento Factor
|
|
|
|
+---+---> Parmetro Actuales.
|
|
Escribir "El factorial es: ",valor
|
+-Final
Obsrvese que los parmetros actuales y formales no tienen
por que llamarse de igual forma, sin embargo es condicin necesaria
que sean del mismo tipo y que estn en el mismo orden.
La transmisin de un parmetro como valor y no como
variable, hace que el programa Padre no reciba las posibles
modificaciones que pueda sufrir dicho parmetro dentro del cdigo
Hijo.
Ejemplo:
+-Algoritmo Factorial Constante
|
|
Variable real num,valor
|
|
Escribir "Introduzca el nmero a factorizar:"
|
Leer num
|
|
valor=0
|
Factor(num,3) <- Llama al Procedimiento Factor
|
|
Escribir "El factorial es: ",valor
|
+-Final
Se puede
se
pueden
dividir
- Sentencias Simples.
- Sentencias Compuestas.
- Sentencias de control del flujo del algoritmo.
Las Sentencias Simples son del tipo de:
- Asignacin de Variables y Constantes.
- Llamadas a Procedimientos y Funciones, dentro de estas ltimas
englobamos todas las funciones y procedimientos que conforman la
librera general de sentencias que veremos posteriormente.
Las Sentencias Compuestas:
- Son aquellas
Funciones.
que
estn
limitas
dentro
de
Procedimientos
| div
| Divisin (devuelve un valor entero)
|
| mod
| Clculo del mdulo aritmtico.
|
| log
| Logaritmo en base 10
|
| ln
| Logaritmo neperiano
|
| exp
| Exponencial de un nmero
|
| pow
| Potencia de un nmero
|
| random
| Obtencin de un nmero aleatorio
|
| abs
| Obtenemos el valor absoluto de un nmero
|
| sqr
| Obtencin del cuadrado de un nmero
|
| sqrt
| Obtencin de la raz cuadrada
|
| sin,cos,tan | Funciones trigonomtricas
|
| chr/toascii | Obtenemos un carcter a partir de un nmero
|
| ord
| Obtenemos el nmero correspondiente al cdigo |
|
| ASCII
|
+-------------+-----------------------------------------------+
Lgicamente, existen
ms adelante.
ms funciones aritmticas
que veremos
la variable b
nos permiten
mayor que
12
generar condiciones
y la variable
d igual a
dos condiciones)
+-------------------------+
| true OR true -> true |
| true OR false -> true |
| false OR true -> true |
| false OR false -> false |
+-------------------------+
Operador XOR: (se cumple cuando las dos condiciones son distintas)
+--------------------------+
| true XOR true -> false |
| true XOR false -> true |
| false XOR true -> true |
| false XOR false -> false |
+--------------------------+
Operador NOT: (niega el resultado de una condicion)
+--------------------+
| NOT true -> false |
| NOT false -> true |
+--------------------+
- La sentencias SI puede tener las siguientes estructuras:
+-Si (condicin) entonces
|
...
+-Sino
|
...
+-Finsi
Tambin puede aparecer en estructuras ms complejas:
+-Si (condicin1) entonces
| +-Si (condicin2) entonces
| |
...
| +-Finsi
+-Sino
|
...
| +-Si (condicin3) entonces
| |
...
| +-Sino
| |
...
| +-Finsi
+-Finsi
A este tipo de estructuras
encadenamiento de sentencias SI".
se le
denomina "anidamiento o
|
accin2
+-Sino Si (condicin3) entonces
|
accin3
+-Sino
|
accin4
+-Finsi
Con una estructura del tipo
resuelto de la siguiente forma:
|
resul=0
| +-Repetir
| |
resul=resul+mult1
| |
mult2=mult2-1
| +-Hasta que mult2<=0
+-Final
(o tambin
dispositivos de almacenamientos
para
leer
registro 'd'
ejemplo de
veamos las
- Leer/Escribir/Reescribir (variable1,variable2)
Esta sentencia permite la
datos que contiene la variable2
determinado en la variable1.
+-Algoritmo Copiar_fichero
|
|
Fichero de enteros Origen,Destino
|
Variable entera x
|
|
Escribir ("Indique el nombre del fichero Origen:");
|
Leer Origen
|
Escribir ("Indique el nombre del fichero Destino:")
|
Leer Destino
|
|
Abrir secuencial (Origen)
|
Iniciar lectura en (Origen)
|
Abrir secuencial (Destino)
|
Iniciar escritura en (Destino)
|
| +-Mientras (NO fin(Origen)) hacer
| |
Leer (Origen,x)
| |
Escribir (Destino,x)
| +-Finmientras
|
|
Escribir ("Fichero Copiado:")
|
|
Cerrar (Origen)
|
Cerrar (Destino)
|
+-Final
Nota: Obsrvese que la variable utilizada en las operaciones
de lectura y/o escritura, deben
ser del mismo tipo que la
declaracin del fichero.
4.3 Registros Estructurados.
Hasta ahora hemos visto como los registros eran de un tipo
nico, es decir, eran todos carcter, enteros, reales, etc. Sin
embargo, hay situaciones en las que debemos realizar agrupaciones de
tipos para formar un registro estructurado. As, un registro
estructurado esta formado por un conjunto de variables de diferentes
tipos que denominaremos campos. De este modo podemos decir que un
Fjese
que los datos estn
almacenados en el orden en el
que han sido introducidos por el
usuario.
Accedemos a los datos por medio
del
valor de la posicin del
registro.
directo
Ejemplo:
+-Algoritmo Contador_de_registros.
|
|
Fichero de enteros F
|
Variable entera x,contador
|
|
Abrir directo (F)
|
Iniciar lectura (F)
|
contador = 0
| +-Mientras (NO fin(F)) hacer
| |
Leer directo(F,x)
| |
contador=contador+1
| +-Finmientras
|
Cerrar(F)
|
|
Escribir ("El fichero:";F;"posee:";contador;"reg.")
|
+-Final
4.5 Ficheros de Acceso Indexado.
Un Fichero de Acceso Indexado es aquel que se encuentra
almacenado en un dispositivo direccionable; y donde sus registros
poseen un campo que denominaremos campo clave principal y que
identifica inequvocamente a cada registro. La clave principal debe
ser aquel campo del registro estructurado que tenga siempre un valor
diferente a los ya introducidos, es decir, dentro del fichero
Indexado no puede haber dos registros con los campos clave principal
iguales.
Adems del campo clave principal pueden existir otros campos
claves secundarios que realizan la misma tarea que el campo clave,
sin embargo, sus valores pueden repetirse. En los Ficheros de Acceso
Indexado el campo clave puede ser cualquiera de los campos de un
registro estructurado. As se establece una correspondencia directa
entre los valores del campo clave y el propio registro al que
pertenece. Los registros se almacenan ordenados alfabticamente por
el campo clave, esto nos facilita la bsqueda y listados ordenados
por los distintas claves.
Para cada campo clave, el fichero genera una tabla, donde
dicha clave aparece ordenada alfabticamente y se relaciona con la
direccin de los datos.
De esta forma en un Fichero de Acceso Indexado nos referimos
a un registro por medio de alguna de las claves que posea el
fichero, tanto la principal como la secundaria. Es decir, leer el
registro cuya clave principal sea: 46.399.554, en este caso leera
el registro correspondiente a INMA. Tambin podramos haber dicho,
leer los registro cuya clave secundaria sea la Edad=16 y primero nos
leera el registro correspondiente a los datos de Luis y en la
siguiente peticin de lectura los datos de Teresa. La diferencia
entre clave principal y secundaria, est en que la clave principal
es nica (relacionando as inequvocamente al registro al que
pertenece) mientras que las claves principales puede ser iguales.
+------------+-------------------------------------+
|
Clave
|
Clave
Clave
Clave
|
| Principal | Secundaria
Secundaria Secundaria |
+--------------------------------------------------+
+---------+------------+------------+-------------+--------+
| (Direc) | (D.N.I.) | (Nombre) | (Provincia) | (Edad) |
+---------|------------|------------|-------------|--------+
|
1
| 55.366.546 | LUIS
| Las Palmas |
16
|
|
2
| 42.386.225 | CARLOS
| Salamanca
|
17
|
|
3
| 32.387.203 | TERESA
| Oviedo
|
16
|
|
4
| 46.399.554 | INMA
| Palencia
|
20
|
|
5
| 60.643.434 | JOAQUIN
| Salamanca
|
17
|
|
6
| 22.543.986 | JOSE
| Las Palmas |
23
|
+---------+------------+------------+-------------+--------+
Como podemos
indexado.
ejemplo de un fichero
+------------+---------+
| (Nombre) | (Direc) |
+------------+---------+
| CARLOS
|
2
|
| INMA
|
4
|
| JOAQUIN
|
5
|
| JOSE
|
6
|
| LUIS
|
1
|
| TERESA
|
3
|
+------------+---------+
+---------------------------+
| Tabla de Ac. Clave Secund.|
+---------------------------+
Obsrvese
como
ambas
tablas
aparecen
ordenadas
alfabticamente (o de menor a mayor en el caso del DNI). Como ya
dijimos, esto nos da grandes
facilidades a la hora de realizar
bsquedas y/o listados ordenados.
4.5.1 Ejemplo de I/O en Ficheros de Acceso Indexado.
Pasemos a
indexados,
pero
utilizaremos.
ver un ejemplo de
antes
veamos
las
- Leer/Escribir/Reescribir (variable1,KEY=,variable2)
datos
Al nmero 104
se le denomina
puntero
de
desbordamiento
campo clave
a travs del
que han sido
aleatorio
TEMA 0: Introduccin
0.1 Orgenes del C
El lenguaje C
cuando trabajaba, junto
operativo UNIX.
escritos
en
son
Escribirlo en un editor.
Compilarlo en un compilador.
Enlazarlo en un enlazador.
Ejecutarlo.
Paso 1: ESCRIBIRLO
El programa se puede escribir en cualquier editor que genere
ficheros de texto estndar, esto es, que los ficheros generados no
incluyan cdigos de control y caracteres no imprimibles.
a partir de los
---->
f1.obj
f2.c
---->
f2.obj
.
.
.
fn.c
.
.
.
---->
fn.obj
f1.lib
f2.lib
.
.
.
---------+
|
---------|
|
|
|
|
|
---------|
|---------------> f.exe
---------|
|
---------+
|
|
|
|
fm.lib
|
---------+
}
Como podemos observar se trata de un programa muy sencillo.
La primera lnea es lo que se conoce como un comentario, un mensaje
que el programa aade al cdigo del programa para explicar o aclarar
su funcionamiento o el de una parte de l. Los comentarios se pueden
situar en cualquier parte de nuestro cdigo y se considerar como
comentarios cualquier mensaje que se encuentre entre los caracteres
/* y */.
Los "/*" y "*/" no son caracteres, sino smbolos o banderas.
La siguiente lnea es lo que se conoce como directiva del
preprocesador, todos
los compiladores de
C disponen de
un
preprocesador, un programa que examina el cdigo antes de compilarlo
y que permite modificarlo de cara al compilador en distintos
sentidos. En temas posteriores trataremos en profundidad estas
directivas del preprocesador, pero para el desarrollo de los temas
anteriores a este debemos conocer al menos la directiva #include.
Las directivas se caracterizan por comenzar con el carcter # y se
deben incluir al comienzo de la lnea aunque es probable que esto
en profundidad la
numero1,numero2,numero3;
coordenada_x,coordenada_y;
a;
b;
b=30;
a=(float)b;
Para ejemplificar todo esto vamos a realizar un programa que
nos calcule el espacio recorrido por un mvil con velocidad uniforme
durante un tiempo determinado. El programa sera algo as:
#include <stdio.h>
main()
{
float
e,v,t;
v,t,e;
ciertas ocasiones
nos puede
interesar que
un programa
Representa igualdad.
Representa desigualdad
Mayor que.
Menor que.
Mayor o igual que.
Menor o igual que.
Y lgico.
O lgico.
IF es la siguiente: if (condicin)
dividir deberamos de
sera algo como sto:
comprobar si el divisor es
cero. El programa
#include <stdio.h>
main()
{
float
dividendo,divisor;
de datos,
como
trazado
de
lneas
Hay que
recordar que
exp2 se
bucle, y no
NINGUNA vez.
al final.
Por tanto
es posible
no ejecutar el bucle
i;
tabla1,tabla2;
printf ("
}
%2dx%2d=%3d",tabla2,i,tabla2*i);
i;
i = 0;
while (i<10)
{
printf ("\n%d",i);
i++;
}
numero;
introduzca el
numero = 10;
while (numero!=0)
{
printf ("\nDime un nmero:");
scanf ("%d",&numero);
}
}
En este ejemplo tenemos que introducir en la variable nmero
un valor distinto de cero antes de entrar en el bucle, puesto que en
principio al declarar una variable el valor de sta no est
determinado y podra valer cero, en cuyo caso nunca se ejecutara el
bucle. Esta es la misin de la instruccin numero = 10;.
2.2.1.3 Bucle do.. while
Su funcionamiento es anlogo al anterior, con la nica
salvedad de que la condicin ahora se evala despus de ejecutar la
instruccin su sintaxis sera:
do instruccin while (exp2);
Si en el ejemplo anterior utilizamos esta estructura no
sera necesario actualizar numero con un valor distinto de cero,
puesto que antes de comprobar si es cero leeramos el valor.
#include <stdio.h>
main()
{
int
numero;
do
{
main()
{
int
int
numero;
contador;
contador =0;
do
{
printf ("\nIntroduce el nmero %2d:",contador);
scanf ("%d",&numero);
if ((numero<0)||(numero>20)) continue;
contador++;
} while (contador<50);
}
Este programa lee nmeros en una variable hasta un mximo de
50, alcanzado este mximo el programa termina. Adems si el nmero
no est entre 0 y 20 (si es menor que 0 o mayor que 20) vuelve a
pedir que lo introduzcamos. El comando continue en la instruccin if
obliga al programa a saltar a la instruccin while donde se vuelve a
evaluar la condicin, sin pasar por la lnea en la que se incrementa
el contador. De esta forma se nos vuelve a pedir el mismo nmero y
la entrada incorrecta no es tenida en cuenta.
La funcin de break es ligeramente distinta no salta a la
instruccin en la que se evala la condicin sino que simplemente
abandona el bucle y contina la ejecucin en la lnea inmediatamente
siguiente al bucle.
#include <stdio.h>
main()
{
int
i;
for (i=0;i<20;i++)
{
if (i==5) break;
printf ("\n%d",i);
}
printf ("\n\n%d",i);
}
La salida de este programa sera algo como esto:
0
1
2
3
4
5
Y con esto terminamos todo lo relacionado con los bucles en
lenguaje C. Los bucles son una estructura bsica y es necesario
utilizarla en la inmensa mayora de los programas.
2.2.2 Mens de Opciones.
2.2.2.1 Introduccin
La mayora de los programas permiten realizar una serie de
operaciones sobre datos. Lo ideal sera poder indicarle al ordenador
que operacin deseamos realizar sobre estos datos en lenguaje
natural. Por ejemplo, para una base de datos nos podra interesar
decirle al ordenador: "Buscame todas la fichas de libros que traten
sobre informtica" "Borra de la base de datos el libro tal".
Existen en la actualidad herramientas de este tipo, pero an distan
bastante del lenguaje natural, por ello una de las formas ms
sencillas de indicar al ordenador la operacin que deseamos realizar
es utilizar un men de opciones.
La otra solucin comnmente adoptada es una lnea de
comandos, es decir, escribimos una frase en un lenguaje muy reducido
indicando al ordenador lo que deseamos hacer (de una forma similar a
como lo hacemos en MS-DOS). Esta solucin tiene la desventaja de
tener que aprender complicados comandos y distintas secuencias para
distintos programas.
Un men nos muestra en pantalla todas las opciones que
podemos realizar con nuestro programa de forma que no es necesario
que el
usuario conozca ninguna serie
de ordenes complejas,
simplificando por tanto el uso de los programas por parte de los
usuarios.
2.2.2.2 Sentencia switch-case-default
La mayora de los lenguajes de alto nivel disponen de alguna
instruccin que permite gestionar el valor de una variable de una
forma estructurada y sencilla, permitiendo por tanto la creacin de
mens de programa de una forma sencilla. En lenguaje C esta
instruccin es switch-case-default. Veamos un ejemplo de como
funciona mediante un pequeo programita.
#include <stdio.h>
main()
{
int
printf
printf
printf
printf
printf
opcion;
("\nEjemplo de Men de Programa");
("\n1.-Cargar fichero de datos");
("\n2.-Almacenar fichero de datos");
("\n3.-Modificar datos");
("\n4.-Salir");
break;
case 4:
/* Salir del programa */
exit (0);
default :
printf ("\nSu opcin no est disponible");
printf ("\nIntntelo con otra");
}
Del ejemplo se deduce fcilmente el funcionamiento de esta
secuencia. El comando switch (var) realizar una bifurcacin o salto
a la lnea indicada por la variable var. Si var vale 2, el programa
se seguir ejecutando a partir de la lnea marcada con case 2. Todos
los separadores case estn separador por un comando break, ya que de
no ser as la ejecucin seguira lineal hasta encontrar la llave que
termina el comando switch. La palabra clave default indica el cdigo
que se debera ejecutar si el valor de la variable especificada en
el switch no corresponde con ninguno de los indicados por los case
dentro del switch. As en nuestro ejemplo si opcion tiene un valor
distinto de 1, 2, 3 4, se mostrar en pantalla un mensaje
indicando que la opcin indicada no es correcta. La sintaxis de esta
estructura sera:
switch (variable)
{
case valor1-variable:
cdigo asociado;
case valor2-variable:
cdigo asociado;
.
.
case valorN-variable:
cdigo asociado;
default:
cdigo asociado;
}
Dentro del cdigo asociado a cada opcin se debern incluir
las instrucciones break adecuadas. Ya se explic el funcionamiento
de break y continue cuando se habl de bucles. Su funcionamiento es
anlogo para los comandos for, while, do-while, y switch.
Un fragmento de
completo sera:
cdigo para
la imprementacin
de un men
while (Opcion!=0)
{
/* Secuencia de printfs que muestran en pantalla
el men. En este caso la opcin 0 debera ser salir */
switch (opcion)
{
/* Secuencia de cases */
default :
/* Mostrar mensaje de error */
}
}
Por su puesto las aplicaciones del comando switch van mucho
ms all de la simple creacin de mens. Puede ser utilizada en
cualquier aplicacin en la que se necesite realizar distintas
operaciones dependiendo de un valor. Un ejemplo sencillo podra ser
Activa Negrita.
Desactiva Negrita.
Activa/desactiva cursiva.
idem sibrayado
la
entrada
de
la matriz
int matriz[2][3] = {
{ 1,2,3 },
{ 4,5,6 }
};
Estas lneas nos declararan una matriz llamada "matriz" de
2x3 elementos inicializada con los valores indicados. Las matrices
son extremadamente tiles para trabajar con multitud de problemas
matemticos que se formulan de esta forma o para mantener tablas de
datos a los que se accede con frecuencia y por tanto su referencia
tiene que ser muy rpida. Supongamos que estamos desarrollando un
programa para dibujar objetos en
tres dimensiones y ms que la
exactitud de la representacin (aunque esto es muy relativo), nos
interesa
la
velocidad.
En
la
representacin
de
objetos
tridimensionales se hace continua
referencia a las funciones
trigonomtricas seno y coseno. El clculo de un seno y un coseno
puede llevar
bastante tiempo as que
antes de comenzar la
representacin calculamos todos los senos y cosenos que necesitemos
(por ejemplo con una resolucin de 1 grado -360 valores-) cada vez
que necesitemos uno de estos valores accedemos a la matriz en lugar
de llamar a la funcin que nos lo calcula. Veamos como sera nuestro
programa (las funciones sin y
cos se encuentran en la librera
estandar math.h y sus paramtros estn en radianes).
#include <stdio.h>
#include <math.h>
main()
{
float
float
int
origen1;
final1;
variable con
estos
matriz_de_puntos[30];
se
podra
utilizar
con
una
struct otra
{
float
x[10];
} matriz_de_puntos;
Con lo cual accederamos al cuarto elemento del campo x de
matriz_de_puntos que es una variable de tipo struct otra constituida
por una matriz de diez floats.
Para terminar con la declaracin struct indicar que es
posible la declaracin de estructuras anidadas, es decir, un campo
de una estructura puede ser otra estructura.
struct vector
{
float
float
float
};
x;
y;
z;
struct poligono_cuadrado
{
struct vector
p1;
struct vector
p2;
struct vector
p3;
struct vecto
p4;
};
struct cubo
{
struct poligono_cuadrado
int
struct vector
};
struct cubo
cara[6];
color;
posicion;
mi_cubo;
caracter;
entero;
en binario con 1
b11111111 = 255
Este es el tamao que el lenguaje C asigna al tipo char, que
slo puede representar 256 valores distintos, desde 0 a 255. El tipo
int short suele ocupar una palabra es decir, 16 bits. As con 16
bits el mayor nmero que podemos representar es:
b1111111111111111 = 65535
NOTA: El tamao asociado a cada tipo de
especfico de cada compilador/ordenador. No debera
supuesto...
datos es muy
darse nada por
0000111100010000
00010000
-> 3856
-> 65 ('A')
BYTE;
HEXAHEDRO;
var1,var2;
var3;
Sera equivalente a:
unsigned char
struct cubo
var1,var2;
var3;
tipos
de
informe1;
informe2[5];
informe3[25];
programa
principal
hemos
declarado
las
*punt_pgina;
i1[10],*punt1;
i3[5],*punt2;
i4[15],*punt3;
....
Por tanto disponemos de un puntero a pginas y tres
punteros, uno para cada tipo de informe y tres matrices de distintos
tipos de informes que nos permiten almacenar en nuestro archivo un
mximo de 30 informes (10 de 1 pgina, 5 de 5 pginas y 15 de 25
pginas).
Supongamos que en el programa principal se llenan esas
matrices con datos (por teclado o leyendo de un fichero, por
ejemplo) y realizamos las siguientes operaciones:
punt_pgina = (pgina *) &i4[0];
punt3
= (informe3 *)&i4[0];
identificador[tamao_de_la_cadena];
Y por
ser en esencia una
matriz todo lo comentado
anteriormente para matrices y punteros puede ser aplicado a ellas.
As la siguiente definicin constituye tambin una cadena de
caracteres:
char
*identificador;
<stdio.h>
cadena1[10];
cadena2[10];
*cadena;
el momento
hemos utilizado
ya numerosas
funciones,
for (i=0;i<longitud;i++)
if (vector[i] == valor) break;
return i;
}
Esta funcin busca un valor en un vector de nmeros
enteros y devuelve el ndice dentro de la matriz de la entrada de
sta que lo contiene. Puesto que devuelve el ndice de la matriz
supondremos en principio un valor de retorno entero para ese
ndice. Los parmetros que debe conocer la funcin son: la matriz
en la que buscar, el valor que debemos buscar y la longitud de la
matriz. Podramos haber realizado una funcin a medida para que
utilizase una matriz de un nmero determinado de elementos (int
vector[100], por ejemplo) y ahorrar el parmetro longitud, sin
embargo con la definicin
que hemos hecho nuestra funcin
funcionar con matrices de cualquier longitud de enteros.
Hemos declarado adems una variable local que es necesaria
para la realizacin del bucle actuando como contador y conteniendo
adems el ndice dentro de la matriz que buscamos. Si la entrada i
de nuestro vector corresponde con valor, salimos del bucle y la
variable i contiene ese valor de la entrada, el cual es devuelto
por la funcin mediante la instruccin return. Ahora veremos como
utilizaramos esta funcin desde un programa:
main ()
{
int
matriz1[20];
int
matriz2[30];
int
indice,dato;
/* Aqu realizaramos alguna operacin sobre las
a = b;
b = t;
}
Y nuestro programa principal podra ser algo como sto:
main ()
{
int
c,d;
c = 5;
d = 7;
swap (c,d);
}
Veamos que pasa en la memoria de nuestro ordenador.
-Funcin main()
-Espacio para la variable c (Posicin de memoria x)
-Espacio para la variable d (Posicin de memoria y)
-Inicializacin de las variables
-swap(c,d)
-Fin de main()
-Funcin swap
-Cdigo de la funcin swap
-Espacio privado para almacenar los parmetros (Posicin
de memoria z)
En este ltimo compartimiento es dnde almacenamos los
valores de nuestros parmetros que sern respectivamente 5 y 7.
Despus de la ejecucin de swap en esta zona de memoria los
valores
estn intercambiados,
nuestro parmetro
a que se
corresponde con la variable c en la llamada a swap contendr el
valor 7 y el parmetro b correspondiente a d en la funcin main
contendr el valor 5. Esto es lo que se encuentra almacenado en la
zona privada de memoria de la funcin. Con este esquema cuando la
funcin swap termina su ejecucin y se devuelve el control al
programa principal main, los valores de c y d no han cambiado,
puesto que los compartimientos o posiciones de memoria x e y no
han sido tocados por la funcin swap, la cual slo ha actuado
sobre el compartimiento z.
Si declaramos ahora nuestra funcin swap como sigue:
swap (int *p1,int *p2)
{
int
t;
t = *p1;
*p1 = *p2;
*p2 = t;
}
/*Metemos en t el contenido de p1 */
/* Contenido de p1 = contenido de p2 */
*p_int;
*mat;
entero y
memoria,
variable
el
la
free (p_int);
free(mat);
Hay que tener cuidado a la hora de liberar la memoria.
Tenemos que liberar todos los bloque que hemos asignado, con lo
cual siempre debemos tener almacenados los punteros al principio
de la zona que reservamos. Si mientras actuamos sobre los datos
modificamos el valor del puntero al inicio de la zona reservada,
la funcin free probablemente no podr liberar el bloque de
memoria.
5.2.3 Ventajas de la asignacin dinmica.
Vamos a exponer un ejemplos
en el que se aprecie
claramente la utilidad de la asignacin dinmica de memoria.
Supongamos que deseamos programar una serie de funciones
para trabajar con matrices. Una primera solucin sera definir una
estructura de datos matriz, compuesta por una matriz y sus
dimensiones puesto que nos
interesa que nuestras funciones
trabajen con matrices de cualquier tamao. Por tanto la matriz
dentro de la estructura tendr
el tamao mximo de todas las
matrices con las que queramos trabajar y como tenemos almacenadas
las dimensiones trabajaremos con una matriz de cualquier tamao
pero tendremos reservada memoria para una matriz de tamao mximo.
Estamos desperdiciando memoria. Una definicin de este tipo sera:
typedef struct
{
float
int
} MATRIZ;
mat[1000][1000];
ancho,alto;
*datos;
ancho,alto;
};
typedef struct mat *MATRIZ;
El tipo MATRIZ ahora debe ser un puntero puesto que
tenemos que reservar memoria para la estructura que contiene la
matriz en s y las dimensiones. Una funcin que nos crease una
matriz sera algo as:
MATRIZ
{
MATRIZ
temp------->datos---------->x*x elementos
ancho,alto
Esta estructura puede parecer en principio demasiado
compleja, pero veremos en el siguiente captulo que es muy til en
el encapsulado de los datos.
En nuestro programa
declararamos algo as:
main()
{
MATRIZ
principal, para
utilizar la
matriz
a;
a = inic_matriz (3,3);
...
borrar_matriz(a);
}
Dnde borrar_matriz(a) libera la memoria reservada en
inic_matriz,
teniendo
en
cuenta
que
se
realizaron dos
asignaciones, una para la estructura mat y otra para la matriz en
s.
Otra definicin posible del problema podra ser as.
typedef struct mat MATRIZ;
void inic_matriz (MATRIZ *p,int x,int y)
{
p->ancho = x;
p->alto = y;
p->datos = (float *)malloc(sizeof(float)*x*y);
}
sto:
Con
este esquema
main()
{
MATRIZ
el programa
principal sera
algo como
a;
inic_matriz (&a,3,3);
.....
borrar_matriz (&a);
}
Con
este
esquema
el
acceso
a
la matriz sera
*(a.datos+x+y*a.ancho), idntico al anterior sustituyendo los
puntos por flechas ->. En el siguiente captulo se justificar la
utilizacin de la primera forma de implementacin frente a esta
segunda. En realidad se trata de la misma implementacin salvo que
en la primera el tipo MATRIZ es un puntero a una estructura, por
tanto es necesario primero reservar memoria para poder utilizar la
estructura, mientras que en la segunda implementacin, el tipo
MATRIZ es ya en si la estructura, con lo cual el compilador ya
reserva la memoria necesaria. En el primer ejemplo MATRIZ a;
datos, la cual
el cdigo de las
el nuevo tipo
VECTOR.C
#include<stdio.h>
#include<stdlib.h>
#define VECTOR_C
struct vector
{
float
int
};
*componentes;
dimension;
temp->componentes=(float *)calloc(dimension,sizeof(float));
if (temp->componentes==0)
{
printf("\nno hay sitio en memoria");exit(1);
}
return temp;
}
void borrar_vector(VECTOR vec)
{
free(vec->componentes);
free(vec);
}
float leer_componente(VECTOR vec,int componente)
{
float x;
x=*(vec->componentes+componente);
return x ;
}
void escribir_componente(VECTOR vec,int componente,float valor)
{
*(vec->componentes+componente)=valor;
}
void suma(VECTOR uno,VECTOR dos,VECTOR tres)
{
int i;
if (uno->dimension!=dos->dimension) printf("\nerror");
else
if (uno->dimension!=tres->dimension) printf("\nerror");
else
for(i=0;i<uno->dimension;i++)
*(tres->componentes+i)=*(dos->componentes+i)+
*(uno->componentes+i);
}
En primer lugar se indican las librera que necesita
utilizar el fichero en s. En este caso la stdlib para las
asignaciones y liberaciones de memoria, y la stdio para sacar
mensajes de error por pantalla.
A continuacin definimos un tipo de datos para trabajar
con vectores, se trata de un vector y un entero que nos indica la
longitud, y finalmente el tipo de dato abstracto VECTOR como un
puntero a esta estructura. Como vemos dentro del fichero VECTOR.C
el dato VECTOR est perfectamente definido y la ocultacin de ste
se realiza en el fichero VECTOR.H.
En el fichero VECTOR.C podemos dividir las funciones en
varios tipos. En primer lugar estn las funciones crear_vector y
borrar_vector, las cuales se encargan de reservar y liberar la
memoria necesaria para cada elemento. Por otra parte tenemos las
funciones leer_componente y escribir_componente que nos permiten
acceder a la estructura de datos, dependiendo del tipo de datos
puede que no sea necesario que el programador acceda a los datos
en la estructura. Finalmente tenemos las funciones que realizan
operaciones con los vectores, sumar_vectores.
3.14159
vector->datos
esto
Hasta aqu (#endif)
Finalmente
veamos
como
utilizaramos
abstracto en un programa, para sumar dos vectores.
nuestro
tipo
#include"stdio.h"
#include"vector.h"
main()
{
VECTOR x,y,z;
int i;
x=crear_vector(3);
y=crear_vector(3);
z=crear_vector(3);
printf ("\n");
for(i=0;i<3;i++)
escribir_componente(x,i,i);
for(i=0;i<3;i++)
escribir_componente(y,i,i+2);
suma(x,y,z);
for(i=0;i<3;i++)
{
printf("\n%f + %f = %f",leer_componente(x,i),
leer_componente(y,i),leer_componente(z,i));
}
borrar_vector (x);
borrar_vector (y);
borrar_vector (z);
}
TEMA 6 : Entrada y salida (E/S) de datos
6.0 Introduccin
El objetivo de este tema es hacer un estudio completo en
todo lo referente a la entrada y, salida (E/S) en C, estudiando
tambin los dos sistemas de ficheros que existen en este lenguaje.
6.1 Entrada y salida (E/S)
Las operaciones de entrada y salida (abreviadamente E/S) no
forman parte del lenguaje C propiamente dicho, sino que estn en una
biblioteca o
librera: <stdio.h>. Todo
programa que utilice
funciones de entrada y salida estndar deber contener la lnea:
#include <stdio.h>
6.1.1 E/S estndar
Por defecto, la entrada estndar es el teclado y la salida
estndar es la pantalla o monitor. Hay dos formas bsicas de cambiar
la entrada y la salida estndar:
1. Con los smbolos de redireccin (<, >, <<, >>) o de tubera (|)
del sistema operativo al ejecutar el programa desde la lnea de
rdenes.
ficheros
no
pueden
abrirse
ni
cerrarse
leer o en la que
para
realizar
operaciones
con un
cuyo
nombre_fichero no se
puede abrir
FILE *pf;
if ((pf = fopen ("prueba", "rb")) == NULL)
{
puts ("Error al intentar abrir el fichero.");
exit (1);
}
/* ... */
if (fclose (pf) != 0)
{
puts ("Error al intentar cerrar el fichero.");
exit (1);
}
Resumen de los 4 pasos para la manipulacin de un fichero:
---------------------------------------------------------1) Declarar un puntero de fichero.
FILE *pf;
2) Abrirlo el fichero.
if ((pf = fopen ("nombre_fichero", "modo_apertura")) == NULL)
error ();
else
/* ... */
3) Realizar las operaciones deseadas con el fichero.
/* En las siguientes ventanas veremos las
funciones que tenemos para ello. */
4) Cerrar el fichero.
if (fclose (pf) != 0)
error ();
else
/* ... */
6.7 Sistema de ficheros tipo UNIX
Debido a que el lenguaje C se desarroll inicialmente bajo
el sistema operativo UNIX, se cre un segundo sistema de ficheros. A
este sistema se le llama E/S sin buffer, E/S de bajo nivel o E/S
tipo UNIX. Hoy en da, este sistema de ficheros est totalmente en
desuso y se considera obsoleto, adems el nuevo estndar ANSI ha
decidido no estandarizar el sistema de E/S sin buffer tipo UNIX. Por
todo lo dicho no se puede recomendar este sistema a los nuevos
programadores C. Sin embargo, todava existen programas que lo usan
y es soportado por la mayora de los compiladores de C. As que
incluimos una breve explicacin al respecto.
6.7.1 Descriptores de ficheros
A diferencia del sistema de E/S de alto nivel, el sistema de
bajo nivel no utiliza punteros a ficheros de tipo FILE; el sistema
de bajo nivel utiliza descriptores de fichero de tipo int. A cada
fichero se le asocia un nmero (su descriptor de fichero).
Hay tres descriptores de fichero predefinidos:
0
1
2
entrada estndar
salida estndar
salida de errores estndar
fichero con
4) Cerrar el fichero.
close (fd);
las funciones
EJEMPLOS
/*
+----------------------------------------+
| BUSQUEDA BINARIA (BUSQUEDA DICOTOMICA) |
+----------------------------------------+
En este programa se realiza una bsqueda binaria (llamada
tambin dicotmica) en un vector ordenado de nmeros enteros.
Este algoritmo es
vlido exclusivamente para vectores
ordenados y consiste en comparar en primer lugar con la componente
central del vector, y si no es igual al valor buscado se reduce el
intervalo de bsqueda a la mitad derecha o izquierda segn donde
pueda encontrarse el valor a buscar. El algoritmo termina si se
encuentra el valor buscado o si el tamao del intervalo de bsqueda
queda anulado.
En los casos en que existan repeticiones en el vector, del
valor buscado, este algoritmo obtendr uno de ellos aleatoriamente
segn los lugares que
ocupen, los cuales necesariamente son
consecutivos.
*/
#include <stdio.h>
/*
+----------------------------+
| PERMUTACIONES DE UN VECTOR |
+----------------------------+
Este programa lee los elementos de un vector y escribe
todas las permutaciones (combinaciones sin repeticin) posibles de
los elementos introducidos en el vector.
El nmero de permutaciones
por el factorial de n.
if (getch () == 27)
exit (0);
/* con estas tres funciones se borra el mensaje anterior */
putchar ('\r');
printf ("
"
");
putchar ('\r');
"
}
printf ("Permutacin %2u: ", numero_de_permutacion);
for (i = 1; i <= vect[0]; i++)
printf ("%d ", vect[i]);
putchar ('\n');
}
void permutar (int v[], int m)
{
register int i;
if (m > 1)
for (i = 1; i <= m; i++)
{
intercambiar (&v[i], &v[m]);
permutar (v, m-1);
intercambiar (&v[i], &v[m]);
}
else
escribir_vector (v);
}
void intercambiar (int *p1, int *p2)
{
int aux;
aux = *p1;
*p1 = *p2;
*p2 = aux;
}
/*
+---------------------------+
| ORDENACION RAPIDA (QSORT) |
+---------------------------+
En este programa se realiza
vector de nmeros enteros.
El
mtodo de
la ordenacin creciente
ordenacin seguido
ha sido
de un
el de ordenacin
rpida.
La ordenacin rpida, inventada y nombrada por C.A.R. Hoare,
est considerada como el mejor algoritmo de ordenacin disponible
actualmente. Est basada en la
ordenacin por el mtodo de
intercambio.
La ordenacin rpida se basa en la idea de las particiones.
El procedimiento general es seleccionar un valor llamado comparando
y entonces dividir el array en dos partes. En un lado todos los
elementos mayores o iguales al valor de particin y en otro todos
se repite en cada
*/
Secuencia inicial
8
2
5
3
9
Elemento comparando: 5
Primer paso
3
2
5
8
9
Ahora se ordena con el mismo procedimiento los vectores '3 2' y
'8 9'
while (vect[i] < elem && j < ind_der) /* recorrido del vector
hacia la derecha */
i++;
while (elem < vect[j] && j > ind_izq) /* recorrido del vector
hacia la izquierda */
j--;
if (i <= j) /* intercambiar */
{
int aux; /* variable auxiliar */
aux = vect[i];
vect[i] = vect[j];
vect[j] = aux;
i++;
j--;
}
} while (i <= j);
if (ind_izq < j)
ordenar (vect, ind_izq, j);
if (i < ind_der)
ordenar (vect, i, ind_der);
/*
+-----------------+
| LAS OCHO REINAS |
+-----------------+
El problema de las ocho reinas consiste en situar ocho
reinas en un tablero de ajedrez, de forma que ninguna reina pueda
actuar sobre cualquiera de las otras.
RANGO:
RANGO:
RANGO:
RANGO:
1..8
1..8
-7..7
2..16
c(i) posiciones_en_columna[(i)-1]
f(i) reina_en_fila[(i)-1]
dn(i) reina_en_diagonal_normal[(i)+7]
di(i) reina_en_diagonal_inversa[(i)-2]
de
estos
datos,
la
lnea
poner
reina
del
f (j) = di (i + j) = dn (i - j) = TRUE;
y la condicin segura del pseudocdigo:
f (i) && di (i + j) && dn (i - j)
*/
/* Ficheros a incluir: */
#include <stdio.h>
#include <conio.h>
/* printf () */
/* getch () */
/* Macros: */
#define BOOLEAN int
#define TRUE
1
#define FALSE
0
/* Variables globales: */
BOOLEAN acertado;
int posiciones_en_columna[8];
BOOLEAN reina_en_fila[8];
BOOLEAN reina_en_diagonal_normal[15];
BOOLEAN reina_en_diagonal_inversa[15];
#define c(i) posiciones_en_columna[(i)-1]
/* rango de ndice: 1..8 */
#define f(i) reina_en_fila[(i)-1]
/* rango de ndice: 1..8 */
#define dn(i) reina_en_diagonal_normal[(i)+7]
/* rango de ndice: -7..7 */
#define di(i) reina_en_diagonal_inversa[(i)-2]
/* rango de ndice: 2..16 */
/* Prototipos de las funciones: */
void proceso (void);
void ensayar (int i);
/* Definiciones de las funciones: */
void main (void)
{
printf ("\n\nPROBLEMA DE LAS OCHO REINAS:\n ");
proceso ();
printf ("\n\nPulsa cualquier tecla para finalizar. ");
getch ();
}
void proceso (void)
{
register int i,j;
for (i = 1; i <= 8; i++)
f (i) = TRUE;
for (i = 2; i <= 16; i++)
di (i) = TRUE;
for (i = -7; i <= 7; i++)
dn (i) = TRUE;
ensayar (1);
if (acertado)
for (printf ("\n\nLA SOLUCION ES:\n\n"), i = 1; i <= 8; i++)
{
for (j = 1; j <= 8; j++)
printf ("%2d", c (j) == i ? 1 : 0);
printf ("\n");
}
else
printf ("\n\nNO HAY SOLUCION.\n");
j++;
acertado = FALSE;
if (f (j) && di (i + j) && dn (i - j))
{
c (i) = j;
f (j) = di (i + j) = dn (i - j) = FALSE;
if (i < 8)
{
ensayar (i + 1);
if (! acertado)
f (j) = di (i + j) = dn (i - j) = TRUE;
}
else
acertado = TRUE;
}
} while (! acertado && j != 8);
/*
+-------------------+
| SALTO DEL CABALLO |
+-------------------+
Este programa realiza lo siguiente: Se da un tablero de nxn
con n*n cuadros. Un caballo -que puede moverse segn las reglas del
ajedrez- se sita en el
cuadro de coordenadas (x0,y0). Se pide
encontrar, si existe, un recubrimiento del tablero completo, o sea,
calcular un circuito de n*n-1 movimientos de forma que cada cuadro
del tablero sea visitado exactamente una vez.
La solucin a este problema
tanteo sistemtico (intento y error).
La funcin ms importante
el siguiente:
est basado
en el
mtodo de
<PRINCIPIO ensayar>
REPETIR seleccionar el nuevo candidato de la lista de futuros
movimientos
SI aceptable ENTONCES
SI tablero no lleno ENTONCES
LLAMAR ensayar nuevo movimiento
SI no acertado ENTONCES
borrar la anotacin anterior
FINSI
FINSI
FINSI
HASTA movimiento acertado O no hay ms posibilidades
<FIN>
Observaciones sobre el cdigo:
1) Estudiar la funcin ensayar() a partir de este pseudocdigo.
2) El mtodo utilizado para obtener el movimiento del caballo de
(x1,y1) hasta
(x2,y2) es sumar
a (x1,y1) los
vectores de
diferencias.
Los vectores de diferencia dif_x y dif_y contienen la
diferencia de la coordenada x e y respectivamente desde la posicin
actual del caballo.
Vese con el siguiente tablero:
0
de las
asignaciones a
los elementos
de la
que se encuentre la
/* Ficheros a incluir: */
#include <stdio.h> /* printf () */
#include <conio.h> /* getch () */
#include <stdlib.h> /* exit () */
/* Macros: */
#define NUM_MOVIMIENTOS_POSIBLES 8
#define NMAXIMO 8
#define BOOLEAN int
#define TRUE
1
#define FALSE
0
#define ESC 27
#define en(x,x1,x2) ((x) >= (x1) && (x) <= (x2))
#define tab(i,j) tablero[(i)-1][(j)-1]
/* tab(1,1) es en realidad
tablero[0][0] */
/* Variables globales: */
int n, tablero[NMAXIMO][NMAXIMO];
BOOLEAN movimiento_acertado;
int dif_x [NUM_MOVIMIENTOS_POSIBLES] =
{ 2, 1, -1, -2, -2, -1, 1, 2 },
dif_y [NUM_MOVIMIENTOS_POSIBLES] =
{ 1, 2, 2, 1, -1, -2, -2, -1 };
/* Prototipos de las funciones: */
void proceso (void);
void ensayar (int i, int x, int y);
/* Definiciones de las funciones: */
void main (void)
{
do
{
printf ("\n\nVUELTA DEL CABALLO:\n ");
proceso ();
printf ("\nPulsa cualquier tecla para repetir "
"o ESC para salir. ");
} while (getch () != ESC);
}
void proceso (void)
{
register int i, j;
int x0, y0;
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++)
tab (i, j) = 0;
if (movimiento_acertado)
for (printf ("\n\nLA SOLUCION ES:\n
{
for (j = 1; j <= n; j++)
printf ("%2d ", tab (i, j));
printf ("\n ");
}
else
printf ("\n\nNO HAY SOLUCION.\n");
{
movimiento_acertado = FALSE;
x2 = x1 + dif_x[movimientos_realizados];
y2 = y1 + dif_y[movimientos_realizados];
movimientos_realizados++;
if (kbhit ())
if (getch () == ESC)
exit (1);
printf ("Nmero de movimientos del caballo (ESC para salir): "
"%ld\r", ++num_movimientos_caballo);
if (en (x2, 1, n) && en (y2, 1, n) && tab (x2, y2) == 0)
{
tab (x2, y2) = i;
if (i < ncuadrado)
{
}
} while (! movimiento_acertado &&
movimientos_realizados != NUM_MOVIMIENTOS_POSIBLES);
}
/*
+-----------------------------------------------+
| COPIA DE UN FICHERO (SIMILAR AL COPY DEL DOS) |
+-----------------------------------------------+
Este
programa
copia
un
fichero
a
otro
fichero.
Funcionalmente este programa es similar al copy del DOS o al cat del
UNIX. Si el fichero de salida es con, se est haciendo un type del
DOS. Si el fichero de entrada es con, recuerda que el carcter fin
de fichero se escribe con CTRL-Z en el DOS.
La funcin strcpy() copia el string pasado como segundo
argumento en el string pasado como primer argumento. La funcin
toupper() devuelve el carcter pasado como argumento en mayscula.
*/
#include <stdio.h>
/*
+-------------------------+
| COMPARACION DE FICHEROS |
+-------------------------+
Este programa
iguales o distintos.
*/
compara
dos
ficheros
determina
si son
#include <stdio.h> /* printf (), gets (), fprintf (), stderr, EOF,
fopen (), fclose (), fgets (), fputs (), NULL */
#include <conio.h> /* getch () */
#include <string.h> /* strcpy (), strstr () */
#include <ctype.h> /* toupper () */
#define BOOLEAN int
#define TRUE
#define FALSE
1
0
#define ESC 27
#define ENTER '\r'
#define NUMMAXCARACTERES 255
void main (void)
{
BOOLEAN salir = FALSE;
char nombre_fichero_1[NUMMAXCARACTERES],
nombre_fichero_2[NUMMAXCARACTERES];
FILE *pf1, *pf2; /* punteros a fichero de entrada y fichero de
salida resp. */
char ch;
while (! salir)
{
puts ("\n\nCOMPARAR DOS FICHEROS:\n");
printf ("Introduzca nombre de primer fichero (ENTER o CON para "
"teclado): ");
gets (nombre_fichero_1);
if (*nombre_fichero_1 == '\0')
strcpy (nombre_fichero_1, "con");
printf ("Introduzca nombre de segundo fichero (ENTER o CON "
"para teclado): ");
gets (nombre_fichero_2);
if (*nombre_fichero_2 == '\0')
strcpy (nombre_fichero_2, "con");
if ((pf1 = fopen (nombre_fichero_1, "r")) == NULL)
fprintf (stderr, "\nERROR: No es posible abrir el fichero "
"%s.\n", nombre_fichero_1);
else if ((pf2 = fopen (nombre_fichero_2, "r")) == NULL)
{
fprintf (stderr, "\nERROR: No es posible abrir el fichero "
%"s.\n", nombre_fichero_2);
fclose (pf1);
}
else
{
int ch1, ch2;
while ((ch1 = fgetc (pf1)) == (ch2 = fgetc (pf2)) && ch1
!= EOF) ;
printf ("\nLos dos ficheros comparados son %s.\n", feof
(pf1) && feof (pf2) ? "iguales" : "distintos");
fclose (pf1);
fclose (pf2);
/*
+----------------------------------------------------+
| ORDENACION DE UN FICHERO (SIMILAR AL SORT DEL DOS) |
+----------------------------------------------------+
Este programa lee las lneas de un fichero de entrada (que
puede ser la consola) y escribe las lneas ordenadas en un fichero
de salida (que puede ser la consola).
*/
#include <stdio.h> /* printf (), gets (), FILE, fopen (), fclose (),
NULL, fprintf (), fgets () */
#include <stdlib.h> /* exit () */
#include <alloc.h> /* malloc (), free () */
#include <conio.h> /* getch () */
#include <string.h> /* strcmp (), strcpy () */
#include <ctype.h> /* toupper () */
#define
#define
#define
#define
#define
#define
BOOLEAN int
TRUE
1
FALSE
0
ESC 27
ENTER '\r' /* no vale '\n' */
NUMMAXCARACTERES 255
struct nodo_arbol
{
char linea[NUMMAXCARACTERES];
struct nodo_arbol *pizq, *pder;
};
void
void
void
void
void
}
void inicializar_arbol (struct nodo_arbol **parb)
{
*parb = NULL;
}
void hacer_nodo_arbol (struct nodo_arbol **pa)
{
if ((*pa = (struct nodo_arbol *) malloc (sizeof (struct
nodo_arbol))) == NULL)
{
printf ("\nERROR: Memoria insuficiente.");
exit (1);
}
}
void insertar_en_arbol (struct nodo_arbol **parb, char *lin)
{
struct nodo_arbol *p, *pant, *pa;
hacer_nodo_arbol (&pa);
strcpy (pa->linea, lin);
pa->pizq = pa->pder = NULL;
p = *parb;
pant = NULL;
while (p != NULL)
{
pant = p;
if (strcmp (p->linea, lin) > 0)
p = p->pizq;
else
p = p->pder;
}
if (pant == NULL)
*parb = pa;
else if (strcmp (pant->linea, lin) > 0)
pant->pizq = pa;
else
pant->pder = pa;
/*
+--------------------+
| SHELL CRONOMETRADO |
+--------------------+
Este programa ejecuta otro programa cronomentrando el tiempo
empleado en la ejecucin del segundo. El programa a ejecutar puede
ser un programa ejecutable con extensin .EXE o .COM, un fichero por
lotes .BAT o un comando interno del DOS como dir. Adems dicho
programa se puede ejecutar con argumentos.
El main() que est entre comentarios es la versin que toma
los datos desde la lnea de rdenes del sistema operativo en vez de
preguntar por ellos con las funciones de entrada estndar como se
hace en el main() actual.
*/
#include
#include
#include
#include
#include
<process.h> /* system () */
<stdio.h>
/* puts (), printf () */
<time.h>
/* time_t, difftime (), time () */
<string.h> /* strcat () */
<conio.h> /* getch () */
/*
void main (int argc, char **argv);
*/
void main (void);
void ejecutar (char *);
/*
void main (int argc, char **argv)
{
if (argc == 1)
puts ("\nEste programa cronometra el tiempo empleado al ejecutar
el programa\npasado como argumento.\n");
else
{
int cont;
char nombre_programa_a_ejecutar[256] = { 0 };
for (cont = 1; cont < argc; cont++)
{
if (*nombre_programa_a_ejecutar)
strcat (nombre_programa_a_ejecutar, " ");
strcat (nombre_programa_a_ejecutar, *(argv+cont));
}
ejecutar (nombre_programa_a_ejecutar);
}
}
*/
void main (void)
{
char nombre_programa_a_ejecutar[256] = { 0 };
printf ("\nIntroduzca nombre de programa a ejecutar: ");
do
{
gets (nombre_programa_a_ejecutar);
} while (!*nombre_programa_a_ejecutar);
ejecutar (nombre_programa_a_ejecutar);
getch ();
}
void ejecutar (char *nombre_programa)
{
int valor_devuelto;
time_t tiempo1, tiempo2;
tiempo1 = time (NULL);
valor_devuelto = system (nombre_programa);
tiempo2 = time (NULL);
if (valor_devuelto == -1)
printf ("\nError al intentar ejecutar el programa \"%s\".",
nombre_programa);
else
{
int horas, minutos, segundos;
/*
+---------------------------------------+
| VISUALIZACION DE 256 BYTES DE MEMORIA |
+---------------------------------------+
Este programa visualiza 256 bytes de memoria a partir de la
direccin de comienzo especificada (en hexadecimal).
*/
#include <stdio.h> /* printf (), scanf () */
#include <conio.h> /* getch () */
void main (void)
{
register int i;
unsigned char ch, *p;
printf ("VISUALIZAR MEMORIA.\n\n");
printf ("Direccin de comienzo (en hex): ");
scanf ("%p%*c", &p);