Professional Documents
Culture Documents
programacin
con
Object Pascal
Free Pascal / Lazarus
Escrito por: Motaz Abdel Azeem
Editado por: Pat Anderson, Jason Hackney
code.sd
30 Agosto 2012
Introduccin
Este libro est escrito para los programadores que quieran aprender el lenguaje Object Pascal.
Tambin es adecuado como primer libro de programacin para estudiantes nveles y no
programadores. Adems del lenguaje Object Pascal, se tratan tcnicas de programacin en general.
El lenguaje Object Pascal
La primera aparicin del lenguaje Pascal que di apoyo a la programacin orientada a objetos fu
realizado en 1983 por la compaa de computadoras Apple. Despus, Borland di soporte a la
programacin orientada a objetos a su famosa lnea Turbo Pascal.
Object Pascal es un lenguaje hbrido de propsito general (programacin orientada a objetos y
estructurada). Puede ser utilizado para una amplia gama de aplicaciones tales como el aprendizaje,
desarrollo de juegos, aplicaciones de negocios, aplicaciones de Internet, aplicaciones de
comunicacin, el desarrollo de herramientas y ncleos del sistema operativo.
Delphi
Tras el xito de Turbo Pascal, Borland decidi portarlo a Windows e introdujo la tecnologa de
componentes para ello. Delphi pronto se convirti en la mejor herramienta RAD (Rapid Application
Development) herramienta de ese momento.
La primera versin de Delphi fue lanzado en 1995 con un completo conjunto de componentes y
paquetes que soportaban Windows y el desarrollo de base de datos en las aplicaciones
Free Pascal
Despus de que Borland abandon el soporte para la lnea Turbo Pascal , el equipo de Free Pascal
comenz un proyecto de cdigo abierto para escribir desde cero un nuevo compilador compatible
con Turbo Pascal y luego con Delphi. Esta vez, el compilador Free Pascal estaba apuntando a otras
plataformas y sistemas operativos, como Windows, Linux, Mac, ARM, y WinCE.
La versin 1.0 del compilador Free Pascal fue lanzado en julio de 2000.
Lazarus
Free Pascal es un compilador, y carece de un entorno de desarrollo integrado (IDE) similar al IDE
de Delphi para Windows. El proyecto Lazarus se inici para proporcionar un IDE para Free Pascal.
Proporciona un editor de cdigo fuente, un depurador, y contiene una gran cantidad de marcos,
paquetes y libreras de componentes similares al IDE de Delphi.
La versin 1.0 de Lazarus fu publicada en agosto de 2012, pero hay una gran cantidad de
aplicaciones desarrolladas con las versiones anteriores (beta) de Lazarus. Una gran cantidad de
voluntarios escribieron paquetes y componentes de Lazarus, y la comunidad sigue creciendo.
Creditos:
Primer Editor:
Pat Anderson se gradu de la Western Washington State College en 1968 y en la Escuela de
Derecho de Rutgers en 1975. Se desempea como Abogado de la Ciudad de Snoqualmie,
Washington. Pat comenz a programar en un modelo de Radio Shack TRS-80 III en 1982 con
intrprete BASIC incorporado, pero pronto descubri Turbo. l ha sido propietario de todas las
versiones de Turbo Pascal desde la 4,0 a la 7,0, y todas las versiones de Delphi desde la 1,0 a la 4,0.
Pat tom un descanso de la programacin a partir de 1998 hasta 2009, cuando se encontr con Free
Pascal / Lazarus, que reaviv su pasin por la programacin.
Segundo Editor
Jason Hackney es un graduado de la Escuela de Aviacin de la Universidad de Western Michigan.
l trabaja a tiempo completo como piloto profesional para una empresa de energa con sede en el
sudeste de Michigan. Jason ha sido un ocasional programador desde su primer contacto con el
Commodore 64 por el ao 1984. Una breve introduccin del Turbo Pascal en 1990, recientemente
reaviv su latente inters por la programacin despus de descubrir Linux, Lazarus, y Free Pascal.
Traductores: http://www.clubdelphi.com
mightydragonlor
FAUST
MAXIUM
AL GONZALEZ
rretamar
champy
Esta edicin:
Eduardo O. Lpez Garca
Licencia:
II
CC by http://creativecommons.org/licenses/by/3.0/deed.es
Entorno para los ejemplos del libro
Vamos a utilizar Lazarus y Free Pascal para todos los ejemplos de este libro. Usted puede obtener el
IDE Lazarus, incluyendo el compilador Free Pascal, desde este sitio: http://lazarus.freepascal.org
Si est usando Linux, entonces usted puede conseguir Lazarus en el repositorio de software. En
Ubuntu desde la consola se puede utilizar el comando:
sudo apt-get install lazarus
En Fedora puede usar el comando:
yum install lazarus
En Mandriva (o Mageia), puede usar el comando:
urpmi lazarus
Windows, Mac y BSD descargar desde:
Compilador: http://sourceforge.net/projects/freepascal
RAD/IDE: http://sourceforge.net/projects/lazarus/?
Lazarus es una aplicacin gratuita y de cdigo abierto. Y est disponible en muchas plataformas.
Las aplicaciones escritas en Lazarus se pueden volver a compilar en otra plataforma para producir
ejecutables para la misma. Por ejemplo, si usted escribe una aplicacin que utiliza Lazarus en
Windows, y desea producir un ejecutable de esa aplicacin para Linux, slo tiene que copiar el
cdigo fuente a Lazarus en Linux, y compilarlo.
Lazarus produce aplicaciones que son nativas (compiladas) de cada sistema operativo, y no requiere
ninguna librera adicional o mquinas virtuales. Por esa razn, es fcil de implementar y rpido en
su ejecucin.
Usando modo texto
Todos los ejemplos en los primeros captulos de este libro sern las aplicaciones de consola
(aplicaciones en modo texto / aplicaciones de lnea de comandos), ya que son estndares y fciles
de entender. Las aplicaciones con interfaz grfica de usuario se introducirn en captulos
posteriores.
III
Indice
1.........................................................................................................Introduccin
1........................................................................................................Captulo Uno
1.........................................................................................Lo bsico del lenguaje
2..............................................................................Nuestra primera Aplicacin
4.............................................................................................Otros ejemplos
6..........................................................................................................Variables
10.........................................................................................................Subtipos
11...........................................................................Bifurcaciones condicionales
11............................................................................................La condicin If
11................................................................Programa aire acondicionado:
13.......................................................................................Programa peso
15................................................................................Declaracin Case .. of
15............................................................................Programa restaurante
15........................................ Programa restaurante usando la condicin If
16............................................................Programa grados de estudiantes
17...................................................................................Programa teclado
19.............................................................................................................Ciclos
19..................................................................................................El ciclo for
20................................................. Tabla de multiplicar usando el ciclo for
21................................................................................. Programa factorial
22.......................................................................................Ciclo Repeat Until
22....................................... Programa restaurante usando el ciclo Repeat
24.................................................................................................Ciclo While
24............................................... Programa factorial usando el ciclo while
25............................................................................................................Strings
28..............................................................................................Funcin Copy
29..................................................................................Procedimiento Insert
30.................................................................................Procedimiento Delete
30...............................................................................................Funcin Trim
31................................................................................Funcin StringReplace
33..........................................................................................................Arreglos
36........................................................................................................Registros
37.........................................................................................................Archivos
38.......................................................................................Archivos de texto
39.........................................................................Leer un archivo de texto
41.......................................Creando y escribiendo en un archivo de texto
43.............................................................Agregando en un archivo de texto
43.........................................Programa agregando en un archivo de texto
44......................................................................Archivos de acceso aleatorio
44........................................................................................Archivos con tipo
45.................................................................................Programa de notas
46................................................................Leyendo notas de estudiantes
46.................................................Programa agregando notas de alumnos
48.........................................Programa crear y agregar notas de alumnos
49...............................................Programa base de datos de automoviles
50......................................................................................Copiando archivos
51........................................................Copiar archivos usando file of byte
53.........................................................................................Archivos sin tipo
IV
VI
Captulo Uno
Lo bsico del lenguaje
Podemos guardar este programa haciendo click en File/Save desde el menu principal, y entonces
darle un nombre como por ejemplo, first.lpi.
Entonces podemos escribir estas lneas entre las declaraciones begin y end:
Writeln('Esto es Free Pascal y Lazarus');
Writeln('Presione la tecla Enter para cerrar');
Readln;
Si usamos Linux, nos encontraremos con un nuevo archivo llamado (first) en un directorio de
programa y en Windows tendremos un archivo llamado first.exe. Ambos archivos se pueden
ejecutar directamente haciendo doble clic con el ratn. El archivo ejecutable se puede copiar a otros
ordenadores para funcionar sin la necesidad de la IDE de Lazarus.
Notas
Si la ventana de aplicacin de consola no aparece, podemos deshabilitar la depuracin en el men
de Lazarus:
Environment/Options/Debugger
En Debugger type and path seleccione (None)
Otros ejemplos
En el programa anterior cambie esta lnea:
Writeln('Esto es Free Pascal y Lazarus');
por esta:
Writeln('Este es un nmero: ', 15);
Salida:
Este es un nmero: 5
Cdigo:
Writeln('5 * 2 = ', 5 * 2);
Salida:
5 * 2 = 10
Codigo:
Writeln('Este es un nmero real: ', 7.2);
Salida:
Este es un nmero real: 7.2000000000000E+0000
Cdigo:
Writeln('Uno, Dos, Tres : ', 1, 2, 3);
Salida:
Uno, Dos, Tres : 123
Cdigo:
Writeln(10, ' * ',
Salida:
10 * 3 = 30
Podemos escribir diferentes valores en la declaracin Writeln cada vez y ver el resultado. Esto nos
ayudar a entenderlo clramente.
Variables
Las variables son contenedores de datos. Por ejemplo cuando decimos que X = 5, , significa que X
es una variable y el valor de su contenido es 5.
Object Pascal es un lenguaje fuertemente tipapdo, esto quiere decir que deber declarar el tipo de
variable antes de poder poner un valor dentro de ella. Si declaramos X como Integer, significa que
slo podremos asignar nmeros enteros a X durante el tiempo de vida de la aplicacin.
Ejemplos de declaracin y uso de variables:
program FirstVar;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes
{ usted puede agregar unidades despues de aqu };
var
x: Integer;
begin
x:= 5;
Writeln(x * 2);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.
var
x, y: Integer;
begin
x:= 5;
y:= 10;
Writeln(x * y);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.
Este tipo slo puede contener una letra o nmero tomado como caracter alfanumrico no como
valor.
En el siguiente ejemplo introducimos el nmero tipo real, que puede poseer parte decimal:
var
x: Single;
begin
x:= 1.8;
Writeln('La capacidad del motor de mi auto es ', x, ' litros');
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.
Para escribir aplicaciones mas flexibles e interactivas, necesitamos aceptar ingresos del usuario. Por
ejemplo podramos pedirle al usuario que introduzca el nmero y a continuacin obtener este
nmero mediante el uso del procedimiento Readln:
var
x: Integer;
begin
Write('Por favor introduzca un nmero:');
Readln(x);
Writeln('Ha introducido: ', x);
Writeln('Presione la tecla enter para cerrar');
Readln;
end.
En este ejemplo, la asignacin del valor a X se realiza a travs del teclado en lugar de asignar un
valor constante en la aplicacin.
En el siguiente ejemplo se muestra una tabla de multiplicar para un nmero introducido por el
usuario:
program MultTable;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes
{ usted puede agregar unidades despues de aqu };
var
x: Integer;
begin
Write('Por favor introduzca un nmero:');
Readln(x);
Writeln(x, ' * 1 = ', x * 1);
Writeln(x, ' * 2 = ', x * 2);
Writeln(x, ' * 3 = ', x * 3);
Writeln(x, ' * 4 = ', x * 4);
Writeln(x, ' * 5 = ', x * 5);
Writeln(x, ' * 6 = ', x * 6);
Writeln(x, ' * 7 = ', x * 7);
Writeln(x, ' * 8 = ', x * 8);
Writeln(x, ' * 9 = ', x * 9);
Writeln(x, ' * 10 = ', x * 10);
Writeln(x, ' * 11 = ', x * 11);
Writeln(x, ' * 12 = ', x * 12);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.
Tenga en cuenta que en el ejemplo anterior todo el texto entre comillas simples (') se muestra en la
ventana de la consola tl como es, por ejemplo:
' * 1 = '
Las variables y expresiones que se escriben sin comillas simples se evalan y se escribe como
valores.
Vea las diferencias entre las dos declaraciones siguientes:
Writeln('5 * 3');
Writeln(5 * 3);
En el siguiente ejemplo, haremos operaciones matemticas con dos nmeros (x, y), y vamos a
asignar el resultado en una tercera variable (Res):
var
x, y: Integer;
Res: Single;
begin
Write('Ingrese un nmero: ');
Readln(x);
Write('Ingrese otro nmero: ');
Readln(y);
Res:= x / y;
Writeln(x, ' / ', y, ' = ', Res);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.
Como la operacin de divisin, podra dar lugar a un nmero con una fraccin, hemos declarado la
variable Resultado (Res) como un nmero real (Single). Single significa un nmero real con punto
flotante de simple precisin.
Subtipos
Hay muchos subtipos para las variables, por ejemplo los subtipos de numeros enteros difieren en el
nmero de bytes requeridos para almacenarse en memoria y los valores que son capaces de
almacenar:
La tabla siguiente contiene tipos enteros, rango de valores que admiten y los bytes que ocupan en
memoria:
Type
Min value
Max Value
Size in Bytes
Byte
255
ShortInt
-128
127
SmallInt
-32768
32767
Word
65535
Integer
-2147483648
2147483647
LongInt
-2147483648
2147483647
Cardinal
4294967295
Int64
-9223372036854780000
9223372036854775807
Podemos obtener los valores mximos y mnimos que cada tipo puede almacenar mediante las
funciones Low, High respectivamente, y el tamao que ocupan en memoria mediante la funcin
SizeOf , tl como se muestra en el siguiente ejemplo:
program Types;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes;
begin
Writeln('Byte: Tamao = ', SizeOf(Byte),
', Valor mnimo = ', Low(Byte), ', Valor mximo = ',
High(Byte));
Writeln('Integer: Tamao = ', SizeOf(Integer),
', Valor mnimo = ', Low(Integer), ', Valor mximo = ',
High(Integer));
Write('Presione la tecla Enter para cerrar');
Readln;
end.
10
Bifurcaciones condicionales
Una de las caractersticas ms importantes de dispositivos inteligentes (como ordenadores,
dispositivos programables) es que pueden tomar acciones acordes a diferentes condiciones. Esto se
puede hacer mediante el uso de bifurcacin condicional. Por ejemplo, algunos coches cierran la
puerta cuando la velocidad alcanza o supera los 40 K / h. La condicin en este caso ser:
If velocidad es >= 40 and puertas estn desbloqueadas, then lock door.
Automviles, lavadoras, y muchos otros dispositivos contienen circuitos programables como
microcontroladores o procesadores pequeos como ARM. Tales circuitos pueden programarse
usando Asembler, C o Free Pascal de acuerdo a su arquitectura.
La condicin If
La declaracin del condicional if es muy sencilla y clara. En el ejemplo siguiente decidiremos si se
debe encender el aire acondicionado o n, de acuerdo a la temperatura ambiente introducida:
Programa aire acondicionado:
var
Temp: Single;
begin
Write('Por favor ingrese la temperatura de esta habitacin:');
Readln(Temp);
if Temp > 22 then
Writeln('Por favor encienda el aire acondicionado')
else
Writeln('Por favor apague el aire acondicionado');
Write('Presione la tecla Enter para cerrar');
Readln;
end.
Hemos introducido la declaracin if then else , en este ejemplo: Si la temperatura es mayor que 22
entonces mostrar la primer sentencia
Por favor encienda el aire acondicionado
var
Temp: Single;
begin
Write('Por favor ingrese la temperatura de esta habitacin:');
Readln(Temp);
if Temp > 22 then
Writeln('Por favor encienda el aire acondicionado')
else
if Temp < 18 then
Writeln('Por favor apague el aire acondicionado')
else
Writeln('Do nothing');
Puede probar el ejemplo anterior con diferentes valores de temperatura para observar los resultados.
Podemos hacer las condiciones mas complejas para que sea mas til:
var
Temp: Single;
ACIsOn: Byte;
begin
Write('Por favor ingrese la temperatura de esta habitacin: ');
Readln(Temp);
Write(' Est el aire acondicionado encendido? (1 = Encendido,',
'0 = Apagado'));
Readln(ACIsOn);
if (ACIsOn = 1) and (Temp > 22) then
Writeln('No hacer nada, necesitamos seguir refrigerando')
else
if (ACIsOn = 1) and (Temp < 18) then
Writeln('Por favor apague el aire acondicionado')
else
if (ACIsOn = 0) and (Temp < 18) then
Writeln('No hacer nada, sigue haciendo fro')
else
if (ACIsOn = 0) and (Temp > 22) then
Writeln('Por favor encienda el aire acondicionado')
else
Writeln('Por favor ingrese un valor vlido');
Write('Presione la tecla Enter para cerrar');
Readln;
end.
En el ejemplo anterior hemos usado la nueva palabra (and) que significa que si la primera condicin
es verdadera (ACIsOn = 1), y tambin lo es la segunda (Temp > 22), entonces ejecuta la
declaracin Writeln. Si una o ambas de las condiciones es falsa saltar a la siguiente parte.
Si por ejemplo, el aire acondicionado est conectado a una computadora mediante un puerto serial
entonces podemos activarlo o desactivarlo desde esa aplicacin usandoutilizando procedimientos de
puerto serie o componentes que lo realicen. En este caso necesitamos agregar parmetros
adicionales para la condicin if, como por cuanto tiempo ha estado operando el aire acondicionado.
Si excede el tiempo permitido (por ejemplo 1 hora) entonces se debe desactivar independientemente
12
de la temperatura ambiente. Tambin podemos considerar la tasa de prdida de fro, si es muy lenta
(por la noche), entonces podramos mantenerlo apagado por ms tiempo.
Programa peso
En este ejemplo, se solicita al usuario que introduzca su altura en metros, y el peso en Kilos.
Entonces el programa calcular el peso adecuado para esa persona de acuerdo a los datos
introducidos y, a continuacin, le dir a l/ella los resultados:
program Weight;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ usted puede agregar unidades despues de aqu };
var
Height: Double;
Weight: Double;
IdealWeight: Double;
begin
Write('Cul es su altura en metros ? (por ejemplo 1,8 metros):');
Readln(Height);
Write(' Cul es su peso en kilos ?: ');
Readln(Weight);
if Height >= 1.4 then
IdealWeight:= (Height - 1) * 100
else
IdealWeight:= Height * 20;
if (Height < 0.4) or (Height > 2.5) or (Weight < 3) or
(Weight > 200) then
begin
Writeln('Valores no vlidos');
Writeln('Por favor, introduzca los valores adecuados');
end
else
if IdealWeight = Weight then
Writeln('Su peso es adecuado')
else
if IdealWeight > Weight then
Writeln('Usted est bajo de peso, usted necesita ',
Format('%.2f', [IdealWeight - Weight]), ' Kilos mas')
else
Writeln('Usted tiene sobrepeso, necesita perder ',
Format('%.2f', [Weight - IdealWeight]), ' Kilos');
Write('Presione la tecla Enter para cerrar');
Readln;
13
end.
Estas han sido convertidas a una sola declaracin mediante el uso de begin end:
if (Height < 0.4) or (Height > 2.5) or (Weight < 3) or
(Weight > 200) then
begin
Writeln('Valores invlidos');
Writeln('Por favor, introduzca los valores adecuados ');
end
4. Hemos utilizado el procedimiento Format, que muestra los valores en un formato especfico.
En este caso se necesita mostrar slo 2 dgitos despus del punto decimal. Tenemos que
aadir la unidad SysUtils a la clusula uses para poder utilizar esta funcin.
Cul es su altura en metros ? (por ejemplo 1,8 metros): 1.8
Cul es su peso en kilos ? : 60.2
Usted est bajo de peso, usted necesita 19.80 Kilos mas
Nota:
Este ejemplo puede no ser fiable al 100%. Puede buscar en la web para el clculo del peso en
detalle. Nosotros slo pretendemos explicar cmo el programador podra solucionar estos
problemas y hacer un buen anlisis de la materia para producir aplicaciones confiables.
14
Declaracin Case .. of
Existe otro mtodo para la ramificacin condicional, que es la declaracin Case .. Of. Se ramifica
ejecucin de acuerdo con el valor ordinal del caso. El programa del restaurante ilustra el uso de la
declaracin case of :
Programa restaurante
var
Meal: Byte;
begin
Writeln('Bienvenido al Restaurante Pascal. Por favor, seleccione su orden');
Writeln('1 - Pollo
(10$)');
Writeln('2 - Pescado
(7$)');
Writeln('3 - Carne
(8$)');
Writeln('4 Ensalada
(2$)');
Writeln('5 Jugo de naranja (1$)');
Writeln('6 Leche
(1$)');
Writeln;
Write('Por favor ingrese su eleccin: ');
Readln(Meal);
case Meal of
1: Writeln('Ud. ha ordenado pollo,',
' esto tardar 15 minutos');
2: Writeln('Ud. ha ordenado Pescado, esto tardar 12 minutos');
3: Writeln('Ud. ha ordenado Carne, esto tardar 18 minutos');
4: Writeln('Ud. ha ordenado Ensalada, esto tardar 5 minutos');
5: Writeln('Ud. ha ordenado Jugo de naranja,',
' esto tardar 2 minutos');
6: Writeln('Ud. ha ordenado Leche, esto tardar 1 minuto');
else
Writeln('Entrada errnea');
end;
Write('Presione la tecla Enter para cerrar');
Readln;
end.
15
Meal: Byte;
begin
Writeln('Welcome to Pascal restaurant, please select your meal');
Writeln('1 - Pollo
(10$)');
Writeln('2 - Pescado
(7$)');
Writeln('3 - Carne
(8$)');
Writeln('4 - Ensalada
(2$)');
Writeln('5 - Jugo de naranja (1$)');
Writeln('6 - Leche
(1$)');
Writeln;
Write('Por favor ingrese your selection: ');
Readln(Meal);
if Meal = 1 then
Writeln('Ud. ha ordenado Pollo, esto tardar 15 minutos')
else
if Meal = 2 then
Writeln('Ud. ha ordenado Pescado, esto tardar 12 minutos')
else
if Meal = 3 then
Writeln('Ud. ha ordenado Carne, esto tardar 18 minutos')
else
if Meal = 4 then
Writeln('Ud. ha ordenado Ensalada, esto tardar 5 minutos')
else
if Meal = 5 then
Writeln('Ud. ha ordenado Jugo de naranja,' ,
' esto tardar 2 minutos')
else
if Meal = 6 then
Writeln('Ud. ha ordenado Leche, esto tardar 1 minute')
else
Writeln('Entrada errnea');
Write('Presione la tecla Enter para cerrar');
Readln;
end.
En el siguiente ejemplo, la aplicacin evalua las notas de los estudiantes y las convierte en
categorias: A,B,C,D,E y F:
var
Mark: Integer;
begin
Write('Por favor ingrese la nota del estudiante: ');
Readln(Mark);
Writeln;
case Mark of
0 .. 39 : Writeln('El grado del estudiante es: F');
16
En el ejemplo previo hemos usado un rango, como (0..39), que indica que la condicin devolver
True si la nota se encuentra en dicho rango.
Note:
La declaracin Case trabaja solo con tipos ordinales como Integer, char, pero no lo hace con otros
tipos como string o nmeros reales.
Programa teclado
En este ejemplo, tomaremos un caracter desde el teclado y la aplicacin nos dir en que nmero de
fila del teclado se encuentra ese caracter:
var
Key: Char;
begin
Write('Por favor, introduzca una letra inglesa: ');
Readln(Key);
Writeln;
case Key of
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p':
Writeln('Est en la segunda fila del teclado');
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l':
Writeln('Est en la tercera fila del teclado ');
'z', 'x', 'c', 'v', 'b', 'n', 'm':
Writeln('Est en la cuarta fila del teclado');
else
Writeln('Letra desconocida');
end;
Write('Presione la tecla Enter para cerrar');
Readln;
end.
Tenga en cuenta que se ha utilizado una nueva tcnica en la condicin de case, que es un conjunto
17
dewhich means execute case branch statement if the Key was one of these values set: valores:
'z', 'x', 'c', 'v', 'b', 'n', 'm':
lo que significa que ejecutara la sentencia si Key tiene uno de los valores del set declarado:
z, x, c, v, b, n, m
Tambin se puede mezclar rangos de valores definidos as:
'a' .. 'd', 'x', 'y', 'z':
18
Ciclos
Los cclos son usados para ejecutar ciertas partes de cdigo (sentencias) una cantidad especfica de
veces, o hasta que una condicin sea satisfecha:
El ciclo for
Usted puede ejecutar la sentencia for un nmero determinado de veces usando un contador como en
este ejemplo:
var
i: Integer;
Count: Integer;
begin
Write('Cuantas veces? ');
Readln(Count);
for i:= 1 to Count do
Writeln('Hola');
Write('Presione la tecla Enter para cerrar');
Readln;
end.
Debemos utilizar tipos ordinales como Byte, Entero, y Char en las variables de bucle. Llamamos a
esta variable a variable de bucle o bucle contador. El valor del contador de bucles puede ser
inicializada con cualquier nmero, y tambin puede determinar el ltimo valor de contador de
bucle. Por ejemplo, si tenemos que contar de 5 a 10, entonces podemos hacer esto:
fori:=5to10do
Tenga en cuenta que esta vez tenemos que repetir dos declaraciones, y por ello se ha utilizado el
comenzar. . poner fin a las palabras clave para que sean un comunicado.
19
En lugar de escribir la declaracin Writeln 12 veces, se escribe una vez dentro de un bucle que se
ejecuta 12 veces.
Podemos hacer la declaracin del ciclo para que itere de forma decreciente usando la palabra clave
downto en lugar de la palabra clave to con esta sintxis:
for i:= 12 downto 1 do
20
Programa factorial
Factorial en matemticas es la multiplicacin de un nmero por cada uno de sus antecesores hasta el
nmero 1. Por ejemplo, 3! = 3 * 2 * 1 = 6.
var
Fac, Num, i: Integer;
begin
Write('Por favor ingrese un nmero: ');
Readln(Num);
Fac:= 1;
for i:= Num downto 1 do
Fac:= Fac * i;
Writeln('El factorial de ', Num ,' es ', Fac);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.
21
22
'2':
'3':
'4':
'5':
'6':
Price:= 10;
end;
begin
Writeln('Ud.
Price:= 7;
end;
begin
Writeln('Ud.
Price:= 8;
end;
begin
Writeln('Ud.
Price:= 2;
end;
begin
Writeln('Ud.
Price:= 1;
end;
begin
Writeln('Ud.
Price:= 1;
end;
else
begin
Writeln('Entrada errnea');
Price:= 0;
end;
end;
Total:= Total + Price;
until (Selection = 'x') or (Selection = 'X');
Writeln('Precio total
= ', Total);
Write('Presione la tecla Enter para cerrar');
Readln;
end.
4. Pusimos dos opciones para terminar los pedidos, ya sea X mayscula o x minscula Ambos
carcteres son diferentes en la representacin (de almacenamiento) en la memoria del
ordenador.
Nota:
Podramos reemplazar esta lnea:
23
Ciclo While
El ciclo while es similar a el ciclo repeat, pero difiere de l en los siguientes aspectos:
1. En el ciclo while la condicin es comprobada antes de ingresar al ciclo, mientras que repeat
entra al ciclo sin comprobacin alguna. Esto significa que repeat siempre ejecuta las
sentencias al menos una vez, en tanto que while puede prevenir la ejecucin al no ingresar al
ciclo si la condicin no se cumple al inicio.
2. El ciclo while necesita de begin/end si hay varias instrucciones que se deben ejecutar dentro
del bucle, pero repeat no no necesita begin/end, su bloque (declaraciones repetidas) se inicia
a partir de la palabra clave repeat hasta la palabra clave until
Ejemplo:
var
Num: Integer;
begin
Write('Ingrese un nmero: ');
Readln(Num);
while Num > 0 do
begin
Write('Desde el interior de bucle : Ingrese un nmero : ');
Readln(Num);
end;
Write('Presione la tecla Enter para cerrar');
Readln;
end.
24
Fac:= 1;
i:= Num;
while i > 1 do
begin
Fac:= Fac * i;
i:= i - 1;
end;
Writeln('El factorial de ', Num ,' es ', Fac);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.
El bucle while no tiene contador de ciclos, y por esa razn se ha utilizado la variable i para hacer de
contador del bucle. El valor del contador de ciclos se inicia al valor del nmero del nmero del que
necesitamos obtener su factorial, entonces tenemos que reducir su valor de forma manual en cada
ciclo. Cuando el valor de i llegue a 1, el bucle finaliza.
Strings
El tipo String se utiliza para declarar variables que pueden almacenar una cadena de caracteres. Se
puede utilizar para almacenar el texto, un nombre, o una combinacin de caracteres y dgitos como
un nmero de matrcula de coches.
En este ejemplo vamos a ver cmo podemos usar la variable de cadena para aceptar un nombre de
usuario:
var
Name: string;
begin
Write('Por favor ingrese su nombre : ');
Readln(Name);
Writeln('Hola ', Name);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.
En el siguiente ejemplo, se utilizan cadenas para almacenar informacin sobre una persona:
var
Name: string;
Address: string;
ID: string;
DOB: string;
begin
Write('Por favor ingrese su nombre : ');
Readln(Name);
Write('Por favor ingrese su direccin : ');
Readln(Address);
25
Las cadenas pueden ser concatenadas para producir cadenas mas grandes. Por ejemplo, podemos
concatenar FirstName, SecondName, y FamilyName en otra cadena llamada FullName, similar al
ejemplo siguiente:
var
YourName: string;
Father: string;
GrandFather: string;
FullName: string;
begin
Write('Por favor ingrese su
Readln(YourName);
Write('Por favor ingrese el
Readln(Father);
Write('Por favor ingrese el
Readln(GrandFather);
FullName:= YourName + ' ' +
Writeln('Su nombre completo
Advierta que en este ejemplo hemos aadido un espacio ('') entre los nombres (como YourName + ''
Father +) para hacer una separacin entre los nombres. El espacio es un carcter tambin.
Podemos hacer muchas operaciones sobre cadenas, como la bsqueda de subtexto en una cadena,
copiar una cadena a otra variable de cadena, o la conversin de caracteres de texto maysculas o
minsculas como los ejemplos siguientes:
Esta lnea convierte las letras en el valor de cadena FullName a maysculas:
FullName:= UpperCase(FullName);
26
Si el nombre contiene una A mayscula, entonces la funcin Pos no apuntar a la misma, debido a
que A es diferente de a como lo mencionamos anteriormente.
Para solucionar este problema podemos convertir todas las letras del nombre de usuario a
minsculas y entonces podemos hacer la bsqueda:
If Pos('a', LowerCase(YourName)) > 0 the
Podr notar que si el nombre contiene ms de una letra a, la funcin Pos devuelve el ndice de la
primera aparicin de ella en el nombre de usuario.
Puede obtener el nmero de caracteres de una cadena mediante la funcin Length:
Writeln('Su nombre tiene ', Length(YourName), ' letters');
27
Y puede conseguir la primera letra / carcter de una cadena usando el nmero de su ndice:
Writeln('La primer letra de su nombre es ', YourName[1]);
Y el segundo caracter:
Writeln('La segunda letra de su nombre es ', YourName[2]);
El ltimo caracter:
Writeln('La ltima letra de su nombre es ', YourName[Length(YourName)]);
Tambin puede mostrar una variable tipo string caracter por caracter usando el ciclo for:
for i:= 1 to Length(YourName) do
Writeln(YourName[i]);
Funcin Copy
Podemos copiar parte de una cadena mediante la funcin copy. Por ejemplo, si tenemos que extraer
'world' de la palabra ''Hola mundo'' de la cadena, lo podemos hacer si conocemos la posicin de esa
parte, como lo hemos hecho en el siguiente ejemplo:
var
Line: string;
Part: string;
begin
Line:= 'Hola mundo';
Part:= Copy(Line, 7, 5);
Writeln(Part);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.
28
En el ejemplo siguiente, se le pedir al usuario que introduzca un nombre de mes, como febrero, el
programa escribir la versin corta de la misma, por ejemplo feb.
var
Month: string;
ShortName: string;
begin
Write('Por favor, introduzca el nombre del mes completo, por ejemplo, enero:
');
Readln(Month);
ShortName:= Copy(Month, 1, 3);
Writeln(Month, ' abreviado es : ', ShortName);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.
Procedimiento Insert
El procedimiento Insert, inserta una subcadena en una cadena. A diferencia del operador de
concatenacin de cadenas (+) que une dos subcadenas, Insert agrega la subcadena a partir del ndice
indicado en la otra cadena.
Por ejemplo, se puede insertar la palabra Pascal en la cadena 'Hola mundo', lo que resulta en "Hola
mundo Pascal", como en el siguiente ejemplo:
var
Line: string;
begin
Line:= 'Hola mundo';
Insert('Pascal ', Line, 7);
Writeln(Line);
29
Procedimiento Delete
Este procedimiento se utiliza para borrar un carcter o subcadena de una cadena. Es necesario
conocer la posicin de inicio y la longitud de la subcadena que debe ser eliminada.
Por ejemplo, si tenemos que eliminar los caracteres 'll' de la cadena 'Hola mundo' para que quede
'Heo World', podemos hacerlo as:
var
Line: string;
begin
Line:= 'Hola mundo';
Delete(Line, 3, 2);
Writeln(Line);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.
Funcin Trim
Esta funcin se utiliza para eliminar los espacios al comienzo y al final de las cadenas. Si tenemos
una cadena que contiene el texto '' Hola ' ser 'Hola despus de usar esta funcin. No podemos
mostrar espacios en una ventana de terminal a menos que pongamos caracteres entre ellos. Mire el
siguiente ejemplo:
program TrimStr;
{$mode objfpc}{$H+}
uses
30
En el ejemplo anterior, hemos utilizado la unidad SysUtils, unidad que contiene la funcin Trim.
Hay otras dos funciones que eliminan los espacios de slo un lado de una cadena, antes o despus.
Estas funciones son: TrimRight, TrimLeft.
Funcin StringReplace
La funcin StringReplace reemplaza caracteres o subcadenas con otros caracteres o subcadenas en
la cadena deseada.
program
StrReplace;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ usted puede agregar unidades despues de aqu };
var
Line: string;
Line2: string;
begin
Line:= 'Esta es una prueba de reemplazo de cadena';
Line2:= StringReplace(Line, ' ', '-', [rfReplaceAll]);
Writeln(Line);
Writeln(Line2);
Write('Presione la tecla Enter para cerrar');
Readln;
end.
31
2.
3.
'-': Esta es la subcadena alternativa que queremos sustituir por la anterior en la cadena
original.
4.
[rfReplaceAll]: Este es el tipo de sustitucin. En este caso especificamos que sustituya todos
los sucesos de la subcadena ' '.
Podemos usar slo una variable de cadena y desechar la variable Linea2 como muestra el ejemplo
modificado, pero vamos a perder el valor del texto original.
var
Line: string;
begin
Line:= 'Esta es una prueba de reemplazo de cadena';
Writeln(Line);
Line:= StringReplace(Line, ' ', '-', [rfReplaceAll]);
Writeln(Line);
Write('Presione la tecla Enter para cerrar');
Readln;
end.
32
Arreglos
Un arreglo es una cadena de variables del mismo tipo. Si tenemos que declarar un array de 10
variables Integer, podemos hacerlo as:
Numbers: array [1 .. 10] of Integer;
Podemos acceder a las variables simples en el arreglo mediante su ndice. Por ejemplo, para poner
un valor en la primera variable del arreglo se puede escribir como:
Numbers[1]:= 30;
Podemos modificar el cdigo anterior para obtener las notas mxima y mnima de los estudiantes:
var
Marks: array [1 .. 10] of Integer;
i: Integer;
Max, Min: Integer;
begin
33
for i:= 1 to 10 do
begin
Write('Ingrese la nota ', i, ' del estudiante: ');
Readln(Marks[i]);
end;
Max:= Marks[1];
Min:= Marks[1];
for i:= 1 to 10 do
begin
// Controlar si la nota actual es la mxima o no
if Marks[i] > Max then
Max:= Marks[i];
// Controlar si la nota actual es la mnima o no
if Marks[i] < Min then
Min:= Marks[i];
Write('La nota numero ', i, ' del estudiante es: ', Marks[i]);
if Marks[i] >= 40 then
Writeln(' Aprob')
else
Writeln(' Reprob');
end;
Writeln('La nota mxima es: ', Max);
Writeln('La nota mnima es: ', Min);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.
Tenga en cuenta que se considera la primera nota (Marks[1]) como la nota mxima y mnima, y
luego vamos a compararlo con el resto de las notas.
Max:= Marks[1];
Min:= Marks[1];
Dentro del bucle se compara Max, Min con cada nota. Si nos encontramos con un nmero que es
mayor que Max, vamos a sustituir el valor mximo de la misma. Si nos encontramos con un nmero
que es menor que Min, entonces vamos a sustituir Min con l.
En el ejemplo previo hemos introducdo comentarios:
// Controlar si la nota actual es la mxima o no
Comenzamos la lnea con los caracteres / /, lo que significa que esta lnea es un comentario y no
afectar el cdigo y no ser compilada. Esta tcnica se utiliza para describir partes de cdigo a otros
programadores o al programador mismo.
/ / Se utiliza para comentarios cortos. Si necesitamos escribir comentarios multilnea se puede
rodear por {} o (**).
Ejemplo:
34
for i:= 1 to 10 do
begin
{ Comprobar si la nota actual es mayor que Marks[i],
si lo es, Marks[i] es el nuevo mximo }
if Marks[i] > Max then
Max:= Marks[i];
(* Comprobar si la nota actual es menor que Marks[i],
si lo es, Marks[i] es el nuevo mnimo *)
if Marks[i] < Min then
Min:= Marks[i];
Write('La nota numero ', i, ' del estudiante es: ', Marks[i]);
if Marks[i] >= 40 then
Writeln(' Aprob')
else
Writeln(' Reprob');
end;
En el cdigo anterior, queda desactivado el procedimiento que escribe la nota mnima de los
estudiantes.
Nota:
Podemos declarar un arreglo basado en ndice cero al igual que en el lenguaje C:
Marks: array [0 .. 9] of Integer;
Este puede contener 10 elementos tambin, pero al primer elemento se accede mediante el ndice 0:
Numbers[0]:= 30;
Segundo elemento:
Numbers[1]:= 315;
Ultimo elemento:
Numbers[9]:= 10;
o
Numbers[High(Numbers)]:= 10;
35
Registros
Mientras que los arreglos pueden contener muchas variables del mismo tipo, los registros pueden
contener variables de tipos diferentes, y estas variables se denominan "campos".
Este grupo de variables(campos) pueden ser tratados como una sola unidad o variable. Podemos
utilizar los registros para almacenar informacin que pertenecen a un mismo objeto, por ejemplo la
informacin de un automvil:
1. Car type: cadena de caracteres
2. Engine size: nmero real
3. Production year: nmero entero
Podemos recoger estos diferentes tipos en un registro que representa un coche como en el ejemplo
siguiente:
program Cars;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes
{ usted puede agregar unidades despues de aqu };
type
TCar = record
ModelName: string;
Engine: Single;
ModelYear: Integer;
end;
var
Car: TCar;
begin
Write('Ingrese la marca del auto: ');
Readln(Car.ModelName);
Write('Ingrese el tamao de cilindrada: ');
Readln(Car.Engine);
Write('Ingrese el modelo(ao): ');
Readln(Car.ModelYear);
Writeln;
Writeln('Car information: ');
Writeln('Marca
: ', Car.ModelName);
Writeln('Cilindrada : ', Car.Engine);
Writeln('Modelo
: ', Car.ModelYear);
Write('Presione la tecla Enter para cerrar..');
Readln;
end.
36
En este ejemplo definimos un nuevo tipo (Record) usando la palabra reservada 'type':
type
TCar = record
ModelName: string;
Engine: Single;
ModelYear: Integer;
end;
Hemos aadido la letra (T) a Car para indicar que se trata de un tipo y no una variable. Los
nombres de variables pueden ser como: Coche, hora, nombre de usuario, pero los nombres de tipo
debe ser como: TCar, thouse y TUserName. Esta es una convencin en el lenguaje Pascal.
Cuando necesitamos utilizar este nuevo tipo, entonces debemos declarar una variable de ese tipo,
por ejemplo:
var
Car: TCar;
Archivos
Los archivos son elementos importantes de los sistemas operativos y aplicaciones. Componentes del
sistema operativo son representados como archivos y la informacin y los datos estn representados
en archivos tambin, como fotos, libros, aplicaciones y archivos de texto simples
El sistema operativo controla la gestin de archivos tales como lectura, escritura, edicin y borrado.
Files are divided into many types according to many perspectives. We can group files into two
types: executable files, and data files. For example compiled binary Lazarus applications are
executable files, while Pascal source code (.pas) are data files. Also PDF books, JPEG pictures, are
data files.
Los archivos se dividen en varios tipos de acuerdo con muchas perspectivas. Podemos agrupar los
archivos en dos tipos: Los archivos ejecutables y archivos de datos. Por ejemplo los archivos
binarios generados por la compilacin de Lazarus son archivos ejecutables. Mientras que los
archivos de cdigo fuente (.pas) son archivos de datos, as como tambin los libros PDF, imgenes
JPEG.
37
Podemos dividir los archivos de datos en dos tipos de acuerdo con la representacin de su
contenido:
1. Archivos de texto: Son simples archivos de texto que pueden ser escritos o ledos usando
cualquier herramienta simple incluyendo lneas de comandos del sistema operativo como los
comandos cat y vi en Linux, o comandos como type o copy con en Windows.
2. Archivos de datos binarios: Estos son ms complejos y requieren aplicaciones especiales
para abrirlos. Por ejemplo, los archivos de imagen no se pueden abrir utilizando sencillas
herramientas de lnea de comandos, sino que debe abrirse con aplicaciones como GIMP,
Kolour Paint, MS Paint, etc Si abrimos una imagen o archivos de voz, tendremos caracteres
irreconocibles que no significan nada para el usuario. Ejemplos de archivos de datos
binarios son archivos de base de datos, que deben ser abiertos con la aplicacin adecuada.
Hay otra manera de clasificar los archivos, segn tipo de acceso:
1. Archivos de acceso secuencial: Un ejemplo de un archivo secuencial es un archivo de texto,
que no tiene ningn registro de tamao fijo. Cada lnea tiene su propia longitud, por lo que
no podemos saber la posicin (en caracteres) para el inicio de la tercera lnea, por ejemplo.
Por esa razn, hemos podido abrir el archivo de slo lectura o slo escritura, y tambin
podemos aadir texto slo al final del archivo. Si necesitamos insertar texto en medio de un
archivo, entonces debemos leer el contenido del archivo en la memoria, hacer las
modificaciones, borrar todo el archivo desde el disco, y luego sobreescribe el archivo con el
texto modificado
2. Archivos de acceso aleatorio: Este tipo de archivo tiene un registro de tamao fijo. Un
registro es la unidad ms pequea que se puede leer y escribir al mismo tiempo, y podra ser
Byte, Integer, String, o un registro definido por el usuario. Podemos leer y escribir al mismo
tiempo, por ejemplo, se poda leer el nmero de registro 3 y copiarlo en el nmero de
registro 10. En este caso, podemos saber exactamente la posicin de cada registro en el
archivo. Modificar registros es simple. En los archivos de acceso aleatorio, podemos
sustituir o sobrescribir cualquier archivo sin afectar al resto del archivo.
Archivos de texto
Los archivos de texto son los ms simples, pero debemos escribir en ellos en una sola direccin
(slo hacia adelante). No podemos volver al escribir en un archivo de texto. Tambin hay que
definir el modo de funcionamiento antes de abrir el archivo: Read (lectura), Write(escritura o
Append (agregar al final).
En este ejemplo, se muestra el contenido de un archivo de texto seleccionado por un usuario. Por
ejemplo, un usuario puede ingresar un nombre de archivo de texto como c:\test\first.pas en
Windows o
/home/usuario/first.pas en Linux:
38
39
TextFile es un tipo que se utiliza para declarar una variable de archivo de texto. Esta variable se
puede vincular a un archivo de texto para su uso posterior.
2.
if FileExists(FileName) then
El procedimiento Reset, abre archivos de texto para lectura solamente, y coloca el puntero de
lectura en el primer carcter del archivo.
Si no hay permiso de lectura para ese archivo para el usuario actual, aparecer un mensaje de error,
de acceso denegado(access denied).
5.
Readln(F, Line); // Leer una lnea del archivo de texto
El procedimiento Readln se utiliza para leer una lnea completa del archivo y ponerlo en la variable
Linea. Antes de leer una lnea del archivo de texto, debemos asegurarnos de que el archivo no se ha
llegado al final. Podemos hacerlo con la siguiente funcin, Eof.
6.
La funcin EOF devuelve verdadero(True) si el archivo ha llegado a su fin. Se utiliza para indicar
que la operacin de lectura no podr usarse nuevamente y se ha ledo todo el contenido del archivo.
7.
CloseFile(F); // Liberar F y la conexin con el nombre de archivo
Despus de terminar la lectura o escritura en un archivo, hay que cerrarlo para liberar el archivo, ya
que el proceso de Reposicin se reserva el archivo en el sistema operativo y evita la escritura y
borrado por otra aplicacin mientras el archivo est abierto.
Debemos utilizar CloseFile slo cuando el procedimiento Reset logra abrir el archivo. Si Reset falla
por que el archivo no existe, o est siendo utilizado por otra aplicacin, etc, en ese caso no hay que
cerrar el archivo.
40
En el siguiente ejemplo vamos a crear un nuevo archivo de texto y poner algn texto en l:
Creando y escribiendo en un archivo de texto
var
FileName: string;
F: TextFile;
Line: string;
ReadyToCreate: Boolean;
Ans: Char;
i: Integer;
begin
Write('Ingrese un nuevo nombre de archivo: ');
Readln(FileName);
// Verificar si el archivo existe, avisar al usuario si es as
if FileExists(FileName) then
begin
Write('El archivo existe, desea sobreescribirlo ? (s/n)');
Readln(Ans);
if upcase(Ans) = 'S' then
ReadyToCreate:= True
else
ReadyToCreate:= False;
end
else // File does not exist
ReadyToCreate:= True;
if ReadyToCreate then
begin
// Enlazar la variable F con el nombre fsico del archivo
AssignFile(F, FileName);
Rewrite(F); // Crear un nuevo archivo para escritura
Writeln('Please input file contents line by line, '
, 'when you finish write % then press enter');
i:= 1;
repeat
Write('Line # ', i, ':');
Inc(i);
Readln(Line);
if Line <> '%' then
Writeln(F, Line); // Escribir una lnea en el archivo de texto
until Line = '%';
CloseFile(F); // Liberar F y la conexin con el nombre de archivo
end
else // El archivo existe y el usuario no desea sobreescibir
Writeln('Doing nothing');
Write('Presione la tecla Enter para cerrar..');
Readln;
end.
41
Este tipo slo puede tener uno de dos valores: True o False. Estos valores se pueden utilizar
directamente en una condicin if, bucle while o bucle repeat
En el ejemplo previo usamos la condicin if de este modo:
if Marks[i] > Max then
This statement is executed when the file exists. The program will warn the user about overwriting
an existing file. If he/she wants to continue, then he/she should enter a lowercase y or capital Y. The
UpCase function will convert the character into a capital letter if it is lowercase.Esta sentencia se
ejecuta cuando el archivo existe.
El programa avisar al usuario acerca de sobrescribir un archivo existente. Si desea continuar,
entonces podra introducir una 'y' minscula o mayscula . La funcin UpCase convertir el
carcter en mayscula si es minscula.
3. Procedimiento Rewrite:
Rewrite(F); // Crear un nuevo archivo para escritura
El procedimiento Rewrite se utiliza para crear un nuevo archivo vaco. Si el archivo ya existe, ser
borrado y sobreescrito Tambin abre el archivo para escritura slo en el caso de archivos de texto.
4. Procedimiento Writeln(F, ..) :
Writeln(F, Line); // Escribir una linea en el archivo
Este procedimiento se utiliza para escribir variables de cadena en archivos de texto, que las aade
con caracteres de fin de lnea retorno de carro y lnea abajo (CR / LF), representado como los
caracteres cuyo valor numrico es 13 y 10 respectivamente.
Estos caracteres no se puede mostrar en una ventana de la consola, sino que se mover el cursor de
pantalla a una nueva lnea.
42
5. Procedimiento Inc:
Inc(i);
6. Procedure CloseFile:
CloseFile(F); // Liberar F y la conexin con el nombre de archivo
43
AssignFile(F, FileName);
Append(F); // Abrir archivo para agregar
Writeln('Please input file contents line by line',
'when you finish write % then press enter');
i:= 1;
repeat
Write('Line # ', i, ' append :');
Inc(i);
Readln(Line);
if Line <> '%' then
Writeln(F, Line); // Escribir una lnea en el archivo de texto
until Line = '%';
CloseFile(F); // Release F and FileName connection, flush buffer
end
else
Writeln('File does not exist');
Write('Presione la tecla Enter para cerrar..');
Readln;
end.
Despus de ejecutar esta aplicacin y entrar en un archivo de texto existente, lo podemos ver con
los comandos cat / type, o haciendo doble clic en l en su directorio para ver los datos adjuntos.
En este ejemplo usamos esta sintxis para definir el archivo con tipo:
F: file of Byte;
Que quiere decir:: el archivo contiene un registro de tipo de datos Byte, que puede contener valores
de 0 a 255.
Creamos el archivo y lo abrimos para escritura usando el procedimiento Rewrite
Rewrite(F); // Crear archivo
Tambin se ha utilizado la funcin Write en lugar de Writeln para escribir registros en el archivo
proporcionado:
Write(F, Mark);
Writeln no es adecuado para los archivos de tipo, porque se aaden los caracteres CR / LF en cada
lnea del texto escrito, pero Write almacena el registro como es, sin ninguna adicin. En este caso, si
hemos entrado 10 registros (de Byte), el tamao del archivo ser de 10 bytes en el disco.
En el siguiente ejemplo, vamos a mostrar cmo se muestra el contenido del archivo anterior: :
45
En el siguiente ejemplo, vamos a mostrar cmo aadir nuevos registros sin eliminar los datos
existentes:
46
var
F: file of Byte;
Mark: Byte;
begin
AssignFile(F, 'marks.dat');
if FileExists('marks.dat') then
begin
FileMode:= 2; // Poner en modo lectura/escritura
Reset(F); // Abrir archivo
Seek(F, FileSize(F)); // Ir hasta el ltimo registro
Writeln('Por favor ingrese la nota de estudiante, escriba 0 para salir');
repeat
Write('Ingrese nota: ');
Readln(Mark);
if Mark <> 0 then // No escribir valor 0 en el archivo
Write(F, Mark);
until Mark = 0;
CloseFile(F);
end
else
Writeln('Archivo (marks.dat) no encontrado');
Write('Presione la tecla Enter para cerrar..');
Readln;
end.
Despus de ejecutar este programa y entrar en nuevos registros, podemos ejecutarlo de nuevo para
ver los datos agregados.
Tenga en cuenta que hemos utilizado Reset para abrir el archivo para escribir en lugar del
procedimiento Rewrite. Rewrite borra todos los datos de los archivos existentes, y crea un archivo
vaco si el archivo no existe, mientras Reset abre un archivo existente sin borrar su contenido.
Tambin hemos asignado 2 a la variable FileMode para indicar que hay que abrir el archivo para
acceso de lectura/escritura. 0 en FileMode significa slo lectura, 1 significa slo escritura y 2 (por
defecto) significa lectura/escritura.
FileMode:= 2; // Poner en modo lectura/escritura
Reset(F); // Abrir archivo
Reset coloca el puntero de lectura/escritura en el primer registro, y por esa razn si empezamos a
escribir los registros inmediatamente, vamos a sobrescribir los archivos antiguos, por lo que hemos
utilizado el procedimiento Seek para mover el puntero de lectura/ escritura al final del archivo .
Seek slo se puede utilizar con archivos de acceso aleatorio.
Si se intenta acceder a una posicin de registro que no existe con el procedimiento Seek (por
ejemplo, nmero de registro 100, mientras que slo existen 50 registros), obtendremos un error.
Tambin hemos usado la funcin FileSize que devuelve el nmero de registros actuales en el
archivo. Se utiliza en combinacin con el procedimiento Seek para saltar al final del archivo:
Seek(F, FileSize(F)); // Ir hasta el ltimo registro
47
Note that this example can be used if the Student marks file already exists; if not, then we should
run the first program (Storing Student Marks) because it uses Rewrite which can create new files.
Tenga en cuenta que este ejemplo se puede utilizar si el archivo de notas de alumnos ya existe. Si
no, debemos ejecutar previamenteel primer programa (Programa de notas ), ya que utiliza Rewrite
y puede crear un nuevo archivo.
Podemos combinar los dos mtodos (Reset y Rewrite) en funcin de si el archivo existe, como lo
hemos hecho en el ejemplo siguiente:
48
until Mark = 0;
CloseFile(F);
Write('Presione la tecla Enter para cerrar..');
Readln;
end.
Observe que en este ejemplo, no utilizamos el procedimiento Seek, en cambio, lemos todo el
contenido de notas de alumnos primero. Esta operacin (leer todo el archivo) mueve el puntero al
final del mismo.
En el siguiente ejemplo, vamos a utilizar un archivo de registros para almacenar la informacin de
Automviles
Programa base de datos de automoviles
program CarRecords;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ usted puede agregar unidades despues de aqu };
type
TCar = record
ModelName: string[20];
Engine: Single;
ModelYear: Integer;
end;
var
F: file of TCar;
Car: TCar;
begin
AssignFile(F, 'cars.dat');
if FileExists('cars.dat') then
begin
FileMode:= 2; // Poner en modo lectura/escritura
Reset(F); // Abrir archivo
Writeln('Archivo existente, abierto para agregar');
// Mostrar registros del archivo
while not Eof(F) do
begin
Read(F, Car);
Writeln;
Writeln('Car # ', FilePos(F), ' --------------------------');
Writeln('Model : ', Car.ModelName);
Writeln('Year : ', Car.ModelYear);
Writeln('Engine: ', Car.Engine);
end
end
49
En el ejemplo anterior, declaramos el tipo TCar para definir la informacin del coche. El primer
campo (ModelName) es una variable de cadena, pero limitamos su longitud mxima a 20
caracteres:
ModelName: string[20];
Debemos utilizar esta declaracin para variables de cadena antes de usarlos en los archivos, ya que
las variables estndar ANSI cadena tiene un tipo diferente e ilimitado de almacenamiento en
memoria, pero para los archivos con tipo, el tamao de cada tipo de dato debe definirse.
Copiando archivos
Todos los tipos de archivos, tales como archivos de texto, archivos binarios, se basan en unidades
de byte, que es la ms pequea representacin de datos en la memoria del ordenador y en el disco.
Cada archivo debe contener un byte, dos bytes, etc, o ningn byte en absoluto . Cada byte podra
contener un nmero entero o un cdigo de caracteres 0 a 255. Podemos abrir todo tipo de archivos
utilizando un archivo de tipo Byte o de tipo Char.
Podemos copiar cualquier archivo a otro usando de archivos de Byte, y el resultado ser un nuevo
archivo que es idntico al contenido del archivo de origen.
50
Despus de ejecutar el ejemplo anterior, podrn ingresar en el archivo origen existente y en el nuevo
archivo destino. En Linux podemos introducir nombres de archivos como estos:
Input source file name: /home/motaz/quran/mishari/32.mp3
51
52
53
end
else // Archivo origen inexistente
Writeln('El archivo orgen no existe');
Write('Copia de archivo finalizada, Presione la tecla Enter para cerrar.');
Readln;
end.
Hemos usado un arreglo de bytes (1 KByte y puede ser modificado) para leer y copiar bloques de
archivo.
3. Abrir un archivo sin tipo requiere un parmetro adicional:
Reset(SourceF, 1); // Abrir archivo origen
Rewrite(DestF, 1); // Crear archivo destino
El procedimiento BlockRead se utiliza con archivos sin tipo. Se leen un montn de datos a la vez.
Los parmetros del procedimiento BlockRead son:
Block : Es la variable o arreglo que almacenar los datos actualmente ledos y escritos.
SizeOf(Block): Este es el nmero deseado de registros que hay que leer de una sola vez. Por
ejemplo, si introducimos 100 que significa que tenemos que leer 100 registros (bytes en este
caso). Si utilizamos la funcin SizeOf, significa que tenemos que leer el nmero de registros
del tamao del contenedor (arreglo de bytes).
slo una parte de ella. Por ejemplo, supongamos que tenemos que leer un archivo que
contiene slo 100 bytes, significa que BlockRead podra leer slo 100 bytes. Leer menos
registros que los deseados sucede tambin en el ltimo bloque del archivo. Si el archivo
contiene 1034 bytes, por ejemplo, eso significa que en el primer bucle, llegaremos 1024,
pero en el siguiente bucle obtendremos slo 10 bytes a la izquierda, y la funcin EOF
devuelve True. Necesitamos el valor NumRead para usar con el procedimiento BlockWrite.
55
begin
AssignFile(F, FileName);
FileMode:= 0;
Reset(F, 1);
Despus de ejecutar este ejemplo e introducir un nombre de archivo de texto, por ejemplo, vamos a
ver por primera vez CR / LF valores (13/10), porque nos muestra cada cdigo de carcter (ASCII).
En Linux encontraremos solo salto de lnea (LF), que tiene un valor de 10 en decimal. Este es un
delimitador de lnea en archivos de texto.
Podemos mostrar otros tipos de archivos, como imgenes, ejecutables, para ver cmo se ven desde
el interior.
Hemos utilizado la funcin Chr en este ejemplo para obtener el valor numrico de caracteres, por
ejemplo, la letra a se almacena en la memoria en un byte como 97, y la ltra A mayscula se
almacena como 65.
Fecha y Hora
La fecha y hora son dos de los temas ms importantes en la programacin. Es importante para las
aplicaciones que almacenan transacciones o cualquier informacin de una operacin, como
compras, facturas de pago, etc, estas necesitan almacenar la fecha y hora de la transaccin. Ms
tarde se podr determinar las transacciones y operaciones que tuvieron lugar durante el mes pasado
o el mes en curso, por ejemplo.
Un registro de solicitudes es una operacin que depende de la fecha / tiempo de grabacin. Tenemos
que saber cuando alguna aplicacin se inicia, se detiene, se genera un error, o se bloquea.
TDateTime es el tipo en Object Pascal que podemos utilizar para almacenar la fecha/hora. Es un
nmero de doble precisin de punto flotante que ocupa 8 bytes en la memoria. La parte fraccionaria
de este tipo representa el tiempo, y la parte integral representa el nmero de das que han pasado
desde el 30/Dic/1899.
56
En el siguiente ejemplo, vamos a mostrar cmo mostrar la fecha/hora actual valor de la funcin
Now .
program DateTime;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes , SysUtils
{ usted puede agregar unidades despues de aqu };
begin
Writeln('Fecha y hora actuales: ', DateTimeToStr(Now));
Write('Presione la tecla Enter para cerrar');
Readln;
end.
Hemos utilizado la funcin DateTimeToStr contenido en la unidad SysUtils para convertir un tipo
TDateTime devuelto por la funcin Now en una representacin de cadena legible fecha/hora.
Si no utilizamos esta conversin, vamos a tener un valor fecha/hora codificada como un nmero
real:
Writeln('Fecha y hora actuales: ', Now);
Tambin hay dos funciones de conversin de fecha/hora que muestran la parte fecha y la parte hora:
Writeln('La fecha actual es ', DateToStr(Now));
Writeln('La hora actua es ', TimeToStr(Now));
La funcin Date devuelve slo la parte fecha de hoy, y la funcin Time devuelve la hora actual
solamente:
Writeln('La fecha actual es ', DateToStr(Date));
Writeln('La hora actua es ', TimeToStr(Time));
Estas dos funciones ponen ceros en la otra parte, por ejemplo, la funcin Date devuelve el da actual
y pone cero en parte hora (cero en la hora significa 12:00 am). La funcin Time devuelve la hora
actual del sistema, y pone a cero la parte de fecha (cero en la fecha significa 30/12/1899).
Podemos comprobar esto utilizando la funcin DateTimeToStr:
Writeln('La fecha actual es ', DateTimeToStr(Date));
Writeln('La hora actual es ', DateTimeToStr(Time));
57
En el siguiente ejemplo, vamos a tratar fecha/hora como un nmero real, sumando y restando los
valores de la misma:
begin
Writeln('La fecha y hora actual es ',
FormatDateTime('yyyy-mm-dd hh:nn:ss', Now));
Writeln('La hora de ayer es ',
FormatDateTime('yyyy-mm-dd hh:nn:ss', Now - 1));
Writeln('La hora de maana es ',
FormatDateTime('yyyy-mm-dd hh:nn:ss', Now + 1));
Writeln('Hoy + 12 horas es ',
FormatDateTime('yyyy-mm-dd hh:nn:ss', Now + 1/2));
Writeln('Hoy + 6 horas es ',
FormatDateTime('yyyy-mm-dd hh:nn:ss', Now + 1/4));
Write('Presione la tecla Enter para cerrar');
Readln;
end.
var
ADate: TDateTime;
begin
ADate:= EncodeDate(1975, 11, 16);
Writeln('Mi fecha de cumpleaos es: ', FormatDateTime('yyyy-mm-dd', ADate));
Write('Presione la tecla Enter para cerrar');
Readln;
end.
La funcin EncodeDate acepta ao, mes y da como entrada, y devuelve ao, mes y da en una
variable de tipo TDateTime.
La funcin EncodeTime acepta hora, minuto, segundo y milisegundo como entrada y devuelve los
valores de tiempo como un valor TDateTime:
58
var
ATime: TDateTime;
begin
ATime:= EncodeTime(19, 22, 50, 0);
Writeln('Almughrib prayer time is: ', FormatDateTime('hh:nn:ss', ATime));
Write('Presione la tecla Enter para cerrar');
Readln;
end.
Comparacin Fecha/Hora
Puede comparar dos variables fecha/hora del mismo modo que la comparacin de nmeros reales.
Por ejemplo, en nmeros reales: 9,3 es mayor que 5,1, lo mismo sucede para los valores
TDateTime. Actual + 1, que representa maana, es mayor que ahora (Now), y Now + 1.24 que
significa una hora despus de Now es mayor que Now - 2/24 que significa dos horas antes de ahora.
En el siguiente ejemplo, vamos a poner la fecha 1/Ene/2012 en una variable, compararla con la
fecha actual y comprobar si esta fecha ya ha pasado o no.
var
Year2012: TDateTime;
begin
Year2012:= EncodeDate(2012, 1, 1);
if Now < Year2012 then
Writeln('El ao 2012 no ha llegado todava')
else
Writeln('El ao 2012 ya ha pasado');
Write('Presione la tecla Enter para cerrar');
Readln;
end.
Podemos aadir nuevas funciones a este ejemplo, para que muestre los das que faltan o los das
pasados a/desde esa fecha:
var
Year2012: TDateTime;
Diff: Double;
begin
Year2012:= EncodeDate(2012, 1, 1);
Diff:= Abs(Now - Year2012);
if Now < Year2012 then
Writeln('El ao 2012 no ha llegado an, faltan ',
Format('%0.2f', [Diff]), ' das ')
else
Writeln('El primer da de enero de 2012 fue pasado por ',
Format('%0.2f', [Diff]), ' das');
Write('Presione la tecla Enter para cerrar');
Readln;
end.
59
Diff es una variable de nmero real que contendr la diferencia entre la fecha actual y la fecha de
2012. Tambin utilizamos la funcin Abs, que devuelve el valor absoluto de un nmero (el nmero
sin el signo negativo).
En este ejemplo, vamos a utilizar archivos de texto para almacenar ttulos de las noticias y, adems,
vamos a almacenar la fecha y la hora tambin.
Despus de cerrar y abrir de nuevo la aplicacin, mostrar el ttulo de las noticias introducidas
anteriormente con su fecha/hora:
program news;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ usted puede agregar unidades despues de aqu };
var
Title: string;
F: TextFile;
begin
AssignFile(F, 'news.txt');
if FileExists('news.txt') then
begin
// Mostrar noticias antiguas
Reset(F);
while not Eof(F) do
begin
Readln(F, Title);
Writeln(Title);
end;
CloseFile(F); // Lectura desde F finalizada
Append(F);
// Abrir nuevamente archivo para agregar
end
else
Rewrite(F);
Write('Ingrese hora actual ttulo noticias: ');
Readln(Title);
Writeln(F, DateTimeToStr(Now), ', ', Title);
CloseFile(F);
Write('Presione Enter para cerrar');
Readln;
end.
60
Constantes
Las constantes son similares a las variables. Tienen nombres y puede almacenar valores, pero
difieren de las variables para modificar dicho valor. Los valores constantes no pueden ser
modificados durante la ejecucin de la aplicacin, y sus valores se deben determinar antes de
compilar la aplicacin.
Hemos utilizado las constantes de una forma diferente antes, sin nombrarlos, as como un valor
entero o de cadena como en este ejemplo:
Writeln(5);
Writeln('Hola');
El valor 5 nunca va a cambiar despus de ejecutar la aplicacin. 'Hola' es tambin una constante de
cadena.
Podemos definir constantes usando la palabra reservada Const despus de la clusula uses clause
como en el siguiente ejemplo:
61
En el ejemplo anterior, se calculan los kilmetros que el coche podra recorrer con el combustible
actual de acuerdo a los siguientes hechos:
1. Consumption: Se ha utilizado la variable Consumption para almacenar kilmetros por galn
para el coche actual
2. Payment: Hemos utilizado la variable Payment para almacenar la cantidad de dinero que
pagamos por el combustible actual
3. GallonPrice: Hemos usado la constante GallonPrice para almacenar el precio de un galn de
combustible para el pas actual. Este valor no debe ser introducida por el usuario, sino que
debe ser definido por el programador.
Las constantes se recomiendan cuando se utiliza el mismo valor muchas veces en la aplicacin. Si
tuvieramos que cambiar este valor, podemos hacerlo de una vez en la cabecera de cdigo.
Tipos ordinales
Los tipos ordinales son valores enteros que utilizan indicaciones literales en lugar de nmeros. Por
ejemplo, si tenemos que definir fecha/hora en (rabe / Ingls / Francs) podemos usar el valor 1
para idioma rabe, 2 para Ingls, y 3 para el francs. Otros programadores no conocern el
significado de los valores de 1, 2 y 3, a menos que encuentren comentarios. Ser ms fcil de leer si
lo hacemos con los tipos ordinales, como en el siguiente ejemplo:
program OrdinalTypes;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes
{ usted puede agregar unidades despues de aqu };
type
TLanguageType = (ltArabic, ltEnglish);
var
Lang: TLanguageType;
AName: string;
Selection: Byte;
begin
62
Los tipos Integer, Char y Boolean son tipos ordinales, mientras que los nmeros reales y las
cadenas no lo son.
Conjuntos (Sets)
Los tipos Set pueden contener varias propiedades o caractersticas de una variable. Los conjuntos se
utilizan slo con valores ordinales.
Por ejemplo, si tenemos que definir el apoyo del sistema operativo para las aplicaciones, podemos
hacerlo como sigue:
1. Definir el tipo ordinal que representa los sistemas operativos : TApplicationEnv:
TApplicationEnv = (aeLinux, aeMac, aeWindows);
63
Tambin podemos utilizar la sintaxis para establecer otros tipos ordinales, como nmeros enteros:
if Month in [1, 3, 5, 7, 8, 10, 12] then
Writeln('Este mes contiene 31 das');
O caracteres:
64
65
Manejo de excepciones
Hay dos tipos de errores: errores de compilacin como el uso de una variable sin definir en la
seccin de Var, o escribir instrucciones con sintaxis incorrecta. Los primeros impedirn la
compilacion de la aplicacin y el compilador mostrar un mensaje apropiado y apunta a la lnea que
contiene el error.
El segundo tipo es el error de tiempo de ejecucin. Este tipo de error se produce mientras se ejecuta
la aplicacin, por ejemplo, la divisin por cero, en una lnea como esta:
x:= y / z;
Esta es una sintaxis vlida, pero en tiempo de ejecucin un usuario podra introducir 0 en la variable
Z, y luego la aplicacin se bloquear y mostrar un mensaje de error divisin por cero.
Tratar de abrir un archivo que no existe generar un error en tiempo de ejecucin (Archivo no
encontrado), o tambin cuando se intenta crear un archivo en un directorio de slo lectura.
El compilador no puede detectar errores de este tipo, que slo se producen despus de ejecutar la
aplicacin.
Para crear una aplicacin fiable que no se colgar con los errores de ejecucin, debemos utilizar el
control de excepciones.
Existen diferentes mtodos de tratamiento de excepciones en Object Pascal:
66
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, sysutils
{ usted puede agregar unidades despues de aqu };
var
x, y: Integer;
Res: Double;
begin
try
Write('Ingrese x: ');
Readln(x);
Write('Ingrese y: ');
Readln(y);
Res:= x / y;
Writeln('x / y = ', Res);
except
on e: exception do
begin
Writeln('Un error ha ocurrido: ', e.message);
end;
end;
Write('Presione la tecla Enter para cerrar');
Readln;
end.
Hay dos secciones de la declaracin try. El primero es el bloque que hay que proteger, que reside
entre try ... except. La otra parte existe entre except .. end.
Si algo va mal en la primera seccin (try except), la solicitud pasar a la seccin de excepcin
(except.. end) y no se bloquear, sino que se mostrar el mensaje de error apropiado y continuar la
ejecucin.
Esta es la lnea que podra elevar la excepcin si el valor de y es cero:
Res:= x / y;
Try finally
Sintxis:
67
try
// Start of protected code
CallProc1;
CallProc2;
// End of protected code
finally
Writeln('Esta lnea ser impresa en pantalla con seguridad');
end;
Esta vez, la parte finally .. end se ejecuta en todos los casos, independientemente de si hay un
error. .
68
Ejemplo:
program RaiseExcept;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ usted puede agregar unidades despues de aqu };
var
x: Integer;
begin
Write('Por favor ingrese un nmero entre 1 y 10: ');
Readln(X);
try
if (x < 1) or (x > 10) then // elevar excepcin
raise exception.Create('Nmero fuera de rango');
Writeln(' X * 10 = ', x * 10);
except
on e: exception do // capturar mi excepcin
begin
Writeln('Error: ' + e.Message);
end;
end;
Write('Presione Enter para cerrar');
Readln;
end.
Si el usuario introduce un valor fuera del rango de 1 al 10, una excepcin se genera (X est fuera de
rango), y si no hay manejo de excepciones para esta parte, la aplicacin se colgar. Pero debido a
que try except envuelve el cdigo que contiene la palabra clave raise, la aplicacin no se bloquear,
sino que se mostrar el mensaje de error.
69
Captulo Dos
Programacin
Estructurada
70
Introduccin
El trmino programacin estructurada naci luego de que los programas se empezaran a
expandir. El cdigo fuente de una aplicacin grande se hace ilegible (e inmanejable) cuando se usa
cdigo no estructurado en un nico archivo. Antes de la programacin estructurada se utilizaba
mucho la sentencia GOTO (que permite el salto incondicional de una parte a otra dentro del
cdigo de un programa), lo que resultaba en programas muy difciles de seguir; este cdigo enorme
con el uso (y abuso) de la sentencia GOTO dentro de un enorme archivo se conoca como cdigo
espagueti, y puede convertirse en una pesadilla para mantener (encontrar errores, introducir
mejoras, entender el funcionamiento). A la metodologa de programacin estructurada tambin se la
conoce como Programacin sin goto.
En la programacin estructurada, nosotros podemos dividir el cdigo fuente de una aplicacin en
partes ms pequeas, llamadas procedimientos y funciones, y tambin podemos agrupar
procedimientos y funciones relacionados con una tarea en particular dentro del programa, en
archivos de cdigo fuente separados llamados unidades.
Beneficios de la programacin estructurada:
1. Divisin del cdigo de una aplicacin para hacerlo ms legible.
2. Reutilizacin de cdigo: los procedimientos y las funciones pueden ser utilizados desde
distintas partes del programa muchas veces sin necesidad de tener que reescribir (y duplicar)
cdigo.
3. Varios programadores pueden compartir cdigo y participar en un mismo proyecto al
mismo tiempo. Cada programador puede escribir sus propios procedimientos y funciones en
una unidad separada, y entonces integrar esas unidades en el proyecto.
4. El mantenimiento y las mejoras a la aplicacin se simplifican: es ms fcil encontrar
errores en el cdigo del programa (llamados bugs) si este est dividido, y se facilita el
poder mejorar los procedimientos (y funciones), el agregado de nuevas unidades, etc.
5. Posibilidad de dividir la lgica de la aplicacin en mdulos y capas: por ejemplo podemos
escribir una unidad que contenga procedimientos para lectura/escritura de datos desde/hacia
archivos, otra que contenga una capa con reglas de validacin, y otra ms que se encargue
de la interaccin con el usuario (capa de interfaz con el usuario).
Procedimientos
En captulos anteriores hemos usado algunos procedimientos, como Writeln, Readln, Reset, etc,
pero es momento de que aprendamos a escribir nuestros propios procedimientos que puedan ser
usados por nuestras propias aplicaciones.
71
En el siguiente ejemplo nosotros escribiremos dos procedimientos: SayHello (decir hola) and
SayGoodbye (decir adis):
program Estructurado;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads} cthreads, {$ENDIF}{$ENDIF} Classes
{ usted puede agregar unidades despus de aqu };
procedure SayHello;
begin
Writeln('Hola a todos !!!');
end;
procedure SayGoodbye;
begin
Writeln('Adis');
end;
begin // Aqu comienza el cdigo principal de la aplicacin
Writeln('Se est ejecutando el cdigo principal de la aplicacin');
SayHello;
Writeln('Esta aplicacin utiliza programacin estructurada');
SayGoodbye;
Write('Presione la tecla Enter para terminar el programa');
Readln;
end.
Podemos observar que un procedimiento tiene el aspecto de un pequeo programa, con su propio
bloque begin---end, y el mismo puede ser llamado desde el cdigo principal de la aplicacin.
Parmetros
En el siguiente ejemplo, veremos cmo usar los parmetros, que son valores que se envan al
procedimiento cuando se lo llama (en este ejemplo x e y son dos parmetros):
procedure WriteSumm(x, y: Integer);
begin
Writeln('El resultado de la suma es: ', x, ' + ', y, ' = ', x + y)
end;
begin
WriteSumm(2, 7);
Write('Presione la tecla Enter para finalizar el programa');
Readln;
end.
73
Ahora el cdigo del programa principal se hizo ms pequeo y ms legible. Los detalles de las otras
partes del programa fueron separados en procedimientos, como get order (tomar pedido) y display
menu (mostrar el men de pedidos).
74
Funciones
Las funciones son similares a los procedimientos, pero tienen una caracterstica adicional, que es la
de retornar un valor. En captulos anteriores usamos funciones como por ejemplo UpperCase ,que
convierte un texto a maysculas, o Abs que devuelve el valor absoluto de un nmero.
En el ejemplo siguiente escribiremos la funcin GetSumm ,que recibe dos valores numricos enteros
y retorna como resultado la suma de ambos:
function GetSumm(x, y: Integer): Integer;
begin
Result:= x + y;
end;
var
Sum: Integer;
begin
Sum:= GetSumm(2, 7);
Writeln('La suma 2 + 7 es igual a ', Sum);
Write('Presione la tecla Enter para terminar el programa');
Readln;
end.
Observemos que declaramos a la funcin para que devuelva un valor de tipo integer (entero), y
dentro de la misma usamos la palabra clave (keyword) Result que representa el valor de salida de la
funcin.
En el cdigo principal de la aplicacin usamos la variable Sum, que es donde se recibir el valor
devuelto por la funcin, aunque tambin se podra eliminar esta variable intermediaria Sum y
llamar a la funcin GetSum directamente dentro del procedimiento Writeln. Justamente esta es una
diferencia entre las funciones y los procedimientos: podemos llamar funciones como parmetros de
entrada en otros procedimientos (o funciones), pero no podemos llamar a procedimientos como
parmetros de otras funciones y procedimientos. Mejor verlo con un ejemplo, donde eliminaremos
la variable Sum usada en el ejemplo anterior, lo que resulta en un programa ms simple todava:
function GetSumm(x, y: Integer): Integer;
begin
Result:= x + y;
end;
begin
Writeln('La suma de 2 y 7 es ', GetSumm(2, 7));
Write('Presione la tecla Enter para terminar el programa');
Readln;
end.
Tip: Una funcin tambin puede ejecutarse como si fuera un procedimiento, en ese caso se ignora
el valor devuelto. En algunas ocasiones esto puede resultar de utilidad.
75
En el ejemplo que sigue a continuacin reescribiremos el programa Restaurante para usar funciones,
lo que lo simplificar ms an.
76
Variables locales
Podemos definir variables (llamadas locales) dentro de un procedimiento o funcin. Estas
variables sern usadas nicamente dentro de este cdigo y no sern accesibles fuera del
procedimiento (o funcin) donde estn escritas.
Ejemplo:
procedure Loop(Counter: Integer);
var
i: Integer;
Sum: Integer;
begin
Sum:= 0;
for i:= 1 to Counter do
Sum:= Sum + i;
Writeln('La suma de ', Counter, ' nmeros es: ', Sum);
end;
begin
// Cdigo principal del programa
Loop(5);
Write('Presione la tecla Enter para terminar el programa');
Readln;
end.
En el procedimiento Loop , usamos dos variables locales llamadas I y Sum. Las variables locales se
almacenan en la pila (stack), un rea de memoria temporal que almacena variables hasta que la
ejecucin del procedimiento (o la funcin) termine. Por este motivo, estas variables locales no
estarn accesibles fuera del procedimiento, e incluso el rea de memoria que ocupaban podr ser
sobreescrita luego, por ejemplo en el momento en que dentro del programa se ejecuta la siguiente
lnea de cdigo:
Write('Presione la tecla Enter para terminal el programa');
Las variables globales son accesibles desde el cdigo principal del programa y tambin dentro de
los procedimientos (y funciones). Los valores almacenados por este tipo de variables se mantienen
durante todo el tiempo en que el programa est activo, pero tiene el inconveniente de que en caso de
errores puede ser difcil de encontrarlos, ya que pueden ser modificados desde cualquier lugar del
programa, incluyendo procedimientos (y funciones). Por este motivo deberan tratar de evitarse las
variables de tipo global en la medida de lo posible (adems es algo que atenta contra la filosofa de
la programacin estructurada, donde el interior de cada procedimiento (o funcin) se mantiene (o se
debera mantener) aislado del resto del programa.
Al definir variables de tipo local garantizamos su privacidad, garantizando que los
77
procedimientos o funciones puedan ser portados a otros programas o llamados desde cualquier
lugar sin preocuparnos por los valores de las variables globales.
78
En este ejemplo tenemos tres procedimientos y una funcin: Add News title (agregar nueva
noticia), display all News (mostrar todas las noticias), searching (bsqueda), and displaying menu
(mostrar men de opciones), permitiendo al usuario seleccionar la funcin que desea ejecutar:
program news;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ usted puede agregar unidades despus de aqu };
type
TNews = record
ATime: TdateTime;
Title: string[100];
end;
// Fecha y hora
// Titular de la noticia (mximo 100 caracteres)
79
Writeln('------------------------------------------');
Writeln('Titular: ', News.Title);
Writeln('Fecha y hora: ', DateTimeToStr(News.ATime));
end;
CloseFile(F);
end
else
Writeln('Base de datos vaca');
end;
procedure Search; // Bsqueda de una noticia en la base de datos
var
F: file of TNews;
News: TNews;
Keyword: string;
Found: Boolean;
begin
AssignFile(F, 'noticias.dat');
Write('Ingrese la palabra (o parte de la misma) que desee buscar: ');
Readln(Keyword);
Found:= False;
if FileExists('noticias.dat') then
begin
Reset(F);
while not Eof(F) do
begin
Read(F, News);
if Pos(LowerCase(Keyword), LowerCase(News.Title)) > 0 then
begin
Found:= True;
Writeln('------------------------------------------');
Writeln('Titular: ', News.Title);
Writeln('Fecha y hora: ', DateTimeToStr(News.ATime));
end;
end;
CloseFile(F);
if not Found then
Writeln(Keyword, ' No se encontr un titular que coincida');
end
else
Writeln('Base de datos vaca');
end;
function Menu: char;
begin
Writeln;
Writeln('...........Base de datos de titulares de noticias..........');
Writeln('1. Agregar un titular nuevo');
Writeln('2. Mostrar todos los titulares');
Writeln('3. Bsqueda de un titular');
Writeln('x. Finalizar');
Write('Por favor ingrese su seleccin : ');
Readln(Result);
end;
// Cdigo principal de la aplicacin
var
80
Selection: Char;
begin
repeat
Selection:= Menu;
case Selection of
'1': AddTitle;
'2': ReadAllNews;
'3': Search;
end;
until LowerCase(Selection) = 'x';
end.
81
Observemos que hemos llamado a la funcin DoubleNumber desde el interior del procedimiento
Writeln.
Tambin podemos modificar de nuevo el ejemplo, para usar una variable intermedia MyNum para
almacenar el resultado de la funcin, y luego mostrar el valor de esta variable dentro del
procedimiento WriteLn (que recibir esta variable como parmetro de entrada):
function DoubleNumber(x: Integer): Integer;
begin
Result:= x * 2;
end;
// Cdigo principal
var
MyNum: Integer;
begin
MyNum:= DoubleNumber(5);
Writeln('El doble de 5 es : ', MyNum);
Readln;
end.
Como podemos observar, estamos agregando una variable intermedia para hacer exactamente lo
mismo. Dentro de los entornos integrados de desarrollo (IDE, Integrated Development
Environment) como Lazarus, existe la posibilidad de modificar automticamente el cdigo para
agregar (o para suprimir) estas variables intermedias, lo que puede ayudar a clarificar/simplificar el
cdigo. Este tipo de modificaciones semi-automticas realizadas en el cdigo fuente (las
posibilidades son muchsimas y exceden por mucho el alcance de esta documentacin de carcter
introductorio) por el IDE se conocen como Refactorizacin del cdigo.
Tambin podemos llamar a funciones dentro de condiciones if o dentro de bucles:
function DoubleNumber(x: Integer): Integer;
begin
82
Result:= x * 2;
end;
// Cdigo principal
begin
if DoubleNumber(5) > 10 then
Writeln('Este nmero es mayor que 10')
else
Writeln('Este nmero es igual o menor que 10');
Readln;
end.
En este ejemplo, el procedimiento doSomething (hacer algo) recibe un valor entero en la variable
x, entonces lo multiplica por dos, y finalmente lo muestra.
En la parte principal del programa, declaramos la variable MyNumber como un entero, le asignamos
el valor 5 y se la pasamos como parmetro al procedimiento DoSomething. En este caso, el valor de
la variable MyNumber (5) es copiado en la variable x.
Despus de que se llama a la funcin, el valor de x ser 10, pero cuando mostramos por pantalla el
valor de MyNumber despus del procedimiento encontramos de que mantiene el valor 5. De ah
podemos deducir que las dos variables MyNumber y x tienen dos ubicaciones diferentes en la
memoria, algo que es lo normal.
83
84
Esta vez el valor de la variable MyNumber cambi y dentro del procedimiento tom el valor de la
variable x ,por lo que se deduce que ahora ambas variables comparten la misma ubicacin en la
memoria.
El pasaje de parmetros por referencia requiere que el parmetro sea una variable del mismo tipo: si
el parmetro declarado es de tipo byte, entonces MyNumber debe ser declarado como Byte, si es de
tipo Integer (entero), entonces MyNumber debe ser una variable entero (Integer).
Importante: No se puede pasar una constante a un procedimiento (o funcin) cuyo parmetro espere
que se le pase un valor por referencia. El siguiente ejemplo genera un error cuando se llama al
procedimiento DoSomething, porque se espera una variable y no una constante.
DoSomething(5);
En el paso de parmetro(s) por valor s se puede usar el ejemplo mostrado, pero siempre se debe
tener en cuenta que al pasar un parmetro por referencia el valor de la variable pasada puede
cambiar (de hecho, la idea de pasar por referencia es que dentro del procedimiento o funcin se
cambie el valor de la(s) variable(s).
En el siguiente ejemplo el procedimiento SwapNumbers (intercambiar nmeros) recibe dos
variables A y B (pasadas por referencia) e intercambia sus valores:
procedure SwapNumbers(var x, y: Integer);
var
Temp: Integer;
begin
Temp:= x;
85
x:= y;
y:= Temp;
end;
// Cdigo principal
var
A, B: Integer;
begin
Write('Por favor ingrese el valor para A: ');
Readln(A);
Write('Por favor ingrese el valor para B: ');
Readln(B);
SwapNumbers(A, B);
Writeln('A = ', A, ', and B = ', B);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.
86
Unidades
Una unidad en Pascal es una biblioteca (un archivo separado del cdigo principal del programa) que
contiene procedimientos, funciones, constantes, variables y tipos definidos por el usuario; la misma
unidad puede ser usada desde muchas aplicaciones.
El propsito del uso de unidades es el siguiente:
1. Reutilizar cdigo: Almacenar procedimientos y funciones que son usados con frecuencia por
las aplicaciones en archivos externos. De esta forma se logra la reusabilidad (volver a
aprovechar lo que ya est escrito) de cdigo fuente en el desarrollo de software.
2. Agrupar procedimientos y funciones que realizan una determinada tarea dentro de una
biblioteca. En lugar de ocupar el cdigo fuente principal de la aplicacin con procedimientos
(y funciones) sin relacin entre s, es mejor agruparlas siguiendo una lgica dentro de
archivos separados usando unidades. Por ejemplo una unidad podra contener el cdigo
correspondiente a clculos, otra a acceso a base de datos, otra unidad se encargara de
imprimir, etc. Un cdigo organizado de esta forma (divide y vencers) es mucho ms fcil
de leer (y de mantener).
Para crear una unidad nueva, se usa la opcin Nueva unidad dentro del tem del men Archivo
de Lazarus. Esto crear una nueva unidad con un aspecto como el siguiente:
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
implementation
end.
Una vez creada la unidad, esta se debe guardar usando un nombre a eleccin del programador, por
ejemplo test . De esa forma, el archivo que se guardar se llamar test.pas , pero el nombre de la
unidad se seguir llamado test dentro de nuestra aplicacin.
Dentro de la unidad podemos escribir procedimientos, funciones y cualquier otro cdigo fuente que
queremos que sea reusable:
unit Test;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
87
const
GallonPrice = 6.5; // Precio del combustible
function GetKilometers(Payment, Consumption: Integer): Single;
implementation
function GetKilometers(Payment, Consumption: Integer): Single;
begin
Result:= (Payment / GallonPrice) * Consumption;
end;
end.
La constante GallonPrice (el precio del combustible) y la funcin GetKilometers sern accesibles
desde cualquier programa (o desde otras unidades).
Hemos colocado tambin el encabezado de la funcin dentro de una seccin de la unidad llamada
Interface ,que permita que esa funcin (junto con las constantes, tipos o variables) sean visibles
desde fuera de la unidad (desde el cdigo principal del programa o bien desde otras unidades). Por
el contrario, el cdigo dentro de la seccin implementation slo ser visible desde dentro de la
propia unidad.
Para usar esta unidad, creamos un nuevo programa en el mismo directorio donde se almacena la
misma (Test.pas), y dentro del cdigo fuente agregamos el nombre de la unidad dentro de la
clusula uses como se ve en el siguiente ejemplo:
program PetrolConsumption;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils,
{ puede agregar unidades despus de aqu }
Test; // Usamos la unidad test.pas
var
Payment: Integer;
Consumption: Integer;
Kilos: Single;
begin
Write('Ingrese el importe que pag por cargar gasolina: ');
Readln(Payment);
Write('Ingrese el consumo de gasolina (kilmetro por litro): ');
Readln(Consumption);
Kilos:= GetKilometers(Payment , Consumption);
Writeln('Esta cantidad de combustible puede mantener el vehculo en marcha
por: ',Format('%0.1f', [Kilos]), ' kilmetros');
Write('Presione Enter para cerrar');
88
Readln;
end.
Si necesita ir al cdigo fuente de la funcin GetKilometers desde el cdigo del programa, esto se
logra presionando la tecla Ctrl y haciendo clic con el ratn sobre el nombre de la funcin: esto
mostrar el cdigo fuente de la unidad con el cursor ubicado en la funcin.
Otra alternativa para acceder rpidamente al cdigo fuente de la unidad Test es colocar el cursor
sobre el nombre de la unidad (Test) y presionando la combinacin de teclas Alt + Enter.
Podemos acceder a las unidades desde nuestros programas bajo las siguientes condiciones:
1. El archivo de la unidad tienen que estar en el mismo directorio que la aplicacin, como
vimos en el ejemplo anterior.
2. Agregando la unidad al proyecto: Esto se hace abriendo el archivo de la unidad dentro de
Lazarus y luego incorporndola a los archivos que componen el programa desde el
Inspector de proyecto (a travs de la opcin Proyecto del men principal). Dentro de la
ventana del Inspector de proyecto se utiliza el botn Aadir y as incorporamos la
unidad abierta al proyecto.
3. Agregando el trayecto donde est ubicado el archivo de la unidad dentro de las opciones del
compilador: Proyecto/Opciones para el proyecto Opciones del compilador/Rutas y
agregndolas en la opcin Otros archivos de unidad.
A continuacin se muestra el aspecto que tienen en Lazarus las ventanas Inspector de Proyecto y
Opciones para el proyecto. En este caso los ejemplos son de Lazarus ejecutndose bajo el sistema
operativo Gnu/Linux.
89
90
91
Los programadores pueden utilizar las unidades provistas por Free Pascal / Lazarus y pueden
escribir sus propias unidades. Las unidades creadas por el programador son para satisfacer
requerimientos especiales de sus programas. Por ejemplo, si se est escribiendo un programa para
un garage de autos (cochera), entonces es probable que se cree una unidad que contenga cdigo
para agregado de datos de un nuevo automvil, bsqueda en la base de datos a travs de la patente,
etc.
El colocar procedimientos y funciones dentro de las unidades hace al programa ms legible,
facilitando que se pueda realizar un trabajo colaborativo entre varios desarrolladores, ya que cada
uno puede centrarse en una (o ms unidades), pudiendo verificar el funcionamiento de cada una en
forma independiente, para luego integrar estas unidades juntas en un proyecto.
92
El calendario islmico Hejri (tambin conocido como calendario musulmn) est basado en meses
lunares. En este ejemplo vamos a crear una unidad para ayudar a convertir el calendario Gregoriano
al calendario lunar Hejri basndonos en las siguientes reglas:
1. El primer da del calendario Hejri es el 16 de julio del ao 622 en el calendario gregoriano.
2. En el calendario Hejri el ao contiene 354.367056 das.
3. Un mes del calendario Hejri contiene 29.530588 das.
Ms informacin: http://es.wikipedia.org/wiki/Calendario_musulmn
La unidad Hejri de ejemplo puede usarse para obtener la fase actual de la luna.
Este es el cdigo fuente de la unidad Hejri:
{
********************************************************************************
HejriUtils:
Author:
email:
Home page:
License:
Created on:
Last modifie:
*******************************************************************************
}
unit HejriUtils;
{$IFDEF FPC}
{$mode objfpc}{$H+}
{$ENDIF}
interface
uses
Classes, SysUtils;
const
HejriMonthsEn: array [1 .. 12] of string = ('Moharram', 'Safar', 'Rabie Awal',
'Rabie Thani', 'Jumada Awal', 'Jumada Thani', 'Rajab', 'Shaban', 'Ramadan',
'Shawal', 'Thi-Alqaida', 'Thi-Elhajah');
HejriMonthsAr: array [1 .. 12] of string = (' ' ,' ', '',
' ',' ',' ',' ' ,' ' ,'' ,
'' ,' ' ,';)'
HejriYearDays = 354.367056;
HejriMonthDays = 29.530588;
93
94
end.
2.
3.
HejriToDate: Esta funcin convierte una fecha Hejri a una fecha en del calendario
gregoriano (valor TdateTime).
HejriDifference: Este procedimiento calcula la diferencia en aos, das y meses entre dos
fechas del calendario Hejri.
95
Hemos usado la palabra reservada overload, para indicar que se usar una sobrecarga (overloading)
de funciones.
96
En este ejemplo, invocamos a la funcin SumAll tres veces: la primera vez usando dos valores, la
segunda vez usando tres y la ltima vez usamos cuatro valores. a y b son paramtros obligatorios
porque no les especificamos valores por defecto, entonces siempre deben especificarse al invocar la
funcin.
Podemos ignorar el envo de valores a los parmetros de la funcin desde la izquierda hacia la
derecha, por ejemplo, si no especificamos el parmetro c, entonces tampoco podemos enviar un
parmetro a d. De esta manera, si invocamos a la funcin como se ve a continuacin obtendremos
un mensaje de error:
Writeln(SumAll(1, 2, , 4));
Los valores por defecto para parmetros deben comenzar desde izquierda a derecha. No podemos
declarar un parmetro con valor por defecto y luego declarar otro a continuacin que no tenga un
valor por defecto, como se muestra a continuacin:
function ErrorParameters(a: Integer; b: Integer = 10; c: Integer; x: string);
97
10
Observando los nmeros, vemos que har falta ms de una pasada (o ciclo) para ordenarlos.
Primera pasada: El primer nmero (7) se compara con el segundo (10) y si es mayor se
intercambian entre s, entonces el segundo se compara con el tercero (2) y as sucesivamente hasta
que el quinto nmero se compara con el sexto.
Despus de esta primera pasada (primer ciclo) los valores quedarn como se muestra a
continuacin:
7
10
10
10
Tercera pasada:
2
Cuarta pasada:
98
10
99
Se puede modificar el cdigo para que el ordenamiento de los nmeros ingresados se haga en forma
descendente, simplemente cambiando el operador mayor que (>) por menor que (<) en la siguiente
lnea:
if X[i] < X[i + 1] then
En el ejemplo siguiente, ordenaremos una lista de estudiantes a partir de sus calificaciones (notas),
colocando en primer lugar los que tuvieron mejores calificaciones, y los de peores calificaciones al
final de la lista:
Ordenando la lista de estudiantes por sus calificaciones
program smSort;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes
{ usted puede agregar unidades despus de aqu };
type
TStudent = record
StudentName: string; // Nombre
Mark: Byte;
// Calificacin (nota)
end;
procedure BubbleSort(var X: array of TStudent);
var
Temp: TStudent;
i: Integer;
Changed: Boolean;
begin
repeat
Changed:= False;
for i:= 0 to High(X) - 1 do
if X[i].Mark < X[i + 1].Mark then
begin
Temp:= X[i];
X[i]:= X[i + 1];
X[i + 1]:= Temp;
Changed:= True;
end;
100
El algoritmo de ordenacin por burbuja es muy simple y los programadores hasta pueden conocerlo
de memoria. Es apropiado para ordenar pequeas cantidades de datos. Si la cantidad de elementos a
ordenar es muy extensa, es ms recomendable optar por otro algoritmo ms eficiente.
Este algoritmo es similar al de burbuja, pero es ms veloz con grandes cantidades de datos. Este
algoritmo contiene dos bucles anidados (uno dentro de otro): el intercambio se realiza en el
buble interno, mientras que las comparaciones se hacen en el buble interno: se realizan muchas ms
comparaciones que intercambios. Observemos el siguiente cdigo donde se ve el funcionamiento de
este algoritmo:
program SelectionSort;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
101
Classes
{ usted puede agregar unidades despus de aqu };
procedure SelectSort(var X: array of Integer);
var
i: Integer;
j: Integer;
SmallPos: Integer;
Smallest: Integer;
begin
for i:= 0 to High(X) -1 do // Buble externo
begin
SmallPos:= i;
Smallest:= X[SmallPos];
for j:= i + 1 to High(X) do // Buble interno
if X[j] < Smallest then
begin
SmallPos:= j;
Smallest:= X[SmallPos];
end;
X[SmallPos]:= X[i];
X[i]:= Smallest;
end;
end;
// Cdigo principal
var
Numbers: array [0 .. 9] of Integer;
i: Integer;
begin
Writeln('Por favor ingrese 10 nmeros al azar');
for i:= 0 to High(Numbers) do
begin
Write('#', i + 1, ': ');
Readln(Numbers[i]);
end;
SelectSort(Numbers);
Writeln;
Writeln('Lista de nmeros ordenada: ');
for i:= 0 to High(Numbers) do
begin
Writeln(Numbers[i]);
end;
Write('Presione la tecla Enter para finalizar');
Readln;
end.
102
103
ShellS(Numbers);
Writeln;
Writeln('Lista de nmeros ordenada por el algoritmo Shell: ');
for i:= 0 to High(Numbers) do
begin
Writeln(Numbers[i]);
end;
Write('Presione la tecla Enter para finalizar');
Readln;
end.
104
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes;
type
TStudent = record
StudentName: string;
Mark: Byte;
end;
procedure BubbleSort(var X: array of TStudent);
var
Temp: TStudent;
i: Integer;
Changed: Boolean;
begin
repeat
Changed:= False;
for i:= 0 to High(X) - 1 do
if X[i].StudentName > X[i + 1].StudentName then
begin
Temp:= X[i];
X[i]:= X[i + 1];
X[i + 1]:= Temp;
Changed:= True;
end;
until not Changed;
end;
var
Students: array [0 .. 9] of TStudent;
i: Integer;
105
begin
Writeln('Ingrese los datos de 10 estudiantes (nombre y calificacin)');
for i:= 0 to High(Students) do
begin
Write('Estudiante #', i + 1, ' nombre : ');
Readln(Students[i].StudentName);
Write('Estudiante #', i + 1, ' calificacin : ');
Readln(Students[i].Mark);
Writeln;
end;
BubbleSort(Students);
Writeln;
Writeln('Lista ordenada: ');
Writeln('--------------');
for i:= 0 to High(Students) do
begin
Writeln('# ', i + 1, ' ', Students[i].StudentName,
' calificacin (', Students[i].Mark, ')');
end;
Write('Precione la tecla Enter para finalizar');
Readln;
end.
106
107
Randomize;
for i:= 0 to High(X) do
X[i]:= Random(10000000);
end;
var
Numbers: array [0 .. 1000000] of Integer;
i: Integer;
StartTime: TDateTime;
begin
Writeln('--- Lista generada completamente al azar ---');
RandomizeData(Numbers);
StartTime:= Now;
Writeln('Ordenando por el algoritmo de burbuja');
BubbleSort(Numbers);
Writeln('Lista ordenada en: (mm:ss): ',
FormatDateTime('nn:ss', Now - StartTime));
Writeln;
RandomizeData(Numbers);
Writeln('Ordenando por el algoritmo de seleccin');
StartTime:= Now;
SelectionSort(Numbers);
Writeln('Lista ordenada en: (mm:ss): ',
FormatDateTime('nn:ss', Now - StartTime));
Writeln;
RandomizeData(Numbers);
Writeln('Ordenando por el algoritmo Shell');
StartTime:= Now;
ShellSort(Numbers);
Writeln('Lista ordenada en: (mm:ss): ',
FormatDateTime('nn:ss', Now - StartTime));
Writeln;
Writeln('--- Lista parcialmente ordenada ---');
Numbers[0]:= Random(10000);
Numbers[High(Numbers)]:= Random(10000);
StartTime:= Now;
Writeln('Ordenando por el algoritmo de burbuja');
BubbleSort(Numbers);
Writeln('Lista ordenada en (mm:ss): ',
FormatDateTime('nn:ss', Now - StartTime));
Writeln;
Numbers[0]:= Random(10000);
Numbers[High(Numbers)]:= Random(10000);
Writeln('Ordenando por el algoritmo de seleccin');
StartTime:= Now;
SelectionSort(Numbers);
Writeln('Lista ordenada en (mm:ss): ',
FormatDateTime('nn:ss', Now - StartTime));
Writeln;
Numbers[0]:= Random(10000);
Numbers[High(Numbers)]:= Random(10000);
Writeln('Ordenando por el algoritmo Shell');
108
StartTime:= Now;
ShellSort(Numbers);
Writeln('Lista ordenada en (mm:ss): ',
FormatDateTime('nn:ss', Now - StartTime));
Write('Presione la tecla Enter para finalizar');
Readln;
end.
109
Captulo 3
La interfaz grfica
110
Introduccin
La interfaz grfica de usuario (GUI) es la nueva alternativa a la interfaz de consola. Contiene
formularios, botones, mensajes, mens y otros componentes grficos. Es ms sencillo para los
usuarios usar aplicaciones GUI que las aplicaciones de consola.
El GUI se usa para aplicaciones empresariales, sistemas operativos, juegos y desarrollo de
herramientas como Lazarus y muchas otras.
111
Podemos mostrar las propiedades del botn tales como Texto, nombre, anchura (caption, name,
112
width, etc) en el Inspector de objetos. Si este no aparece en las ventanas de Lazarus, podremos
mostrarlo haciendo click en Ventana/Inspector de objetos (Window/Object Inspector) del men
principal o presionando F11. Obtendremos una ventana como esta:
Ahora escriba esta lnea en la plantilla del evento OnClick que Lazarus ha creado por nosotros:
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage('Hola mundo, esta es mi primera GUI');
end;
113
Al hacer esto, cuando iniciemos la aplicacin, se mostrar una ventana de dialogo conteniendo el
mensaje deseado al hacer click en el botn con el ratn.
En Linux, encontraremos primergui como un archivo ejecutable en la misma carpeta del proyecto, y
firstgui.exe si estamos usando Windows. Estos son los archivos ejecutables que se pueden copiar a
otro ordenador y ejecutar sin necesidad de tener instalado Lazarus.
En el ejemplo anterior hay algunas cuestiones importantes:
1. Archivo principal de aplicacin: Se encuentra en primergui.lpi en el ejemplo. Podremos
verlo haciendo click en Project/Source. Veremos este cdigo:
program primergui;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms
{ usted puede agregar unidades despues de aqu }, main;
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Deberemos modificar este cdigo en algunos casos segn nuestras necesidades, pero normalmente
podremos dejarlo tal como est y permitir a Lazarus manejarlo automticamente.
2. Unidad principal: Esta unidad es la que contiene las definiciones del formulario que aparece
automticamente cuando iniciamos la aplicacin.
A continuacin est el cdigo completo de la unidad principal con el evento OnClick.
unit main;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
StdCtrls;
114
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage('Hola mundo, esta es mi primera aplicacin GUI');
end;
initialization
{$I main.lrs}
end.
115
Este procedimiento ser llamado cuando se haga click en el botn. El procedimiento recibe el
nombre de (handler).
116
117
Ahora podemos iniciar la aplicacin, escribir nuestro nombre en la caja de texto y hacer click en el
botn.
En el ejemplo anterior se ha utilizado la propiedad Text de la caja de texto edName para leer lo que
el usuario ha escrito. Esta es la alternativa grfica para el procedimiento Readln usado en las
aplicaciones de consola para recibir datos del usuario.
Tambin hemos utilizado la propiedad Caption del label laYourName para mostrar el mensaje. Este
es uno de los mtodos alternativos a Writeln en aplicaciones GUI.
Al hacer click en el botn Add se aadir el texto de la caja de texto al listado. El botn Delete
borrar el objeto que actualmente est seleccionado. El botn clear borrar completamente la lista.
Finalmente el botn Close finalizar la aplicacin.
119
Comience una nueva aplicacin y coloque los siguientes objetos en el formulario principal:
- TMainMenu
- TMemo: cambie la propiedad align a alClient y ScrollBars a ssBoth
- TOpenDialog y TSaveDialog de la paleta de componentes Dialogs.
Haga doble Click en el componente MainMenu1 y aada el texto File (Archivo) a este hay
que crearle un submen que contenga las opciones Abrir, Guardar y cerrar como objetos de
men.
if OpenDialog1.Execute then
Memo1.Lines.LoadFromFile(OpenDialog1.FileName);
if SaveDialog1.Execute then
Memo1.Lines.SaveToFile(SaveDialog1.FileName);
Close;
Despus de iniciar la aplicacin, podremos escribir texto y guardarlo en disco. Tambin es posible
abrir archivos existentes como los .pas.
120
121
Aplicacin de noticias
Esta vez escribiremos una aplicacin para almacenar ttulos de noticias, siga estos pasos:
Button1
Caption: Aadir ttulo
Button2
Caption: Guardar
Anchors: Left=False, Right=True
Edit1:
Text=
Memo1
ScrollBars: ssBoth
ReadOnly: True
Anchors: Top=True, Left=Ture, Right=True, Bottom=Ture
Tendr un formulario similar a este:
Para el evento OnClick del botn Aadir ttulo escriba este cdigo:
Memo1.Lines.Insert(0,
FormatDateTime('yyyy-mm-dd hh:nn', Now) + ': ' + Edit1.Text);
122
En el evento OnClose del formulario principal escriba lo siguiente para se guarden las
noticias:
Memo1.Lines.SaveToFile('news.txt');
En el evento OnCreate del formulario principal escriba este cdigo para cargar los ttulos de
noticias que haban sido previamente guardados.
if FileExists('news.txt') then
Memo1.Lines.LoadFromFile('news.txt');
Ya puede iniciar la aplicacin y hacer click en el botn para mostrar el segundo formulario.
123
Captulo 4
Programacin
Orientada a Objetos
124
Introduccin
En la Programacin Orientada a Objetos, describimos las entidades de una aplicacin como objetos.
Por ejemplo, podemos representar informacin de automviles como un objeto que contiene
nombre del modelo, ao del modelo, precio, y ese objeto tiene la capacidad de guardar estos datos
en un archivo.
El objeto contiene:
1. Propiedades que almacenan informacin de estado. Estos valores pueden ser guardados en
variables.
2. Procedimientos y funciones que son llamados Mtodos. Estos mtodos representan las
acciones que pueden ser realizadas en el objeto.
3. Eventos: Sucesos que pueden ser recibidos por el objeto, como el cursor de ratn
movindose sobre el objeto, un clic de ratn, etc.
4. Manejadores de eventos: Estos son los procedimientos que sern ejecutados si un evento
ocurre.
Las propiedades y mtodos que estn relacionados entre s pueden ser representados como un
objeto:
125
uses
Classes, SysUtils;
type
{ TMyDateTime }
TMyDateTime = class
private
fDateTime: TDateTime;
public
function GetDateTime: TDateTime;
procedure SetDateTime(ADateTime: TDateTime);
procedure AddDays(Days: Integer);
procedure AddHours(Hours: Single);
function GetDateTimeAsString: string;
function GetTimeAsString: string;
function GetDateAsString: string;
constructor Create(ADateTime: TDateTime);
destructor Destroy; override;
end;
implementation
{ TMyDateTime }
function TMyDateTime.GetDateTime: TDateTime;
begin
Result:= fDateTime;
end;
procedure TMyDateTime.SetDateTime(ADateTime: TDateTime);
begin
fDateTime:= ADateTime;
end;
procedure TMyDateTime.AddDays(Days: Integer);
begin
fDateTime:= fDateTime + Days;
end;
procedure TMyDateTime.AddHours(Hours: Single);
begin
fDateTime:= fDateTime + Hours / 24;
end;
function TMyDateTime.GetDateTimeAsString: string;
begin
Result:= DateTimeToStr(fDateTime);
end;
function TMyDateTime.GetTimeAsString: string;
begin
Result:= TimeToStr(fDateTime);
end;
function TMyDateTime.GetDateAsString: string;
begin
Result:= DateToStr(fDateTime);
end;
126
Hemos puesto cinco botones sobre el formulario principal, tal como se muestra:
127
Button4: TButton;
Button5: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public
MyDT: TMyDateTime;
{ public declarations }
end;
var
Form1: TForm1;
implementation
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
MyDT := TMyDateTime.Create(Now);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(MyDT.GetDateTimeAsString);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
ShowMessage(MyDT.GetDateAsString);
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
ShowMessage(MyDT.GetTimeAsString);
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
MyDT.AddHours(1);
end;
procedure TForm1.Button5Click(Sender: TObject);
begin
MyDT.AddDays(1);
end;
initialization
{$I main.lrs}
end.
Unidad DateTimeUnit.1. Se define TMyDateTime como class, que es la palabra reservada para definir nuevas classes.
2. Se introduce el mtodo Constructor: Create. Este es un procedimiento especial que es
usado para crear objetos en memoria e inicializarlos.
3. Se introduce el mtodo Destructor: Destroy. Este es un procedimiento especial que es
llamado para liberar la memoria del objeto despus de terminar de usarlo.
4. Hay dos secciones en esa clase: private, la cual contiene propiedades y mtodos que no
pueden ser accedidas desde fuera de la unidad de la clase. La otra seccin es public, la cual
contiene propiedades y mtodos que pueden ser accedidos desde fuera de la unidad. Si una
clase no contiene una seccin pblica, significa que no puede utilizarse en absoluto.
Unidad Main:
1. Hemos agregado DateTimeUnit en la clusula Uses del formulario principal para acceder a
su clase.
2. Hemos declarado el objeto MyDT dentro de la unidad: MyDT:
3.
TMyDateTime;
4. Hemos creado el objeto e inicializado este en el evento OnCreate del formulario principal.
5.
MyDT := TMyDateTime.Create(Now);
129
En este ejemplo, nosotros deseamos reescribir la aplicacin de noticias usando mtodos orientados a
objetos. Tambin tenemos que clasificar las noticias en archivos separados.
Hemos creado una nueva aplicacin GUI y le dimos el nombre oonews.
El siguiente ejemplo es una nueva unidad que contiene la clase TNews, la cual tiene funcionalidad
para noticias.
unit news;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
type
TNewsRec = record
ATime: TDateTime;
Title: string[100];
end;
{ TNews }
TNews = class
private
F: file of TNewsRec;
fFileName: string;
public
constructor Create(FileName: string);
destructor Destroy; override;
procedure Add(ATitle: string);
procedure ReadAll(var NewsList: TStringList);
function Find(Keyword: string;
var ResultList: TStringList): Boolean;
end;
implementation
{ TNews }
constructor TNews.Create(FileName: string);
begin
fFileName:= FileName;
end;
destructor TNews.Destroy;
begin
inherited Destroy;
end;
procedure TNews.Add(ATitle: string);
var
130
Rec: TNewsRec;
begin
AssignFile(F, fFileName);
if FileExists(fFileName) then
begin
FileMode:= 2; // Read/write access
Reset(F);
Seek(F, FileSize(F));
end
else
Rewrite(F);
Rec.ATime:= Now;
Rec.Title:= ATitle;
Write(F, Rec);
CloseFile(F);
end;
procedure TNews.ReadAll(var NewsList: TStringList);
var
Rec: TNewsRec;
begin
NewsList.Clear;
AssignFile(F, fFileName);
if FileExists(fFileName) then
begin
Reset(F);
while not Eof(F) do
begin
Read(F, Rec);
NewsList.Add(DateTimeToStr(Rec.ATime) + ' : ' + Rec.Title);
end;
CloseFile(F);
end;
end;
function TNews.Find(Keyword: string; var ResultList: TStringList): Boolean;
var
Rec: TNewsRec;
begin
ResultList.Clear;
Result:= False;
AssignFile(F, fFileName);
if FileExists(fFileName) then
begin
Reset(F);
while not Eof(F) do
begin
Read(F, Rec);
if Pos(LowerCase(Keyword), LowerCase(Rec.Title)) > 0 then
begin
ResultList.Add(DateTimeToStr(Rec.ATime) + ' : ' + Rec.Title);
Result:= True;
end;
end;
CloseFile(F);
131
end;
end;
end.
132
TForm1 = class(TForm)
btAdd: TButton;
btShowAll: TButton;
btSearch: TButton;
cbType: TComboBox;
edTitle: TEdit;
Label1: TLabel;
Label2: TLabel;
Memo1: TMemo;
procedure btAddClick(Sender: TObject);
procedure btSearchClick(Sender: TObject);
procedure btShowAllClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public
NewsObj: array of TNews;
{ public declarations }
end;
var
Form1: TForm1;
implementation
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
var
i: Integer;
begin
SetLength(NewsObj, cbType.Items.Count);
for i:= 0 to High(NewsObj) do
NewsObj[i]:= TNews.Create(cbType.Items[i] + '.news');
end;
procedure TForm1.btAddClick(Sender: TObject);
begin
NewsObj[cbType.ItemIndex].Add(edTitle.Text);
end;
procedure TForm1.btSearchClick(Sender: TObject);
var
SearchStr: string;
ResultList: TStringList;
begin
ResultList:= TStringList.Create;
if InputQuery('Search News', 'Please input keyword', SearchStr) then
if NewsObj[cbType.ItemIndex].Find(SearchStr, ResultList) then
begin
Memo1.Lines.Clear;
Memo1.Lines.Add(cbType.Text + ' News');
Memo1.Lines.Add('--------------------------------------------------');
Memo1.Lines.Add(ResultList.Text);
end
else
Memo1.Lines.Text:= SearchStr + ' not found in ' +
cbType.Text + ' news';
133
ResultList.Free;
end;
procedure TForm1.btShowAllClick(Sender: TObject);
var
List: TStringList;
begin
List:= TStringList.Create;
NewsObj[cbType.ItemIndex].ReadAll(List);
Memo1.Lines.Clear;
Memo1.Lines.Add(cbType.Text + ' News');
Memo1.Lines.Add('-----------------------------------------------------------');
Memo1.Lines.Add(List.Text);
List.Free;
end;
procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
var
i: Integer;
begin
for i:= 0 to High(NewsObj) do
NewsObj[i].Free;
NewsObj:= nil;
end;
initialization
{$I main.lrs}
end.
Lo cual significa que prepare espacio para 10 elementos en esa matriz. Esto es similar a la
declaracin de una matriz normal:
NewsObj: array [0 .. 9] of TNews;
El tamao de una matriz normal permanecer constante durante el tiempo que una aplicacin est
corriendo, pero el tamao de una matriz dinmica puede ser aumentado y disminuido.
134
En este ejemplo, hemos inicializado la matriz de acuerdo a las categoras que existen en el cuadro
combinado.
SetLength(NewsObj, cbType.Items.Count);
135
Aplicacin Cola
Una cola es un ejemplo de tipo de estructura de datos. Esta es utilizada para insertar y guardar
elementos de forma secuencial y eliminarlos en el orden en el cual fueron insertados. Su regla se
llama primero en entrar, primero en salir.
En el siguiente ejemplo, hemos escrito una unidad llamada Queue (en ingls, cola), la cual contiene
la clase TQueue. La clase TQueue puede ser utilizada para guardar datos como nombres, y
obtenerlos de forma secuencial. Obtener datos de una cola elimina esos datos. Por ejemplo, si la
cola contiene 10 elementos, y nosotros obtenemos y leemos tres, siete elementos se quedarn en la
cola.
Unidad Queue:
unit queue;
// This unit contains TQueue class,
// which is suitable for any string queue
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
type
{ TQueue }
TQueue = class
private
fArray: array of string;
fTop: Integer;
public
constructor Create;
destructor Destroy; override;
function Put(AValue: string): Integer;
function Get(var AValue: string): Boolean;
function Count: Integer;
function ReOrganize: Boolean;
end;
implementation
{ TQueue }
constructor TQueue.Create;
begin
fTop:= 0;
end;
destructor TQueue.Destroy;
begin
SetLength(fArray, 0); // Erase queue array from memory
inherited Destroy;
end;
136
137
138
end;
var
fmMain: TfmMain;
implementation
{ TfmMain }
procedure TfmMain.FormCreate(Sender: TObject);
begin
MyQueue:= TQueue.Create;
end;
procedure TfmMain.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
MyQueue.Free;
end;
procedure TfmMain.bbCountClick(Sender: TObject);
begin
Memo1.Lines.Add('Queue length is: ' + IntToStr(MyQueue.Count));
end;
procedure TfmMain.bbAddClick(Sender: TObject);
var
APosition: Integer;
begin
APosition:= MyQueue.Put(edCustomer.Text);
Memo1.Lines.Add(edCustomer.Text + ' has been added as # ' +
IntToStr(APosition + 1));
end;
procedure TfmMain.bbGetClick(Sender: TObject);
var
ACustomer: string;
begin
if MyQueue.Get(ACustomer) then
begin
Memo1.Lines.Add('Got: ' + ACustomer + ' from the queue');
end
else
Memo1.Lines.Add('Queue is empty');
end;
initialization
{$I main.lrs}
end.
En la clase TQueue, hemos empleado el mtodo Put para insertar un nuevo elemento expandiendo
la matriz dinmica fArray, y poner el nuevo elemento en la nueva ltima posicin de la matriz.
Cuando se llama al mtodo Get para quitar el elemento que est al inicio de la cola, el apuntador
fTop se mueve al siguiente elemento de la cola.
139
Sacar elementos del comienzo de la matriz dinmica, causar que se mueva el apuntador fTop, pero
las casillas de la matriz dinmica permanecern en memoria y seguirn ocupando espacio, ya que
slo podemos eliminar esas casillas desde el fondo (extremo final) de la matriz dinmica. Por esta
razn, si el nmero de elementos extrados alcanza 100, ser llamado el mtodo ReOrganize para
mover los elementos al inicio de la matriz dinmica y suprimir el espacio que ya no usa.
Este es el cdigo que mueve los elementos de la cola al comienzo de la matriz dinmica:
for i:= fTop to High(fArray) do
fArray[i - fTop]:= fArray[i];
Y este es el cdigo para cortar la matriz dinmica de la parte inferior (extremo final).
// Truncate unused data
SetLength(fArray, PCount);
fTop:= 0;
En este ejemplo, hemos encontrado que la programacin orientada a objetos introduce informacin
oculta. Es negado el acceso a datos sensibles, como ciertos campos ("variables") de la clase. En su
lugar, podemos usar mtodos especficos que no provocarn un comportamiento raro en el objeto.
Los datos y mtodos sensibles son colocados en la seccin privada de la declaracin de la clase:
private
fArray: array of string;
fTop: Integer;
Los programadores que usen esta clase no podrn acceder directamente a estos campos. Si fueran
capaces de acceder a ellos, entonces podran corromper la cola modificando fTop o fArray por
accidente. Por ejemplo, suponga que fTop ha sido cambiado a 1000 cuando la cola contiene slo 10
elementos; eso provocara un error de violacin de acceso en tiempo de ejecucin.
Como alternativa al uso directo de campos de la clase, hemos implementado los mtodos Put y Get
para agregar y remover elementos de la matriz de forma segura. Este mecanismo es como usar
puertas para controlar los elementos interiores. Se trata de una caracterstica de la POO llamada
encapsulamiento.
Este mecanismo es muy similar a usar archivos sin tipo, excepto que se emplea un archivo
orientado a objetos.
Tambin podemos usar una forma ms simple de copiar archivos:
procedure TfmMain.Button1Click(Sender: TObject);
var
SourceF, DestF: TFileStream;
begin
if OpenDialog1.Execute and SaveDialog1.Execute then
begin
SourceF:= TFileStream.Create(OpenDialog1.FileName, fmOpenRead);
DestF:= TFileStream.Create(SaveDialog1.FileName, fmCreate);
DestF.CopyFrom(SourceF, SourceF.Size);
SourceF.Free;
DestF.Free;
ShowMessage('Copy finished');
end;
end;
141
El mtodo CopyForm copia el contenido total del archivo al archivo destino porque dimos a ste el
tamao del archivo origen: SourceF.Size.
Herencia
La herencia en Programacin Orientada a Objetos significa crear una nueva clase a partir de una
existente, heredando sus mtodos y propiedades. Despus de heredar propiedades y mtodos
existentes, podemos agregar nuevos mtodos y propiedades a la nueva clase.
Como ejemplo de herencia, deseamos crear una nueva clase cola Integer a partir de nuestra vieja
clase cola String. En vez de escribir la cola Integer a partir de cero, podemos heredar de la cola
String.
Para heredar de la cola String, aada una nueva unidad y ponga la unidad de la cola String en su
clusula Uses. Entonces declare la nueva cola Integer as:
TIntQueue = class(TQueue)
El nombre de la nueva unidad es IntQueue, y hemos introducido dos nuevos mtodos: PutInt y
GetInt.
El cdigo completo de la unidad que contiene la case TIntQueue es:
unit IntQueue;
// This unit contains TIntQueue class, which is inherits TQueue
// class and adds PutInt, GetInt methods to be used with
// Integer queue
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Queue;
type
{ TIntQueue }
TIntQueue = class(TQueue)
public
function PutInt(AValue: Integer): Integer;
function GetInt(var AValue: Integer): Boolean;
end;
implementation
{ TIntQueue }
function TIntQueue.PutInt(AValue: Integer): Integer;
begin
Result:= Put(IntToStr(AValue));
end;
142
Vea que no escribimos nuevos mtodos Create, Destroy y Count, dado que estos ya existen en la
clase padre TQueue.
Para usar la nueva clase cola Integer, hemos creado una nueva aplicacin y agregado estos
componentes:
143
bbAdd: TButton;
bbCount: TButton;
bbGet: TButton;
edCustomerID: TEdit;
Label1: TLabel;
Memo1: TMemo;
procedure bbAddClick(Sender: TObject);
procedure bbCountClick(Sender: TObject);
procedure bbGetClick(Sender: TObject);
procedure FormClose(Sender: TObject;
var CloseAction: TCloseAction);
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public
MyQueue: TIntQueue;
{ public declarations }
end;
var
fmMain: TfmMain;
implementation
{ TfmMain }
procedure TfmMain.FormCreate(Sender: TObject);
begin
MyQueue:= TIntQueue.Create;
end;
procedure TfmMain.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
MyQueue.Free;
end;
procedure TfmMain.bbCountClick(Sender: TObject);
begin
Memo1.Lines.Add('Queue length is: ' + IntToStr(MyQueue.Count));
end;
procedure TfmMain.bbAddClick(Sender: TObject);
var
APosition: Integer;
begin
APosition:= MyQueue.PutInt(StrToInt(edCustomerID.Text));
Memo1.Lines.Add(edCustomerID.Text + ' has been added as # '
+ IntToStr(APosition + 1));
end;
procedure TfmMain.bbGetClick(Sender: TObject);
var
ACustomerID: Integer;
begin
if MyQueue.GetInt(ACustomerID) then
begin
Memo1.Lines.Add('Got: Customer ID : ' + IntToStr(ACustomerID) +
' from the queue');
end
144
else
Memo1.Lines.Add('Queue is empty');
end;
initialization
{$I main.lrs}
end.
Observe que hemos utilizado las propiedades y mtodos de TQueue adems de las propiedades y
mtodos de TIntQueue.
En este caso, llamamos a la clase original TQueue la clase base o ancestro, y llamamos a la nueva
clase descendiente.
En lugar de crear una nueva clase, podramos modificar la unidad de la cola String y agregarle
PutInt y GetInt para manejar enteros, pero hemos creado la nueva clase TIntQueue para ilustrar la
herencia. Hay tambin otra razn: Suponga que no tenemos el cdigo fuente original de TQueue,
sino solamente el archivo de unidad compilada (.ppu en Lazarus or .dcu en Delphi). En un caso as
no podramos ver el cdigo fuente, y desde luego no podramos modificarlo. La herencia sera la
nica manera de agregar ms funcionalidad a esta cola.
El fin
Code.sd
145