Cuando desarrollamos un programa, nos podemos encontrar con que hay variables que realmente "no varían" a lo largo de la ejecución de un programa, sino que su valor es constante.
Hay una manera especial de definirlas, que es con el especificador "const", que tiene el formato
const Nombre = Valor;
Veamos un par de ejemplos antes de seguir
const MiNombre = 'Nacho Cabanes';
const PI = 3.1415926535;
const LongitudMaxima = 128;
Estas constantes se manejan igual que variables como las que habíamos
visto hasta hora, sólo que no se puede cambiar su valor. Así,
es valido hacer
Writeln(MiNombre);
if Longitud > LongitudMaxima then ...
OtraVariable := MiNombre;
LongCircunf := 2 * PI * r;
pero no podríamos hacer
PI := 3.14;
MiNombre := 'Nacho';
LongitudMaxima := LongitudMaxima + 10;
Las constantes son mucho más prácticas de lo que puede
parecer a primera vista (especialmente para quien venga de lenguajes como
Basic, en el que no existen -en el Basic "de siempre", puede que sí
existan en los últimas versiones del lenguaje-). Me explico
con un ejemplillo:
Supongamos que estamos haciendo nuestra agenda en Pascal (ya falta menos para que sea verdad), y estamos tan orgullosos de ella que queremos que en cada pantalla de cada parte del programa aparezca nuestro nombre, el del programa y la versión actual. Si lo escribimos "de nuevas" cada vez, además de perder tiempo tecleando más, corremos el riesgo de que un día queramos cambiar el nombre (ya no se llamará "Agenda" sino "SuperAgenda" ;-) ) pero lo hagamos en unas partes sí y en otras no, etc., y el resultado tan maravilloso quede estropeado por esos "detalles".
O si queremos cambiar la anchura de cada dato que guardamos de nuestros amigos, porque el espacio para el nombre nos había quedado demasiado escaso, tendríamos que recorrer todo el programa de arriba a abajo, con los mismos problemas, pero esta vez más graves aún, porque puede que intentemos grabar una ficha con una tamaño y leerla con otro distinto...
¿Solución? Pues definir todo ese tipo de datos
como constantes al principio del programa, de modo que con un vistazo a
esta zona podemos hacer cambios globales:
const
Nombre = 'Nacho';
Prog = 'SuperAgenda en Pascal';
Versión = 1.95;
LongNombre = 40;
LongTelef = 9;
LongDirec = 60;
...
Las declaraciones de las constantes se hacen antes del cuerpo del programa principal, y generalmente antes de las declaraciones de variables:
program MiniAgenda;
const
NumFichas = 50;
var
Datos: array[ 1..NumFichas ] of string;
begin
...
Ejercicio propuesto: Modificar el programa de adivinar números (apartado 6.8) para que el número a adivinar deba estar entre 1 y 1000 (estos límites se definirán mediante constantes) y el máximo de intentos permitidos sea 10 (también mediante una constante).
El identificador "const" tiene también en Turbo Pascal otro uso menos habitual: definir lo que se suele llamar constantes con tipo, que son variables normales y corrientes, pero a las que damos un valor inicial antes de que comience a ejecutarse el programa. Se usa
const variable: tipo = valor;
Así, volviendo al ejemplo de la clave de acceso, podíamos tener una variables "intentos" que dijese el número de intentos. Hasta ahora habríamos hecho
var
intentos: integer;
begin
intentos := 3;
...
Ahora ya sabemos que sería mejor hacer, si sabemos que el valor no va a cambiar:
const
intentos = 3;
begin
...
Pero si se nos da el caso de que vemos por el nombre que es alguien de confianza, que puede haber olvidado su clave de acceso, quizá nos interese permitirle 5 o más intentos. ¿Qué hacemos? Ya no podemos usar "const" porque el valor puede variar, pero por otra parte, siempre comenzamos concediendo 3 intentos, hasta comprobar si es alguien de fiar. Conclusión: podemos hacer
const intentos: integer = 3;
begin
...
Insisto: a efectos de manejo, una "constante con tipo" es exactamente
igual que una variable, con las ventajas de que está más
fácil de localizar si queremos cambiar su valor inicial y de que
el compilador optimiza un poco el código, haciendo el programa unos
bytes más pequeño.
El "tipo" de una variable es lo que determina qué clase de valores podremos guardar en ella. Para nosotros, es lo que indicamos junto a su nombre cuando la declaramos. Por ejemplo,
const intentos: integer = 3;
begin
...
indica que vamos a usar una variable que se va a llamar PrimerNumero y que almacenará valores de tipo entero. Si queremos definir una de las fichas de lo que será nuestra agenda, también haríamos:
var ficha: record
nombre: string;
direccion: string;
edad: integer;
observaciones: string
end;
Tampoco hay ningún problema con esto, ¿verdad?
Y si podemos utilizar variables creando los tipos "en el momento", como
en el caso anterior, ¿para qué necesitamos definir tipos?
Vamos a verlo con un ejemplo. Supongamos que vamos a tener ahora dos variables:
una "ficha1" que contendrá el dato de la ficha actual y otra "ficha2"
en la que almacenaremos datos temporales. Veamos qué pasa...
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Intenta asignar dos }
{ tipos definidos como }
{ distintos. Da error }
{ y no compila. }
{ TIPOS1.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Free Pascal 2.2.0w }
{ - Turbo Pascal 7.0 }
{ - Turbo Pascal 5.0 }
{ - Surpas 1.00 }
{ - Tmt Pascal Lt 1.20 }
{--------------------------}
program PruebaTipos;
var
ficha1: record
nombre: string[20];
direccion: string[50];
edad: integer;
observaciones: string[70]
end;
ficha2: record
nombre: string[20];
direccion: string[50];
edad: integer;
observaciones: string[70]
end;
begin
ficha1.nombre := 'Pepe';
ficha1.direccion := 'Su casa';
ficha1.edad := 65;
ficha1.observaciones := 'El mayor de mis amigos... ;-) ';
ficha2 := ficha1;
writeln( ficha2.nombre );
end.
¿Qué haría este programa?
Es fácil de seguir: define dos variables que van a guardar la misma
clase de datos. Da valores a cada uno de los datos que almacenará
una de ellas. Después hacemos que la segunda valga lo mismo
que la primera, e imprimimos el nombre de la segunda. Aparecerá
escrito "Pepe" en la pantalla, ¿verdad?
¡Pues no! Aunque a nuestros ojos "ficha1" y "ficha2" sean iguales, para el compilador no es así, por lo que protesta y el programa ni siquiera llega a ejecutarse. Es decir: las hemos definido para que almacene la misma clase de valores, pero no son del mismo tipo.
Esto es fácil de solucionar:
var ficha1, ficha2: record
nombre: string;
direccion: string;
edad: integer;
observaciones: string
end;
begin
...
Si las definimos a la vez, SI QUE SON DEL MISMO TIPO. Pero surge un problema del que os iréis dando cuenta a partir del próximo día, que empezaremos a crear funciones y procedimientos. ¿Qué ocurre si queremos usar en alguna parte del programa otras variables que también sean de ese tipo? ¿Las definimos también a la vez? En muchas ocasiones no será posible.
Así que tiene que haber una forma de indicar que todo eso que sigue a la palabra "record" es un tipo al que nosotros queremos acceder con la misma comodidad que si fuese "integer" o "boolean", queremos definir un tipo, no simplemente declararlo, como estábamos haciendo.
Pues es sencillo:
type NombreDeTipo = DeclaracionDeTipo;
o en nuestro caso
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Asignación correcta }
{ de tipos }
{ TIPOS2.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Free Pascal 2.2.0w }
{ - Turbo Pascal 7.0 }
{ - Turbo Pascal 5.0 }
{ - Surpas 1.00 }
{ - Tmt Pascal Lt 1.20 }
{--------------------------}
program PruebaTipos2;
type TipoFicha = record
nombre: string[20];
direccion: string[50];
edad: integer;
observaciones: string[70]
end;
var ficha1, ficha2: TipoFicha;
begin
ficha1.nombre := 'Pepe';
ficha1.direccion := 'Su casa';
ficha1.edad := 65;
ficha1.observaciones := 'El mayor de mis amigos... ;-) ';
ficha2 := ficha1;
writeln( ficha2.nombre );
end.
Ahora sí que podremos asignar valores entre variables que hayamos definido en distintas partes del programa, podremos usar esos tipos para crear ficheros (eso lo veremos en el tema 11), etc, etc, etc...
Ejercicio propuesto: Crear un tipo de datos llamado "punto", que sea un registro formado por dos componentes, X e Y, números reales. Pedir al usuario el valor de X e Y para dos puntos distintos y calcular la distancia entre esos dos puntos.
Vamos a juntar todo lo que hemos visto en una "agenda" que permita introducir datos de nuestros amigos, mostrarlos, buscar entre ellos...
Usará comprobación de condiciones sencilla (con "if", para ver si hay datos), múltiple (con "case", para el menú"), "arrays" de "records", bloques repetitivos ("repeat..until" para el bucle principal, "for" para recorrer el array"), declaración de tipos y de constantes...
Haremos ligeras mejoras en apartados posteriores, para incorporarle algunas de las posibilidades que vayamos viendo.
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Ejemplo de "Agenda": }
{ Permite añadir datos, }
{ mostrar, buscar. }
{ AGENDA1.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Free Pascal 2.4.0 }
{--------------------------}
program Agenda1;
type
tipoPersona = record
nombre: string;
email: string;
anyoNacimiento: integer;
end;
const
capacidad = 1000;
var
gente: array[1..capacidad] of tipoPersona; { Los datos }
cantidad: integer; { Cantidad de datos existentes }
opcion: integer; { Opción escogida }
i: integer; { Para bucles for }
textoBuscar: string; { Para búsquedas }
encontrado: boolean; { Idem }
{Cuerpo del programa principal}
begin
cantidad := 0;
repeat
WriteLn('Agenda');
WriteLn;
WriteLn('1- Añadir una nueva persona');
WriteLn('2- Ver nombres de todos');
WriteLn('3- Buscar una persona');
WriteLn('0- Salir');
Write('Escoja una opción: ');
ReadLn(opcion);
WriteLn;
case opcion of
1: { Añadir datos de una persona }
if (cantidad < capacidad) then
begin
inc(cantidad);
WriteLn('Introduciendo la persona ', cantidad);
Write('Introduzca el nombre: ');
ReadLn(gente[cantidad].nombre);
Write('Introduzca el correo electrónico: ');
ReadLn(gente[cantidad].email);
Write('Introduzca el año de nacimiento: ');
ReadLn(gente[cantidad].anyoNacimiento);
WriteLn;
end
else
WriteLn('Base de datos llena');
2: { Ver nombres de todos }
begin
if cantidad = 0 then
WriteLn('No hay datos')
else
for i := 1 to cantidad do
WriteLn(i, ' ', gente[i].nombre);
WriteLn;
end;
3: { Buscar una persona }
begin
Write('¿Qué texto busca? ');
ReadLn( textoBuscar );
encontrado := false;
for i := 1 to cantidad do
if pos (textoBuscar, gente[i].nombre) > 0 then
begin
encontrado := true;
WriteLn( i,' - Nombre: ', gente[i].nombre,
', Email: ', gente[i].email,
', Nacido en: ', gente[i].anyoNacimiento);
end;
if not encontrado then
WriteLn('No se ha encontrado.');
WriteLn;
end;
0: { Salir de la aplicación }
begin
WriteLn;
WriteLn('Saliendo...');
WriteLn;
end;
else
begin
WriteLn;
WriteLn('Opción incorrecta!');
WriteLn;
end;
end; { Fin de "case" }
until opcion = 0;
end.