Cheatsheet Pascal
Linguagem estruturada clássica para ensino e desenvolvimento (Free Pascal/Delphi)
Pascal
Básico e Estrutura
Estructura del programa
program MiPrograma;
uses SysUtils;
var
nombre: string;
begin
WriteLn('¡Hola Mundo!');
Write('Nombre: ');
ReadLn(nombre);
WriteLn('Hola, ', nombre);
end.Un programa Pascal comienza con program, sigue con uses (bibliotecas), var (variables) y el bloque begin...end. (con punto final).
Operadores aritméticos
var a, b: integer; r: real; begin a := 10; b := 3; WriteLn(a + b); // 13 suma WriteLn(a - b); // 7 resta WriteLn(a * b); // 30 multiplicación WriteLn(a div b); // 3 división entera WriteLn(a mod b); // 1 resto r := a / b; // 3.33 división real end.
div es la división entera y mod el resto. El operador / devuelve siempre real, incluso con operandos enteros.
Operador in (conjunto)
var
x: integer;
c: char;
begin
x := 5;
if x in [1..10] then
WriteLn('entre 1 y 10');
c := 'a';
if c in ['a', 'e', 'i', 'o', 'u'] then
WriteLn('vocal');
end.El operador in verifica pertenencia a un conjunto. [1..10] es un intervalo y [...] una lista de valores. Muy usado en validaciones.
Tipo enumerado simple
type
TDia = (Lun, Mar, Mie, Jue, Vie, Sab, Dom);
var
d: TDia;
begin
d := Lun;
if d = Lun then
WriteLn('Inicio de la semana');
end.Un tipo enumerado lista valores fijos entre paréntesis. Hace el código más legible y seguro que usar enteros sueltos.
Tipos de datos
var i: integer; // entero (32-bit) b: byte; // 0..255 r: real; // número real c: char; // 1 carácter s: string; // string dinámica ok: boolean; // true/false d: double; // precisión doble n: int64; // entero 64-bit
Pascal es fuertemente tipado: cada variable tiene un tipo fijo. integer e int64 para enteros, real/double para decimales, boolean para lógico.
Operadores de comparación
var x: integer; begin x := 5; WriteLn(x = 5); // true igual WriteLn(x <> 3); // true diferente WriteLn(x > 3); // true mayor WriteLn(x <= 5); // true menor o igual end.
La igualdad es = (un solo igual) y la diferencia es <>. Los operadores >, <, >= y <= comparan orden.
Comentarios
// comentario de una línea
{ comentario entre
llaves }
(* comentario entre
paréntesis-asterisco *)
begin
WriteLn('Hola'); // inline
end.Pascal acepta tres formas de comentario: // (línea), { } y (* *) (bloque). Los de bloque pueden abarcar varias líneas.
Subintervalos (subrange)
type TNota = 0..20; TVocales = 'a'..'z'; var nota: TNota; begin nota := 15; // nota := 25; // ERROR: fuera del intervalo end.
Un subrange restringe una variable a un intervalo de valores (ej.: 0..20). El compilador puede validar los límites asignados.
Variables y asignación
var x, y, z: integer; nombre: string; begin x := 10; // asignación con := y := x * 2; // 20 nombre := 'Ana'; z := x + y; end.
La asignación usa := (dos puntos e igual), diferente de = que es comparación. Varias variables del mismo tipo se declaran en la misma línea.
Operadores lógicos
var a, b: boolean; begin a := true; b := false; WriteLn(a and b); // false (Y) WriteLn(a or b); // true (O) WriteLn(not a); // false (negación) WriteLn(a xor b); // true (O exclusivo) end.
Los operadores lógicos son con palabras: and (Y), or (O), not (negación) y xor (O exclusivo). Operan sobre boolean.
Escritura formateada
var
n: integer;
r: real;
begin
n := 42;
r := 3.14159;
WriteLn(n:5); // " 42" (ancho 5)
WriteLn(r:8:2); // " 3.14" (2 decimales)
Write('sin ');
WriteLn('salto'); // misma línea
end.WriteLn escribe con salto de línea y Write sin salto. La sintaxis valor:ancho:decimales formatea la salida alineada.
Constantes
const PI = 3.14159; MAX = 100; NOMBRE = 'Pascal'; ACTIVO = true; begin WriteLn(PI * 2); // PI := 3; // ERROR: constante end.
Las constantes se declaran con const y no pueden ser alteradas. El tipo se infiere del valor. Útiles para valores fijos como PI o límites.
Concatenación de strings
var nombre, saludo: string; begin nombre := 'Ana'; saludo := 'Hola, ' + nombre + '!'; WriteLn(saludo); // Hola, Ana! end.
El operador + concatena strings. Para juntar texto con números, convierte primero con IntToStr() o usa WriteLn con comas.
Lectura de datos
var
nombre: string;
edad: integer;
begin
Write('Nombre: ');
ReadLn(nombre);
Write('Edad: ');
ReadLn(edad);
WriteLn('Hola ', nombre, ', ', edad);
end.ReadLn lee una línea del teclado hacia la variable. Write muestra el prompt sin salto de línea antes de la lectura.
Controlo de Fluxo
If / Else
if edad >= 18 then
WriteLn('Adulto')
else if edad >= 12 then
WriteLn('Adolescente')
else
WriteLn('Niño');El if/else evalúa condiciones en orden. No hay paréntesis obligatorios y no se usa punto y coma antes del else.
For (creciente)
var
i: integer;
begin
for i := 1 to 10 do
WriteLn(i);
end.El for con to cuenta de forma creciente. La variable de control debe ser un tipo ordinal (entero, char, enum). No la modifiques dentro del bucle.
Break
var
i: integer;
begin
for i := 1 to 100 do
begin
if i = 50 then
Break; // sale del bucle
WriteLn(i);
end;
end.El Break termina inmediatamente el bucle (for, while o repeat) y continúa después de él. Útil para salir al encontrar un resultado.
If con bloque begin/end
if x > 0 then
begin
y := x * 2;
WriteLn('positivo: ', y);
end
else
begin
y := 0;
WriteLn('no positivo');
end;Para ejecutar varias instrucciones en una rama, agrúpalas con begin...end. Sin el bloque, solo la primera instrucción pertenece al if.
For (decreciente)
var
i: integer;
begin
for i := 10 downto 1 do
WriteLn(i);
// 10, 9, 8, ... 1
end.El for con downto cuenta de forma decreciente. Útil para cuentas regresivas o recorrer arrays del final al inicio.
Continue
var
i: integer;
begin
for i := 1 to 10 do
begin
if i mod 2 = 0 then
Continue; // salta los pares
WriteLn(i); // solo impares
end;
end.El Continue salta a la siguiente iteración del bucle, ignorando el resto del bloque actual. Aquí imprime solo los números impares.
Case
case dia of
1: WriteLn('Lunes');
2: WriteLn('Martes');
3..5: WriteLn('Mitad de semana');
6, 7: WriteLn('Fin de semana');
else
WriteLn('Inválido');
end;El case selecciona por valor. Acepta valores únicos, intervalos (3..5) y listas (6, 7). El else trata los demás casos.
While
var
x: integer;
begin
x := 5;
while x > 0 do
begin
WriteLn(x);
x := x - 1;
end;
end.El while repite mientras la condición sea verdadera. Verifica la condición antes de cada iteración, pudiendo no ejecutar nunca el bloque.
Exit
function Dividir(a, b: integer): integer;
begin
if b = 0 then
begin
WriteLn('División por cero');
Exit; // sale de la función
end;
Result := a div b;
end;El Exit termina inmediatamente la función o procedure actual. En funciones, puede devolver un valor con Exit(valor) (Delphi/FPC moderno).
Case con string
case comando of
'salir': Close;
'ayuda': ShowHelp;
'guardar': Save;
else
WriteLn('Comando desconocido');
end;En Free Pascal y Delphi el case también acepta strings. Cada rama compara con una constante string. Más limpio que varios if.
Repeat / Until
var
x: integer;
begin
x := 0;
repeat
x := x + 1;
WriteLn(x);
until x >= 5;
end.El repeat/until ejecuta el bloque antes de verificar la condición, garantizando al menos una ejecución. Repite hasta que la condición sea verdadera.
Bucles anidados
var
i, j: integer;
begin
for i := 1 to 3 do
for j := 1 to 3 do
WriteLn('i=', i, ' j=', j);
end.Puedes anidar bucles para recorrer matrices o generar combinaciones. Cada nivel usa su propia variable de control (i, j).
Funções e Procedures
Procedure simple
procedure Saludar(nombre: string);
begin
WriteLn('Hola, ', nombre, '!');
end;
begin
Saludar('Ana');
Saludar('Ray');
end.Una procedure es un subprograma que ejecuta acciones sin devolver valor. Se declara antes del begin principal y se llama por el nombre.
Parámetro const
procedure Imprimir(const s: string); begin WriteLn(s); // s := 'x'; // ERROR: no puede modificar end;
El const pasa por referencia pero impide la modificación. Evita la copia de tipos grandes (strings, records) manteniendo la seguridad de lectura.
Parámetros por defecto
procedure Log(msg: string; nivel: integer = 1);
begin
WriteLn('[', nivel, '] ', msg);
end;
begin
Log('error', 3); // [3] error
Log('info'); // [1] info
end.Los parámetros con valor por defecto (ej.: nivel: integer = 1) pueden omitirse en la llamada. Deben ir al final de la lista de parámetros.
Scope de variables
var global: integer; // visible en todo el programa procedure Prueba; var local: integer; // solo visible aquí begin local := 5; global := local; end;
Las variables declaradas arriba son globales; dentro de una rutina son locales. Las variables locales dejan de existir cuando la rutina termina.
Function con retorno
function Sumar(a, b: integer): integer; begin Sumar := a + b; // retorno por el nombre end; begin WriteLn(Sumar(2, 3)); // 5 end.
Una function devuelve un valor, asignado al propio nombre de la función (aquí Sumar := ...). El tipo de retorno va después de :.
Array abierto (open array)
function Suma(const nums: array of integer): integer;
var
i: integer;
begin
Result := 0;
for i := Low(nums) to High(nums) do
Result := Result + nums[i];
end;
begin
WriteLn(Suma([1, 2, 3, 4])); // 10
end.Un array of como parámetro acepta arrays de cualquier tamaño. Low() y High() dan los límites y puedes pasar literales [...].
Declaración forward
procedure B; forward;
procedure A;
begin
B; // llama a B declarada más adelante
end;
procedure B;
begin
WriteLn('B');
end;La directiva forward declara una rutina antes de su implementación, permitiendo referencia mutua entre procedures (ej.: A llama a B y B llama a A).
Result (forma moderna)
function Cuadrado(x: integer): integer; begin Result := x * x; end; function EsPar(n: integer): boolean; begin Result := (n mod 2 = 0); end;
La variable especial Result guarda el valor de retorno de forma más legible. Es la forma preferida en Delphi y Free Pascal moderno.
Recursión
function Factorial(n: integer): int64;
begin
if n <= 1 then
Result := 1
else
Result := n * Factorial(n - 1);
end;
begin
WriteLn(Factorial(5)); // 120
end.Una función recursiva se llama a sí misma. Necesita un caso base (n <= 1) para terminar. Aquí calcula el factorial de n.
Funciones anónimas (Delphi/FPC)
type
TIntFunc = reference to function(x: integer): integer;
var
doble: TIntFunc;
begin
doble := function(x: integer): integer
begin
Result := x * 2;
end;
WriteLn(doble(5)); // 10
end.Las funciones anónimas (lambdas) usan reference to function. Pueden asignarse a variables y pasarse como argumentos, como en otros lenguajes modernos.
Parámetro por referencia (var)
procedure Incrementar(var x: integer); begin x := x + 1; // altera la variable original end; var n: integer; begin n := 10; Incrementar(n); WriteLn(n); // 11 end.
El var pasa el parámetro por referencia: la función altera la variable original. Sin var, recibe solo una copia (por valor).
Overload de funciones
function Max(a, b: integer): integer; overload; begin if a > b then Result := a else Result := b; end; function Max(a, b: real): real; overload; begin if a > b then Result := a else Result := b; end;
El overload permite varias funciones con el mismo nombre pero parámetros diferentes. El compilador elige la versión correcta por el tipo de los argumentos.
Funciones de orden superior
type TOperacion = function(a, b: integer): integer; function Aplicar(x, y: integer; op: TOperacion): integer; begin Result := op(x, y); end; function Sumar(a, b: integer): integer; begin Result := a + b; end;
Puedes pasar funciones como parámetros usando un tipo función (function(a,b): integer). Esto permite funciones de orden superior reutilizables.
Estruturas de Dados
Array estático
var
arr: array[1..5] of integer;
i: integer;
begin
for i := 1 to 5 do
arr[i] := i * 10;
WriteLn(arr[1]); // 10
WriteLn(arr[5]); // 50
end.Un array estático tiene tamaño fijo definido en compilación (array[1..5]). El índice inicial puede ser cualquier valor ordinal, aquí empieza en 1.
Record con métodos
type
TPunto = record
x, y: integer;
procedure Mover(dx, dy: integer);
end;
procedure TPunto.Mover(dx, dy: integer);
begin
x := x + dx;
y := y + dy;
end;Los records modernos (Delphi/FPC) pueden tener métodos y propiedades. La sintaxis TPunto.Mover implementa el método declarado en el record.
Sets (conjuntos)
type
TVocales = set of char;
var
v: TVocales;
begin
v := ['a', 'e', 'i', 'o', 'u'];
if 'a' in v then
WriteLn('es vocal');
end.Un set guarda valores únicos de un tipo ordinal. El operador in verifica pertenencia. Útil para flags y colecciones pequeñas.
TDictionary
uses Generics.Collections;
var
dict: TDictionary<string, integer>;
begin
dict := TDictionary<string, integer>.Create;
try
dict.Add('Ana', 30);
dict.Add('Ray', 25);
WriteLn(dict['Ana']); // 30
finally
dict.Free;
end;
end.TDictionary<K,V> guarda pares clave-valor. Accede al valor por la clave (ej.: dict["Ana"]). Equivalente a un mapa/hashtable.
Array dinámico
var dyn: array of integer; begin SetLength(dyn, 5); // asigna 5 elementos dyn[0] := 10; // empieza en 0 dyn[4] := 50; WriteLn(Length(dyn)); // 5 WriteLn(Low(dyn)); // 0 WriteLn(High(dyn)); // 4 end.
Un array dinámico (array of) es redimensionable con SetLength. Empieza siempre en el índice 0. Length, Low y High dan los límites.
Variant record
type
TForma = record
case tipo: char of
'c': (radio: real);
'r': (ancho, alto: real);
end;
var
f: TForma;
begin
f.tipo := 'c';
f.radio := 5.0;
end.Un variant record tiene campos que comparten memoria según un campo discriminante (case). Similar a una union en C.
Operaciones de sets
var A, B, C: set of integer; begin A := [1, 2, 3]; B := [2, 3, 4]; C := A + B; // unión [1,2,3,4] C := A - B; // diferencia [1] C := A * B; // intersección [2,3] end.
Los sets soportan operaciones matemáticas: + (unión), - (diferencia) y * (intersección). Ideales para lógica de conjuntos.
Constantes array y record
const
Días: array[1..7] of string =
('Lun', 'Mar', 'Mie', 'Jue', 'Vie', 'Sab', 'Dom');
Origen: TPunto = (x: 0; y: 0);
begin
WriteLn(Días[1]); // Lun
end.Puedes crear arrays y records constantes con valores iniciales fijos. Los arrays usan (...) y los records usan (campo: valor; ...).
Array multidimensional
var
matriz: array[1..3, 1..3] of integer;
i, j: integer;
begin
for i := 1 to 3 do
for j := 1 to 3 do
matriz[i, j] := i * j;
WriteLn(matriz[2, 3]); // 6
end.Un array multidimensional usa varios índices separados por coma (array[1..3, 1..3]). Ideal para matrices y cuadrículas bidimensionales.
With (atajo de record)
var
p: TPersona;
begin
with p do
begin
nombre := 'Ana';
edad := 30;
activo := true;
end;
end.El with evita repetir el nombre del record al acceder a varios campos. Dentro del bloque, nombre se refiere a p.nombre. Usar con moderación.
TStringList
uses Classes;
var
lista: TStringList;
begin
lista := TStringList.Create;
try
lista.Add('item1');
lista.Add('item2');
WriteLn(lista.Count); // 2
WriteLn(lista.IndexOf('item1')); // 0
finally
lista.Free;
end;
end.TStringList es una lista dinámica de strings de la RTL. Ofrece Add, IndexOf, Sort y Count. Crea con Create y libera con Free.
Record simple
type
TPersona = record
nombre: string;
edad: integer;
activo: boolean;
end;
var
p: TPersona;
begin
p.nombre := 'Ana';
p.edad := 30;
p.activo := true;
end.Un record agrupa campos de tipos diferentes en una estructura. Se accede a los campos con punto (p.nombre). Es el equivalente a una struct.
Enumerados (enum)
type
TColor = (Rojo, Verde, Azul);
var
c: TColor;
begin
c := Verde;
if c = Verde then
WriteLn('Verde');
WriteLn(Ord(c)); // 1 (posición)
end.Un enumerado define un conjunto ordenado de valores con nombre. Ord() devuelve la posición (empieza en 0). Más legible que enteros.
Genéricos (TList)
uses Generics.Collections;
var
nums: TList<integer>;
begin
nums := TList<integer>.Create;
try
nums.Add(10);
nums.Add(20);
nums.Sort;
WriteLn(nums[0]); // 10
finally
nums.Free;
end;
end.Los genéricos (TList<integer>) crean colecciones tipadas seguras. Generics.Collections trae TList, TDictionary y otras listas dinámicas.
Strings e Conversões
Length y Copy
var s: string; begin s := 'Hola Mundo'; WriteLn(Length(s)); // 10 WriteLn(Copy(s, 1, 4)); // 'Hola' WriteLn(Copy(s, 6, 5)); // 'Mundo' end.
Length() devuelve el número de caracteres. Copy(s, inicio, n) extrae una substring a partir de inicio con n caracteres.
StringReplace
uses SysUtils;
var
s: string;
begin
s := 'ola mundo ola';
s := StringReplace(s, 'ola', 'hola',
[rfReplaceAll, rfIgnoreCase]);
WriteLn(s); // 'hola mundo hola'
end.StringReplace() sustituye texto. rfReplaceAll cambia todas las ocurrencias y rfIgnoreCase ignora mayúsculas/minúsculas.
Format
uses SysUtils;
begin
WriteLn(Format('%d años', [30]));
WriteLn(Format('%.2f', [3.14159])); // 3.14
WriteLn(Format('%s tiene %d', ['Ana', 30]));
WriteLn(Format('%8d', [42])); // alineado
end.Format() construye strings con marcadores: %d (entero), %f (real), %s (string). El .2 define los decimales.
Mayúsculas y minúsculas
uses SysUtils; var s: string; begin s := 'Hola Mundo'; WriteLn(UpperCase(s)); // 'HOLA MUNDO' WriteLn(LowerCase(s)); // 'hola mundo' end.
UpperCase() convierte a mayúsculas y LowerCase() a minúsculas. Están en la unit SysUtils.
Trim
uses SysUtils; var s: string; begin s := ' texto '; WriteLn(Trim(s)); // 'texto' WriteLn(TrimLeft(s)); // 'texto ' WriteLn(TrimRight(s)); // ' texto' end.
Trim() elimina espacios al inicio y al final. TrimLeft() solo a la izquierda y TrimRight() solo a la derecha. Esencial para limpiar input.
Char: Ord y Chr
var
c: char;
n: integer;
begin
n := Ord('A'); // 65 (código ASCII)
c := Chr(65); // 'A'
c := Chr(Ord('a') - 32); // 'A'
WriteLn(Succ('A')); // 'B'
WriteLn(Pred('B')); // 'A'
end.Ord() devuelve el código numérico del carácter y Chr() hace lo inverso. Succ() y Pred() dan el siguiente/anterior.
Pos (buscar)
var
s: string;
p: integer;
begin
s := 'Hola Mundo';
p := Pos('Mundo', s);
WriteLn(p); // 6 (posición)
if Pos('xyz', s) = 0 then
WriteLn('no encontrado');
end.Pos(sub, s) devuelve la posición de la primera ocurrencia (empieza en 1) o 0 si no encuentra. Útil para verificar presencia.
String a número
uses SysUtils;
var
n: integer;
r: real;
begin
n := StrToInt('42'); // 42
r := StrToFloat('3.14'); // 3.14
n := StrToIntDef('abc', 0); // 0 (seguro)
end.StrToInt() y StrToFloat() convierten strings en números y lanzan excepción si son inválidas. StrToIntDef() devuelve un valor por defecto en vez de fallar.
Concat y Length
var a, b, c: string; begin a := 'Hola'; b := 'Mundo'; c := Concat(a, ' ', b); WriteLn(c); // 'Hola Mundo' WriteLn(Length(c)); // 10 end.
Concat() une varias strings en una sola (alternativa a +). Length() devuelve la longitud. Las strings en Pascal son dinámicas.
Delete e Insert
var
s: string;
begin
s := 'Hola Mundo';
Delete(s, 1, 5); // elimina 5 chars
WriteLn(s); // 'Mundo'
Insert('!', s, 6);
WriteLn(s); // 'Mundo!'
end.Delete(s, inicio, n) elimina n caracteres (modifica la string). Insert(txt, s, pos) inserta texto en la posición indicada.
Número a string
uses SysUtils;
var
s: string;
begin
s := IntToStr(42); // '42'
s := FloatToStr(3.14); // '3.14'
s := FloatToStrF(3.14159,
ffFixed, 8, 2); // '3.14'
end.IntToStr() y FloatToStr() convierten números en strings. FloatToStrF() permite controlar el formato y los decimales.
String con comillas (escape)
var s: string; begin s := 'Él dijo ''hola'''; WriteLn(s); // Él dijo 'hola' s := 'Linea1' + #13#10 + 'Linea2'; WriteLn(s); // dos líneas end.
Para incluir una comilla simple dentro de una string, duplícala (''). #13#10 inserta un salto de línea (CR+LF) usando códigos de carácter.
Ponteiros, Units e Exceções
Punteros básicos
var p: ^integer; x: integer; begin x := 42; p := @x; // dirección de x WriteLn(p^); // 42 (dereference) p^ := 100; // cambia x WriteLn(x); // 100 end.
Un puntero (^integer) guarda una dirección. @x obtiene la dirección y p^ accede al valor apuntado (dereference).
Usar una Unit
program Principal; uses MiUnit, SysUtils; begin WriteLn(Sumar(2, 3)); // de MiUnit end.
La cláusula uses importa units para acceder a sus funciones y tipos. Puede aparecer en el programa o en otra unit (interface o implementation).
Excepción personalizada
type
ESaldoInsuficiente = class(Exception)
constructor Create(valor: real);
end;
constructor ESaldoInsuficiente.Create(valor: real);
begin
inherited CreateFmt('Saldo insuficiente: %.2f',
[valor]);
end;Crea clases que heredan de Exception para errores específicos. CreateFmt formatea el mensaje con parámetros, como Format.
Operaciones bitwise
var a, b: integer; begin a := 12; // 1100 b := 10; // 1010 WriteLn(a and b); // 8 (1000) WriteLn(a or b); // 14 (1110) WriteLn(a xor b); // 6 (0110) WriteLn(a shl 1); // 24 (desplazar) end.
Los operadores bit a bit and, or, xor, shl y shr operan sobre los bits del entero. Útiles para flags y máscaras.
Memoria dinámica
var p: ^integer; begin New(p); // asignar memoria p^ := 100; WriteLn(p^); Dispose(p); // liberar memoria p := nil; end.
New() asigna memoria para el tipo apuntado y Dispose() la libera. Define el puntero como nil después para evitar accesos inválidos.
Try / Except
var
x: integer;
begin
try
x := StrToInt('abc');
except
on E: EConvertError do
WriteLn('Número inválido');
on E: Exception do
WriteLn('Error: ', E.Message);
end;
end.try..except captura excepciones. El on E: Tipo trata cada tipo de excepción. E.Message da la descripción del error.
Constantes tipadas
const Umbral: integer = 100; // mutable (FPC) begin Umbral := 200; // permitido WriteLn(Umbral); end.
Las constantes tipadas (nombre: tipo = valor) son en realidad variables estáticas inicializadas: mantienen el valor entre llamadas y pueden cambiarse.
Programa completo (ejemplo)
program Media;
uses SysUtils;
var
notas: array of integer;
i, suma: integer;
begin
SetLength(notas, 3);
suma := 0;
for i := 0 to High(notas) do
begin
notas[i] := Random(20) + 1;
suma := suma + notas[i];
end;
WriteLn('Media: ', suma / Length(notas):0:1);
end.Ejemplo completo: asigna un array dinámico, lo llena con Random, suma y calcula la media. Muestra la estructura típica de un programa Pascal.
GetMem y FreeMem
var ptr: Pointer; begin GetMem(ptr, 1024); // 1024 bytes // usar ptr... FreeMem(ptr); // liberar ptr := nil; end.
GetMem() asigna un bloque de bytes en bruto y FreeMem() lo libera. Más flexible que New para buffers de tamaño variable.
Try / Finally
var
lista: TStringList;
begin
lista := TStringList.Create;
try
lista.Add('item');
WriteLn(lista.Count);
finally
lista.Free; // se ejecuta siempre
end;
end.try..finally garantiza la ejecución del bloque finally incluso con error. Es el patrón para liberar recursos (memoria, ficheros, objetos).
Directivas de compilación
{$IFDEF DEBUG}
WriteLn('Modo debug activo');
{$ENDIF}
{$MODE DELPHI} // modo Delphi (FPC)
{$RANGECHECKS ON} // verifica índices
begin
WriteLn('Hola');
end.Las directivas {$...} controlan la compilación. {$IFDEF} compila condicionalmente, {$MODE} define compatibilidad y {$RANGECHECKS} valida índices.
Estructura de una Unit
unit MiUnit; interface uses SysUtils; function Sumar(a, b: integer): integer; implementation function Sumar(a, b: integer): integer; begin Result := a + b; end; end.
Una unit es un módulo reutilizable. La sección interface declara lo que es público e implementation contiene el código. Se usa con uses.
Raise (lanzar excepción)
procedure Validar(edad: integer);
begin
if edad < 0 then
raise Exception.Create('Edad inválida');
end;raise lanza una excepción manualmente. Exception.Create(msg) crea la excepción con un mensaje. Interrumpe el flujo hasta el except más cercano.
Type aliases
type TNombre = string; TEdad = integer; TMatriz = array of array of real; var nombre: TNombre; m: TMatriz; begin nombre := 'Ana'; end.
El type crea nombres alternativos para tipos existentes, mejorando la legibilidad. TNombre es solo un alias para string.
Entrada/Saída e Ficheiros
Write y WriteLn
begin
Write('Sin salto ');
WriteLn('con salto');
WriteLn('A', 'B', 'C'); // ABC
WriteLn(10, ' ', 20); // 10 20
WriteLn(3.14:6:2); // 3.14
end.Write imprime sin cambiar de línea y WriteLn sí. Aceptan varios argumentos separados por comas y formato :ancho:decimales.
Append (añadir)
var f: TextFile; begin AssignFile(f, 'log.txt'); Append(f); // añadir al final WriteLn(f, 'Nueva entrada'); CloseFile(f); end.
Append abre un fichero existente para añadir al final, sin borrar el contenido anterior. Ideal para ficheros de log.
Verificar existencia
uses SysUtils;
begin
if FileExists('datos.txt') then
WriteLn('existe')
else
WriteLn('no existe');
if DirectoryExists('C:\temp') then
WriteLn('la carpeta existe');
end.FileExists() verifica si un fichero existe y DirectoryExists() si una carpeta existe. Están en la unit SysUtils.
Read y ReadLn
var nombre: string; edad: integer; begin ReadLn(nombre); // lee una línea ReadLn(edad); // lee un entero WriteLn(nombre, ' ', edad); end.
ReadLn lee una línea completa del teclado y la convierte al tipo de la variable. Read lee sin consumir el salto de línea.
Fichero binario (tipado)
type
TRegistro = record
id: integer;
nombre: string[50];
end;
var
f: file of TRegistro;
reg: TRegistro;
begin
AssignFile(f, 'datos.dat');
Rewrite(f);
reg.id := 1;
reg.nombre := 'Ana';
Write(f, reg);
CloseFile(f);
end.Un file of TRegistro guarda registros de tamaño fijo en binario. Write(f, reg) y Read(f, reg) leen/escriben registros completos.
Borrar y renombrar
var f: TextFile; begin AssignFile(f, 'antiguo.txt'); Erase(f); // borra el fichero AssignFile(f, 'nuevo.txt'); Rename(f, 'nuevo2.txt'); // renombra end.
Erase() borra el fichero asociado y Rename() cambia el nombre. La variable debe estar asociada con AssignFile pero no abierta.
Escribir fichero de texto
var f: TextFile; begin AssignFile(f, 'datos.txt'); Rewrite(f); // crear/escribir WriteLn(f, 'Linea 1'); WriteLn(f, 'Linea 2'); CloseFile(f); end.
AssignFile asocia la variable al fichero, Rewrite lo abre para escritura (crea uno nuevo), escribes con WriteLn(f, ...) y cierras con CloseFile.
Leer fichero binario
var
f: file of TRegistro;
reg: TRegistro;
begin
AssignFile(f, 'datos.dat');
Reset(f);
while not EOF(f) do
begin
Read(f, reg);
WriteLn(reg.id, ' ', reg.nombre);
end;
CloseFile(f);
end.La lectura binaria usa Read(f, reg) dentro de while not EOF(f). Cada iteración carga un registro completo de la estructura.
TFileStream
uses Classes, SysUtils;
var
fs: TFileStream;
s: string;
begin
fs := TFileStream.Create('datos.bin',
fmCreate);
try
s := 'Hola';
fs.WriteBuffer(s[1], Length(s));
finally
fs.Free;
end;
end.TFileStream da control total sobre la lectura/escritura binaria. fmCreate crea el fichero y WriteBuffer escribe bytes en bruto.
Leer fichero de texto
var
f: TextFile;
linea: string;
begin
AssignFile(f, 'datos.txt');
Reset(f); // abrir para lectura
while not EOF(f) do
begin
ReadLn(f, linea);
WriteLn(linea);
end;
CloseFile(f);
end.Reset abre el fichero para lectura. El bucle while not EOF(f) recorre hasta el final, leyendo cada línea con ReadLn(f, linea).
Tamaño y posición (binario)
var f: file of TRegistro; begin AssignFile(f, 'datos.dat'); Reset(f); WriteLn(FileSize(f)); // nº de registros Seek(f, 2); // ir al registro 2 WriteLn(FilePos(f)); // posición actual CloseFile(f); end.
FileSize() devuelve el número de registros y FilePos() la posición actual. Seek(f, n) mueve al registro n (acceso aleatorio).
Parámetros de línea de comandos
var
i: integer;
begin
WriteLn('Nº args: ', ParamCount);
for i := 1 to ParamCount do
WriteLn(ParamStr(i));
end.ParamCount devuelve el número de argumentos de la línea de comandos y ParamStr(i) cada argumento. ParamStr(0) es el nombre del ejecutable.
Classes e OOP
Clase básica
type
TPersona = class
Nombre: string;
Edad: integer;
procedure Presentar;
end;
procedure TPersona.Presentar;
begin
WriteLn(Nombre, ', ', Edad);
end;Una clase se declara con class y contiene campos y métodos. Los métodos se implementan fuera con TPersona.Presentar. Se instancia con Create.
Private y public
type
TCuenta = class
private
FSaldo: real; // oculto del exterior
public
procedure Depositar(v: real);
function Saldo: real;
end;private restringe el acceso al interior de la clase (encapsulamiento). public hace los miembros accesibles desde fuera. Los campos privados usan el prefijo F.
inherited
procedure TPerro.Hablar;
begin
inherited Hablar; // llama al de la superclase
WriteLn('... y mueve la cola');
end;inherited llama a la versión del método en la superclase. Útil para extender el comportamiento en vez de sustituirlo por completo.
Polimorfismo
var
formas: array of TForma;
f: TForma;
begin
SetLength(formas, 2);
formas[0] := TCirculo.Create;
formas[1] := TCuadrado.Create;
for f in formas do
WriteLn(f.Area); // llama al correcto
end.Con métodos virtual/override, la misma llamada (f.Area) ejecuta la implementación correcta según el tipo real del objeto en runtime.
Crear y liberar objeto
var
p: TPersona;
begin
p := TPersona.Create;
try
p.Nombre := 'Ana';
p.Edad := 30;
p.Presentar;
finally
p.Free; // liberar memoria
end;
end.Los objetos se crean con Create y deben liberarse con Free. El try..finally garantiza la liberación incluso si ocurre un error.
Properties
type
TPersona = class
private
FNombre: string;
public
property Nombre: string read FNombre write FNombre;
property SoloLectura: string read FNombre;
end;Una property expone campos con read y write, controlando el acceso. Puede enlazarse a métodos getter/setter para validación.
is y as
var
a: TAnimal;
begin
a := TPerro.Create;
if a is TPerro then
WriteLn('es un perro');
(a as TPerro).Ladrar;
a.Free;
end.is verifica el tipo en runtime y as hace un cast seguro (lanza una excepción si falla). Esenciales para trabajar con polimorfismo.
for in (colecciones)
var
lista: TList<integer>;
n: integer;
begin
lista := TList<integer>.Create;
lista.AddRange([1, 2, 3]);
for n in lista do
WriteLn(n);
lista.Free;
end.El for in recorre colecciones y arrays de forma limpia, sin índices. Funciona con arrays dinámicos, TList y otros enumerables.
Constructor
type
TPersona = class
Nombre: string;
constructor Create(n: string);
end;
constructor TPersona.Create(n: string);
begin
inherited Create;
Nombre := n;
end;
var p: TPersona;
begin
p := TPersona.Create('Ana');
end.El constructor inicializa el objeto en la creación. inherited Create llama al constructor de la clase base. Permite pasar parámetros iniciales.
Herencia
type
TAnimal = class
procedure Hablar; virtual;
end;
TPerro = class(TAnimal)
procedure Hablar; override;
end;
procedure TPerro.Hablar;
begin
WriteLn('¡Guau guau!');
end;La herencia usa class(TAnimal). virtual marca el método como redefinible y override lo reimplementa en la subclase (polimorfismo).
Clase estática y Self
type
TContador = class
class var Total: integer;
class procedure Incrementar;
end;
class procedure TContador.Incrementar;
begin
Total := Total + 1;
end;Los miembros class pertenecen a la clase y no a la instancia (compartidos). Self se refiere al objeto actual, como this en otros lenguajes.
Destructor
type
TRecurso = class
destructor Destroy; override;
end;
destructor TRecurso.Destroy;
begin
WriteLn('Liberando recursos');
inherited Destroy;
end;El destructor Destroy (con override) se ejecuta al liberar el objeto. Se usa para limpiar recursos. Se llama con Free, que verifica nil.
Métodos abstract
type
TForma = class
function Area: real; virtual; abstract;
end;
TCirculo = class(TForma)
Radio: real;
function Area: real; override;
end;
function TCirculo.Area: real;
begin
Result := 3.14159 * Radio * Radio;
end;Un método abstract se declara sin implementación y obliga a las subclases a definirlo. Convierte la clase base en un contrato (clase abstracta).
Interfaces
type
IGuardable = interface
['{GUID-AQUI}']
procedure Guardar;
end;
TDocumento = class(TInterfacedObject, IGuardable)
procedure Guardar;
end;Una interface define un contrato sin implementación. La clase hereda de TInterfacedObject e implementa los métodos. Soporta conteo de referencias.