AnteriorPosterior

Tema 9: Otros tipos de datos.

  Curso: Curso de Pascal, por Nacho Cabanes

Tema 9: Otros tipos de datos.

Comenzamos a ver los tipos de datos que podíamos manejar en el tema 2. En aquel momento tratamos los siguientes:

  • Byte. Entero, 0 a 255. Ocupa 1 byte de memoria.
  • Integer. Entero con signo, -32768 a 32767. Ocupa 2 bytes.
  • Char. Carácter, 1 byte.
  • String[n]. Cadena de n caracteres (hasta 255). Ocupa n+1 bytes.
  • Real. Real con signo. De 2.9e-39 a 1.7e38, 11 o 12 dígitos significativos, ocupa 6 bytes.
  • Boolean. TRUE o FALSE.
  • Array. Vectores o matrices.
  • Record. Con campos de distinto tamaño.


Pues esta vez vamos a ampliar con otros tipos de datos. :

  • Enteros.
  • Correspondencia byte-char.
  • Reales del 8087.
  • Tipos enumerados.
  • Más detalles sobre Strings.
  • Registros variantes.
  • Conjuntos.


Vamos allá:




Comencemos por los demás tipos de números enteros. Estos son:

  • Shortint. Entero con signo, de -128 a 127, ocupa 1 byte.
  • Word. Entero sin signo, de 0 a 65535. Ocupa 2 bytes.
  • Longint. Con signo, de -2147483648..2147483647. Ocupa 4 bytes.


Estos tipos, junto con "char" (y "boolean" y otros para los que no vamos a entrar en tanto detalle) son tipos ordinales, existe una relación de orden entre ellos y cada elemento está precedido y seguido por otro que podemos conocer (cosa que no ocurre en los reales). Para ellos están definidas las funciones:

  • pred - Predecesor de un elemento : pred(3) = 2
  • succ - Sucesor: succ(3) = 4
  • ord - Número de orden (posición) dentro de todo el conjunto.


El uso más habitual de "ord" es para convertir de "char" a "byte". Los caracteres se almacenan en memoria de tal forma que a cada uno se le asigna un número entre 0 y 255, su "código ASCII" (ej: A=65, a=96, 0=48, _=178). La forma de hallar el código ASCII de una letra es simplemente ord(letra), como ord('_').

El paso contrario, la letra que corresponde a cierto número, se hace con la función "chr". Así, podemos escribir los caracteres "imprimibles" de nuestro ordenador sabiendo que van del 32 al 255 (los que están por debajo de 32 suelen ser caracteres de control, que en muchos casos no se podrán mostrar en pantalla; en algunos sistemas ocurre lo mismo con los caracteres que están por encima del 127):


var
  bucle: byte;
begin
  for bucle := 32 to 255 do
    write( chr(bucle) );
end.



Si tenemos coprocesador matemático, podemos utilizar también los siguientes tipos de números reales del 8087:

Nombre Rango Dígitos Bytes
single 1.5e-45 a 3.4e38 7-8 4
double 5.0e-324 a 1.7e308 15-16 8
extended 3.4e-4932 a 1.1e4932 19-20 10
comp -9.2e18 a 9.2e18 19-20 8

El tipo "comp" es un entero (no real, sin decimales) de 8 bytes, que sólo tenemos disponible si usamos el coprocesador.


Nosotros podemos crear nuestros propios tipos de datos enumerados:


type DiasSemana = (Lunes, Martes, Miercoles, Jueves, Viernes,
  Sabado, Domingo);

Declaramos las variables igual que hacíamos con cualquier otro tipo:


var dia: DiasSemana;

Y las empleamos como siempre: podemos darles un valor, utilizarlas en comparaciones, etc.


begin
  dia := Lunes;
  [...]

  if dia = Viernes then
    writeln( 'Se acerca el fin de semana!' );
  [...]

Los tipos enumerados también son tipos ordinales, por lo que podemos usar pred, succ y ord con ellos. Así, con los datos del ejemplo anterior tendríamos

pred(Martes) = Lunes, succ(Martes) = Miercoles, ord(Martes) = 1

(el número de orden de Martes es 1, porque es el segundo elemento, y se empieza a numerar en cero).


Nota: también podemos definir los valores que puede tomar una variable, indicándolo en forma de subrango, al igual que se hace con los índices de un array:


var
  dia: 1..31;


Volvamos a los strings. Habíamos visto que se declaraban de la forma "string[n]" y ocupaban n+1 bytes (si escribimos sólo "string", es válido en las últimas versiones de Pascal y equivale a "string[255]"). ¿Por qué n+1 bytes? Pues porque también se guarda la longitud de la cadena.

Ya que estamos, vamos a ver cómo acceder a caracteres individuales de una cadena. Nada más fácil. A lo mejor a alguien la definición anterior, indicando el tamaño entre corchetes le recuerda a la de un Array. Así es. De hecho, la definición original en Pascal del tipo String[x] era "Packed Array[1..x] of char" ("packed" era para que el compilador intentase "empaquetar" el array, de modo que ocupase menos; esto no es necesario en Turbo Pascal). Así, con nombre[1] accederíamos a la primera letra del nombre, con nombre[2] a la segunda, y así sucesivamente.

Una última curiosidad: habíamos dicho que se guarda también la longitud de la cadena. ¿Donde? Pues en la posición 0. Va programita de ejemplo:

 {--------------------------}
 {  Ejemplo en Pascal:      }
 {                          }
 {    Longitud de una       }
 {    cadena; posiciones    }
 {    POSCAD.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         }
 {--------------------------}

 program PosCad;

 var
   linea: string [20];    (* Cadena inicial: limitada a 20 letras *)
   pos: byte;                     (* Posición que estamos mirando *)

 begin
   writeln( 'Introduce una línea de texto...' );
   readln( linea );
   for pos := 1 to ord(linea[0]) do
     writeln(' La letra número ', pos,' es una ', linea[pos]);
 end. 

Comentarios:

  • "linea[0]" da la longitud de la cadena, pero es un carácter, luego debemos convertirlo a byte con "ord".
  • Entonces, recorremos la cadena desde la primera letra hasta la última.
  • Si tecleamos más de 20 letras, las restantes se desprecian.



Tema 9.2: Otros tipos de datos (2).

También habíamos visto ya los registros (records), pero con unos campos fijos. No tiene por qué ser necesariamente así. Tenemos a nuestra disposición los registros variantes, en los que con un "case" podemos elegir unos campos u otros. La mejor forma de entenderlos es con un ejemplo.

 {--------------------------}
 {  Ejemplo en Pascal:      }
 {                          }
 {    Registros variantes   }
 {    REGVAR.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.01  }
 {--------------------------}

 program RegistrosVariantes;

 type
   TipoDato  = (Num, Fech, Str);
   Fecha   = record
      D, M, A: Byte;
   end;
   Ficha = record
     Nombre: string[20];           (* Campo fijo *)
     case Tipo: TipoDato of        (* Campos variantes *)
       Num:  (N: real);                (* Si es un número: campo N *)
       Fech: (F: Fecha);               (* Si es fecha: campo F *)
       Str:  (S: string[30]);          (* Si es string: campo S *)
   end;

 var
   UnDato: Ficha;

 begin
   UnDato.Nombre := 'Nacho';     (* Campo normal de un record *)
   UnDato.Tipo   := Num;         (* Vamos a almacenar un número *)
   UnDato.N      := 3.5;         (* que vale 3.5 *)
   Writeln('Ahora el tipo es numérico, y el nombre es ',
     UnDato.Nombre, '.');
   Writeln('El campo N vale: ', UnDato.N);
   UnDato.Nombre := 'Nacho2';    (* Campo normal *)
   UnDato.Tipo   := Fech;        (* Ahora almacenamos una fecha *)
   UnDato.F.D    := 7;           (* Día: 7 *)
   UnDato.F.M    := 11;          (* Mes: 11 *)
   UnDato.F.A    := 93;          (* Año: 93 *)
   Writeln('Ahora el tipo es Fecha, y el nombre es ',
     UnDato.Nombre, '.');
   Writeln('El campo F.D (día) vale: ', UnDato.F.D);
   UnDato.Nombre := 'Nacho3';     (* Campo normal *)
   UnDato.Tipo   := Str;          (* Ahora un string *)
   UnDato.S      := 'Nada';       (* el texto "Nada" *)
   Writeln('Ahora el tipo es string, y el nombre es ',
     UnDato.Nombre, '.');
   Writeln('El campo S vale: ', UnDato.S);
 end. 


Tema 9.3: Otros tipos de datos (3).

Finalmente, tenemos los conjuntos (sets). Un conjunto está formado por una serie de elementos de un tipo base, que debe ser un ordinal de no más de 256 valores posibles, como un "char", un "byte" o un enumerado.


type
  Letras = set of Char;

type DiasSemana = (Lunes, Martes, Miercoles, Jueves, Viernes,
  Sabado, Domingo);

Dias = set of DiasSemana; 

Para construir un "set" utilizaremos los corchetes ([]), y dentro de ellos enumeramos los valores posibles, uno a uno o como rangos de valores separados por ".." :


var
  LetrasValidas : Letras;
  Fiesta : Dias;
begin
  LetrasValidas = ['a'..'z', 'A'..'z', '0'..'9'];
  Fiesta = [ Sabado, Domingo ];
end.

Un conjunto vacío se define con [ ].

Las operaciones que tenemos definidas sobre los conjuntos son:

Operac Nombre
+ Unión
- Diferencia
* Intersección
in Pertenencia

Así, podríamos hacer cosas como


VocalesPermitidas := LetrasValidas * Vocales;

if DiaActual in Fiesta then
  writeln( 'No me diras que estas trabajando... ;-D ' );

En el primer ejemplo hemos dicho que el conjunto de vocales permitidas (que deberíamos haber declarado) es la intersección de las vocales (que también debíamos haber declarado) y las letras válidas.

En el segundo, hemos comprobado si la fecha actual (que sería de tipo DiasSemana) pertenece al conjunto de los días de fiesta.

Vamos a ver un ejemplito sencillo "que funcione":

 {--------------------------} 
 {  Ejemplo en Pascal:      } 
 {                          } 
 {    Conjuntos (sets)      } 
 {    EJSET.PAS             } 
 {                          } 
 {  Este fuente procede de  } 
 {  CUPAS, curso de Pascal  } 
 {  por Nacho Cabanes       } 
 {                          } 
 {  Comprobado con:         } 
 {    - FreePascal 2.0.2    } 
 {--------------------------} 

 program EjSet; 

 var 
   minusculasValidas, 
     mayusculasValidas, 
     letrasValidas: set of char; 
   letra: char; 

 begin 
   minusculasValidas := ['a', 'b', 'c', 'd']; 
   mayusculasValidas := ['F', 'H', 'K', 'M']; 
   letrasValidas := minusculasValidas
     + mayusculasValidas; 
   repeat 
     writeln( 'Introduce una letra...' ); 
     readln( letra ); 
     if not (letra in letrasValidas) then 
       writeln('No aceptada!'); 
   until letra in letrasValidas; 
 end.

Pues eso es todo por hoy. Si es denso (eso creo), pues a releerlo un par de veces y a experimentar...

No propongo ejercicios porque es un tema árido y habrá gente que no use casi nada de esto. Quien le vea la utilidad, que se los proponga él sólo según la aplicación que les quiera dar. De todas formas, a medida que vayamos haciendo programas más grandes, iremos usando más de una de las cosas que hemos visto hoy.

Actualizado el: 15-04-2006 17:40

AnteriorPosterior