DevTools

Cheatsheet Pascal

Linguagem estruturada clássica para ensino e desenvolvimento (Free Pascal/Delphi)

Voltar às linguagens
Pascal
105 cards encontrados
Categorias:
Versões:

Básico e Estrutura


14 cards
Estrutura do programa
program MeuPrograma;

uses SysUtils;

var
  nome: string;

begin
  WriteLn('Olá Mundo!');
  Write('Nome: ');
  ReadLn(nome);
  WriteLn('Olá, ', nome);
end.

Um programa Pascal começa com program, segue com uses (bibliotecas), var (variáveis) e o bloco begin...end. (com ponto final).

Operadores aritméticos
var
  a, b: integer;
  r: real;

begin
  a := 10; b := 3;
  WriteLn(a + b);   // 13 soma
  WriteLn(a - b);   // 7  subtração
  WriteLn(a * b);   // 30 multiplicação
  WriteLn(a div b); // 3  divisão inteira
  WriteLn(a mod b); // 1  resto
  r := a / b;       // 3.33 divisão real
end.

div é a divisão inteira e mod o resto. O operador / devolve sempre real, mesmo com operandos inteiros.

Operador in (conjunto)
var
  x: integer;
  c: char;

begin
  x := 5;
  if x in [1..10] then
    WriteLn('entre 1 e 10');

  c := 'a';
  if c in ['a', 'e', 'i', 'o', 'u'] then
    WriteLn('vogal');
end.

O operador in verifica pertença a um conjunto. [1..10] é um intervalo e [...] uma lista de valores. Muito usado em validações.

Tipo enumerado simples
type
  TDia = (Seg, Ter, Qua, Qui, Sex, Sab, Dom);

var
  d: TDia;

begin
  d := Seg;
  if d = Seg then
    WriteLn('Início da semana');
end.

Um tipo enumerado lista valores fixos entre parênteses. Torna o código mais legível e seguro do que usar inteiros soltos.

Tipos de dados
var
  i: integer;    // inteiro (32-bit)
  b: byte;       // 0..255
  r: real;       // número real
  c: char;       // 1 caractere
  s: string;     // string dinâmica
  ok: boolean;   // true/false
  d: double;     // precisão dupla
  n: int64;      // inteiro 64-bit

O Pascal é fortemente tipado: cada variável tem um tipo fixo. integer e int64 para inteiros, real/double para decimais, boolean para lógico.

Operadores de comparação
var
  x: integer;

begin
  x := 5;
  WriteLn(x = 5);   // true  igual
  WriteLn(x <> 3);  // true  diferente
  WriteLn(x > 3);   // true  maior
  WriteLn(x <= 5);  // true  menor ou igual
end.

A igualdade é = (um só igual) e a diferença é <>. Os operadores >, <, >= e <= comparam ordem.

Comentários
// comentário de uma linha

{ comentário entre
  chavetas }

(* comentário entre
   parênteses-asterisco *)

begin
  WriteLn('Olá'); // inline
end.

O Pascal aceita três formas de comentário: // (linha), { } e (* *) (bloco). Os de bloco podem span várias linhas.

Subintervalos (subrange)
type
  TNota = 0..20;
  TVogais = 'a'..'z';

var
  nota: TNota;

begin
  nota := 15;
  // nota := 25;  // ERRO: fora do intervalo
end.

Um subrange restringe uma variável a um intervalo de valores (ex.: 0..20). O compilador pode validar os limites atribuídos.

Variáveis e atribuição
var
  x, y, z: integer;
  nome: string;

begin
  x := 10;       // atribuição com :=
  y := x * 2;    // 20
  nome := 'Ana';
  z := x + y;
end.

A atribuição usa := (dois pontos e igual), diferente de = que é comparação. Várias variáveis do mesmo tipo declaram-se na mesma linha.

Operadores lógicos
var
  a, b: boolean;

begin
  a := true; b := false;
  WriteLn(a and b);  // false (E)
  WriteLn(a or b);   // true  (OU)
  WriteLn(not a);    // false (negação)
  WriteLn(a xor b);  // true  (OU exclusivo)
end.

Os operadores lógicos são por extenso: and (E), or (OU), not (negação) e xor (OU exclusivo). Operam sobre boolean.

Escrita formatada
var
  n: integer;
  r: real;

begin
  n := 42;
  r := 3.14159;
  WriteLn(n:5);     // "   42" (largura 5)
  WriteLn(r:8:2);   // "    3.14" (2 casas)
  Write('sem ');
  WriteLn('quebra'); // mesma linha
end.

WriteLn escreve com quebra de linha e Write sem quebra. A sintaxe valor:largura:casas formata a saída alinhada.

Constantes
const
  PI = 3.14159;
  MAX = 100;
  NOME = 'Pascal';
  ATIVO = true;

begin
  WriteLn(PI * 2);
  // PI := 3;  // ERRO: constante
end.

Constantes declaram-se com const e não podem ser alteradas. O tipo é inferido do valor. Úteis para valores fixos como PI ou limites.

Concatenação de strings
var
  nome, saudacao: string;

begin
  nome := 'Ana';
  saudacao := 'Olá, ' + nome + '!';
  WriteLn(saudacao);  // Olá, Ana!
end.

O operador + concatena strings. Para juntar texto com números, converte primeiro com IntToStr() ou usa WriteLn com vírgulas.

Leitura de dados
var
  nome: string;
  idade: integer;

begin
  Write('Nome: ');
  ReadLn(nome);

  Write('Idade: ');
  ReadLn(idade);

  WriteLn('Olá ', nome, ', ', idade);
end.

ReadLn lê uma linha do teclado para a variável. Write mostra o prompt sem quebra de linha antes da leitura.

Controlo de Fluxo


12 cards
If / Else
if idade >= 18 then
  WriteLn('Adulto')
else if idade >= 12 then
  WriteLn('Adolescente')
else
  WriteLn('Criança');

O if/else avalia condições em ordem. Não há parênteses obrigatórios e não se usa ponto e vírgula antes do else.

For (crescente)
var
  i: integer;

begin
  for i := 1 to 10 do
    WriteLn(i);
end.

O for com to conta de forma crescente. A variável de controlo deve ser um tipo ordinal (inteiro, char, enum). Não a modifiques dentro do ciclo.

Break
var
  i: integer;

begin
  for i := 1 to 100 do
  begin
    if i = 50 then
      Break;  // sai do ciclo
    WriteLn(i);
  end;
end.

O Break termina imediatamente o ciclo (for, while ou repeat) e continua após ele. Útil para sair ao encontrar um resultado.

If com bloco begin/end
if x > 0 then
begin
  y := x * 2;
  WriteLn('positivo: ', y);
end
else
begin
  y := 0;
  WriteLn('não positivo');
end;

Para executar várias instruções num ramo, agrupa-as com begin...end. Sem o bloco, só a primeira instrução pertence ao if.

For (decrescente)
var
  i: integer;

begin
  for i := 10 downto 1 do
    WriteLn(i);
  // 10, 9, 8, ... 1
end.

O for com downto conta de forma decrescente. Útil para contagens regressivas ou percorrer arrays do fim para o início.

Continue
var
  i: integer;

begin
  for i := 1 to 10 do
  begin
    if i mod 2 = 0 then
      Continue;  // salta os pares
    WriteLn(i);  // só ímpares
  end;
end.

O Continue salta para a próxima iteração do ciclo, ignorando o resto do bloco atual. Aqui imprime apenas os números ímpares.

Case
case dia of
  1: WriteLn('Segunda');
  2: WriteLn('Terça');
  3..5: WriteLn('Meio da semana');
  6, 7: WriteLn('Fim de semana');
else
  WriteLn('Inválido');
end;

O case seleciona por valor. Aceita valores únicos, intervalos (3..5) e listas (6, 7). O else trata os restantes casos.

While
var
  x: integer;

begin
  x := 5;
  while x > 0 do
  begin
    WriteLn(x);
    x := x - 1;
  end;
end.

O while repete enquanto a condição for verdadeira. Verifica a condição antes de cada iteração, podendo nunca executar o bloco.

Exit
function Dividir(a, b: integer): integer;
begin
  if b = 0 then
  begin
    WriteLn('Divisão por zero');
    Exit;  // sai da função
  end;
  Result := a div b;
end;

O Exit termina imediatamente a função ou procedure atual. Em funções, pode devolver um valor com Exit(valor) (Delphi/FPC moderno).

Case com string
case comando of
  'sair':  Close;
  'ajuda': ShowHelp;
  'gravar': Save;
else
  WriteLn('Comando desconhecido');
end;

No Free Pascal e Delphi o case também aceita strings. Cada ramo compara com uma constante string. Mais limpo do que vários if.

Repeat / Until
var
  x: integer;

begin
  x := 0;
  repeat
    x := x + 1;
    WriteLn(x);
  until x >= 5;
end.

O repeat/until executa o bloco antes de verificar a condição, garantindo pelo menos uma execução. Repete até a condição ser verdadeira.

Ciclos aninhados
var
  i, j: integer;

begin
  for i := 1 to 3 do
    for j := 1 to 3 do
      WriteLn('i=', i, ' j=', j);
end.

Podes aninhar ciclos para percorrer matrizes ou gerar combinações. Cada nível usa a sua própria variável de controlo (i, j).

Funções e Procedures


13 cards
Procedure simples
procedure Saudar(nome: string);
begin
  WriteLn('Olá, ', nome, '!');
end;

begin
  Saudar('Ana');
  Saudar('Rui');
end.

Uma procedure é um subprograma que executa ações sem devolver valor. Declara-se antes do begin principal e chama-se pelo nome.

Parâmetro const
procedure Imprimir(const s: string);
begin
  WriteLn(s);
  // s := 'x';  // ERRO: não pode modificar
end;

O const passa por referência mas impede modificação. Evita a cópia de tipos grandes (strings, records) mantendo a segurança de leitura.

Parâmetros por defeito
procedure Log(msg: string; nivel: integer = 1);
begin
  WriteLn('[', nivel, '] ', msg);
end;

begin
  Log('erro', 3);  // [3] erro
  Log('info');     // [1] info
end.

Parâmetros com valor por defeito (ex.: nivel: integer = 1) podem ser omitidos na chamada. Devem vir no fim da lista de parâmetros.

Scope de variáveis
var
  global: integer;  // visível em todo o programa

procedure Teste;
var
  local: integer;  // só visível aqui
begin
  local := 5;
  global := local;
end;

Variáveis declaradas no topo são globais; dentro de uma rotina são locais. Variáveis locais deixam de existir quando a rotina termina.

Function com retorno
function Somar(a, b: integer): integer;
begin
  Somar := a + b;  // retorno pelo nome
end;

begin
  WriteLn(Somar(2, 3));  // 5
end.

Uma function devolve um valor, atribuído ao próprio nome da função (aqui Somar := ...). O tipo de retorno vem após :.

Array aberto (open array)
function Soma(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(Soma([1, 2, 3, 4]));  // 10
end.

Um array of como parâmetro aceita arrays de qualquer tamanho. Low() e High() dão os limites e podes passar literais [...].

Declaração forward
procedure B; forward;

procedure A;
begin
  B;  // chama B declarada à frente
end;

procedure B;
begin
  WriteLn('B');
end;

A diretiva forward declara uma rotina antes da sua implementação, permitindo referência mútua entre procedures (ex.: A chama B e B chama A).

Result (forma moderna)
function Quadrado(x: integer): integer;
begin
  Result := x * x;
end;

function EPar(n: integer): boolean;
begin
  Result := (n mod 2 = 0);
end;

A variável especial Result guarda o valor de retorno de forma mais legível. É a forma preferida no Delphi e Free Pascal moderno.

Recursão
function Fatorial(n: integer): int64;
begin
  if n <= 1 then
    Result := 1
  else
    Result := n * Fatorial(n - 1);
end;

begin
  WriteLn(Fatorial(5));  // 120
end.

Uma função recursiva chama-se a si própria. Precisa de um caso base (n <= 1) para terminar. Aqui calcula o fatorial de n.

Funções anónimas (Delphi/FPC)
type
  TIntFunc = reference to function(x: integer): integer;

var
  dobro: TIntFunc;

begin
  dobro := function(x: integer): integer
  begin
    Result := x * 2;
  end;

  WriteLn(dobro(5));  // 10
end.

Funções anónimas (lambdas) usam reference to function. Podem ser atribuídas a variáveis e passadas como argumentos, como noutras linguagens modernas.

Parâmetro por referência (var)
procedure Incrementar(var x: integer);
begin
  x := x + 1;  // altera a variável original
end;

var
  n: integer;
begin
  n := 10;
  Incrementar(n);
  WriteLn(n);  // 11
end.

O var passa o parâmetro por referência: a função altera a variável original. Sem var, recebe apenas uma cópia (por valor).

Overload de funções
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;

O overload permite várias funções com o mesmo nome mas parâmetros diferentes. O compilador escolhe a versão certa pelo tipo dos argumentos.

Funções de ordem superior
type
  TOperacao = function(a, b: integer): integer;

function Aplicar(x, y: integer; op: TOperacao): integer;
begin
  Result := op(x, y);
end;

function Somar(a, b: integer): integer;
begin
  Result := a + b;
end;

Podes passar funções como parâmetros usando um tipo função (function(a,b): integer). Isto permite funções de ordem superior reutilizáveis.

Estruturas de Dados


14 cards
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.

Um array estático tem tamanho fixo definido em compilação (array[1..5]). O índice inicial pode ser qualquer valor ordinal, aqui começa em 1.

Record com métodos
type
  TPonto = record
    x, y: integer;
    procedure Mover(dx, dy: integer);
  end;

procedure TPonto.Mover(dx, dy: integer);
begin
  x := x + dx;
  y := y + dy;
end;

Records modernos (Delphi/FPC) podem ter métodos e propriedades. A sintaxe TPonto.Mover implementa o método declarado no record.

Sets (conjuntos)
type
  TVogais = set of char;

var
  v: TVogais;

begin
  v := ['a', 'e', 'i', 'o', 'u'];
  if 'a' in v then
    WriteLn('é vogal');
end.

Um set guarda valores únicos de um tipo ordinal. O operador in verifica pertença. Útil para flags e coleções pequenas.

TDictionary
uses Generics.Collections;

var
  dict: TDictionary<string, integer>;
begin
  dict := TDictionary<string, integer>.Create;
  try
    dict.Add('Ana', 30);
    dict.Add('Rui', 25);
    WriteLn(dict['Ana']);  // 30
  finally
    dict.Free;
  end;
end.

TDictionary<K,V> guarda pares chave-valor. Acede ao valor pela chave (ex.: dict["Ana"]). Equivalente a um mapa/hashtable.

Array dinâmico
var
  dyn: array of integer;

begin
  SetLength(dyn, 5);  // aloca 5 elementos
  dyn[0] := 10;       // começa em 0
  dyn[4] := 50;

  WriteLn(Length(dyn));  // 5
  WriteLn(Low(dyn));     // 0
  WriteLn(High(dyn));    // 4
end.

Um array dinâmico (array of) é redimensionável com SetLength. Começa sempre no índice 0. Length, Low e High dão os limites.

Variant record
type
  TForma = record
    case tipo: char of
      'c': (raio: real);
      'r': (larg, alt: real);
  end;

var
  f: TForma;
begin
  f.tipo := 'c';
  f.raio := 5.0;
end.

Um variant record tem campos que partilham memória conforme um campo discriminante (case). Semelhante a uma union em C.

Operações de sets
var
  A, B, C: set of integer;

begin
  A := [1, 2, 3];
  B := [2, 3, 4];
  C := A + B;  // união [1,2,3,4]
  C := A - B;  // diferença [1]
  C := A * B;  // interseção [2,3]
end.

Os sets suportam operações matemáticas: + (união), - (diferença) e * (interseção). Ideais para lógica de conjuntos.

Constantes array e record
const
  Dias: array[1..7] of string =
    ('Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sab', 'Dom');

  Origem: TPonto = (x: 0; y: 0);

begin
  WriteLn(Dias[1]);  // Seg
end.

Podes criar arrays e records constantes com valores iniciais fixos. Arrays usam (...) e records usam (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.

Um array multidimensional usa vários índices separados por vírgula (array[1..3, 1..3]). Ideal para matrizes e grelhas bidimensionais.

With (atalho de record)
var
  p: TPessoa;

begin
  with p do
  begin
    nome := 'Ana';
    idade := 30;
    ativo := true;
  end;
end.

O with evita repetir o nome do record ao aceder a vários campos. Dentro do bloco, nome refere-se a p.nome. Usar com moderação.

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 é uma lista dinâmica de strings da RTL. Oferece Add, IndexOf, Sort e Count. Cria com Create e liberta com Free.

Record simples
type
  TPessoa = record
    nome: string;
    idade: integer;
    ativo: boolean;
  end;

var
  p: TPessoa;
begin
  p.nome := 'Ana';
  p.idade := 30;
  p.ativo := true;
end.

Um record agrupa campos de tipos diferentes numa estrutura. Acede-se aos campos com ponto (p.nome). É o equivalente a uma struct.

Enumerados (enum)
type
  TCor = (Vermelho, Verde, Azul);

var
  c: TCor;

begin
  c := Verde;
  if c = Verde then
    WriteLn('Verde');
  WriteLn(Ord(c));  // 1 (posição)
end.

Um enumerado define um conjunto ordenado de valores nomeados. Ord() devolve a posição (começa em 0). Mais legível do que inteiros.

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.

Genéricos (TList<integer>) criam coleções tipadas seguras. Generics.Collections traz TList, TDictionary e outras listas dinâmicas.

Strings e Conversões


12 cards
Length e Copy
var
  s: string;

begin
  s := 'Olá Mundo';
  WriteLn(Length(s));      // 9
  WriteLn(Copy(s, 1, 3));  // 'Olá'
  WriteLn(Copy(s, 5, 5));  // 'Mundo'
end.

Length() devolve o número de caracteres. Copy(s, inicio, n) extrai uma substring a partir de inicio com n caracteres.

StringReplace
uses SysUtils;

var
  s: string;
begin
  s := 'ola mundo ola';
  s := StringReplace(s, 'ola', 'olá',
       [rfReplaceAll, rfIgnoreCase]);
  WriteLn(s);  // 'olá mundo olá'
end.

StringReplace() substitui texto. rfReplaceAll troca todas as ocorrências e rfIgnoreCase ignora maiúsculas/minúsculas.

Format
uses SysUtils;

begin
  WriteLn(Format('%d anos', [30]));
  WriteLn(Format('%.2f', [3.14159]));  // 3.14
  WriteLn(Format('%s tem %d', ['Ana', 30]));
  WriteLn(Format('%8d', [42]));  // alinhado
end.

Format() constrói strings com marcadores: %d (inteiro), %f (real), %s (string). O .2 define casas decimais.

Maiúsculas e minúsculas
uses SysUtils;

var
  s: string;
begin
  s := 'Olá Mundo';
  WriteLn(UpperCase(s));  // 'OLÁ MUNDO'
  WriteLn(LowerCase(s));  // 'olá mundo'
end.

UpperCase() converte para maiúsculas e LowerCase() para minúsculas. Estão na 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() remove espaços no início e no fim. TrimLeft() só à esquerda e TrimRight() só à direita. Essencial para limpar input.

Char: Ord e 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() devolve o código numérico do caractere e Chr() faz o inverso. Succ() e Pred() dão o seguinte/anterior.

Pos (procurar)
var
  s: string;
  p: integer;

begin
  s := 'Olá Mundo';
  p := Pos('Mundo', s);
  WriteLn(p);  // 5 (posição)

  if Pos('xyz', s) = 0 then
    WriteLn('não encontrado');
end.

Pos(sub, s) devolve a posição da primeira ocorrência (começa em 1) ou 0 se não encontrar. Útil para verificar presença.

String para 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() e StrToFloat() convertem strings em números e lançam exceção se inválidas. StrToIntDef() devolve um valor por defeito em vez de falhar.

Concat e Length
var
  a, b, c: string;

begin
  a := 'Olá';
  b := 'Mundo';
  c := Concat(a, ' ', b);
  WriteLn(c);          // 'Olá Mundo'
  WriteLn(Length(c));  // 9
end.

Concat() junta várias strings numa só (alternativa ao +). Length() devolve o comprimento. Strings em Pascal são dinâmicas.

Delete e Insert
var
  s: string;

begin
  s := 'Olá Mundo';
  Delete(s, 1, 4);   // remove 4 chars
  WriteLn(s);        // 'Mundo'

  Insert('!', s, 6);
  WriteLn(s);        // 'Mundo!'
end.

Delete(s, inicio, n) remove n caracteres (modifica a string). Insert(txt, s, pos) insere texto na posição indicada.

Número para 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() e FloatToStr() convertem números em strings. FloatToStrF() permite controlar o formato e as casas decimais.

String com aspas (escape)
var
  s: string;

begin
  s := 'Ele disse ''olá''';
  WriteLn(s);  // Ele disse 'olá'

  s := 'Linha1' + #13#10 + 'Linha2';
  WriteLn(s);  // duas linhas
end.

Para incluir uma aspa simples numa string, duplica-a (''). #13#10 insere quebra de linha (CR+LF) usando códigos de caractere.

Ponteiros, Units e Exceções


14 cards
Ponteiros básicos
var
  p: ^integer;
  x: integer;
begin
  x := 42;
  p := @x;       // endereço de x
  WriteLn(p^);   // 42 (dereference)
  p^ := 100;     // altera x
  WriteLn(x);    // 100
end.

Um ponteiro (^integer) guarda um endereço. @x obtém o endereço e p^ acede ao valor apontado (dereference).

Usar uma Unit
program Principal;

uses MinhaUnit, SysUtils;

begin
  WriteLn(Somar(2, 3));  // da MinhaUnit
end.

A cláusula uses importa units para aceder às suas funções e tipos. Pode aparecer no programa ou noutra unit (interface ou implementation).

Exceção personalizada
type
  ESaldoInsuficiente = class(Exception)
    constructor Create(valor: real);
  end;

constructor ESaldoInsuficiente.Create(valor: real);
begin
  inherited CreateFmt('Saldo insuficiente: %.2f',
    [valor]);
end;

Cria classes que herdam de Exception para erros específicos. CreateFmt formata a mensagem com parâmetros, como o Format.

Operações 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 (deslocar)
end.

Os operadores bit a bit and, or, xor, shl e shr operam sobre os bits do inteiro. Úteis para flags e máscaras.

Memória dinâmica
var
  p: ^integer;
begin
  New(p);      // alocar memória
  p^ := 100;
  WriteLn(p^);
  Dispose(p);  // libertar memória
  p := nil;
end.

New() aloca memória para o tipo apontado e Dispose() liberta-a. Define o ponteiro como nil depois para evitar acessos 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('Erro: ', E.Message);
  end;
end.

try..except captura exceções. O on E: Tipo trata cada tipo de exceção. E.Message dá a descrição do erro.

Constantes tipadas
const
  Limiar: integer = 100;  // mutável (FPC)

begin
  Limiar := 200;  // permitido
  WriteLn(Limiar);
end.

Constantes tipadas (nome: tipo = valor) são na verdade variáveis estáticas inicializadas: mantêm o valor entre chamadas e podem ser alteradas.

Programa completo (exemplo)
program Media;

uses SysUtils;

var
  notas: array of integer;
  i, soma: integer;

begin
  SetLength(notas, 3);
  soma := 0;
  for i := 0 to High(notas) do
  begin
    notas[i] := Random(20) + 1;
    soma := soma + notas[i];
  end;
  WriteLn('Média: ', soma / Length(notas):0:1);
end.

Exemplo completo: aloca um array dinâmico, preenche com Random, soma e calcula a média. Mostra a estrutura típica de um programa Pascal.

GetMem e FreeMem
var
  ptr: Pointer;
begin
  GetMem(ptr, 1024);  // 1024 bytes
  // usar ptr...
  FreeMem(ptr);       // libertar
  ptr := nil;
end.

GetMem() aloca um bloco de bytes em bruto e FreeMem() liberta. Mais flexível do que New para buffers de tamanho variável.

Try / Finally
var
  lista: TStringList;
begin
  lista := TStringList.Create;
  try
    lista.Add('item');
    WriteLn(lista.Count);
  finally
    lista.Free;  // executa sempre
  end;
end.

try..finally garante a execução do bloco finally mesmo com erro. É o padrão para libertar recursos (memória, ficheiros, objetos).

Diretivas de compilação
{$IFDEF DEBUG}
  WriteLn('Modo debug ativo');
{$ENDIF}

{$MODE DELPHI}   // modo Delphi (FPC)
{$RANGECHECKS ON} // verifica índices

begin
  WriteLn('Olá');
end.

Diretivas {$...} controlam a compilação. {$IFDEF} compila condicionalmente, {$MODE} define compatibilidade e {$RANGECHECKS} valida índices.

Estrutura de uma Unit
unit MinhaUnit;

interface

uses SysUtils;

function Somar(a, b: integer): integer;

implementation

function Somar(a, b: integer): integer;
begin
  Result := a + b;
end;

end.

Uma unit é um módulo reutilizável. A secção interface declara o que é público e implementation contém o código. Usa-se com uses.

Raise (lançar exceção)
procedure Validar(idade: integer);
begin
  if idade < 0 then
    raise Exception.Create('Idade inválida');
end;

raise lança uma exceção manualmente. Exception.Create(msg) cria a exceção com uma mensagem. Interrompe o fluxo até ao except mais próximo.

Type aliases
type
  TNome = string;
  TIdade = integer;
  TMatriz = array of array of real;

var
  nome: TNome;
  m: TMatriz;
begin
  nome := 'Ana';
end.

O type cria nomes alternativos para tipos existentes, melhorando a legibilidade. TNome é apenas um alias para string.

Entrada/Saída e Ficheiros


12 cards
Write e WriteLn
begin
  Write('Sem quebra ');
  WriteLn('com quebra');
  WriteLn('A', 'B', 'C');   // ABC
  WriteLn(10, ' ', 20);     // 10 20
  WriteLn(3.14:6:2);        //   3.14
end.

Write imprime sem mudar de linha e WriteLn muda. Aceitam vários argumentos separados por vírgulas e formatação :largura:casas.

Append (acrescentar)
var
  f: TextFile;

begin
  AssignFile(f, 'log.txt');
  Append(f);             // acrescentar no fim
  WriteLn(f, 'Nova entrada');
  CloseFile(f);
end.

Append abre um ficheiro existente para acrescentar no fim, sem apagar o conteúdo anterior. Ideal para ficheiros de log.

Verificar existência
uses SysUtils;

begin
  if FileExists('dados.txt') then
    WriteLn('existe')
  else
    WriteLn('não existe');

  if DirectoryExists('C:\temp') then
    WriteLn('pasta existe');
end.

FileExists() verifica se um ficheiro existe e DirectoryExists() se uma pasta existe. Estão na unit SysUtils.

Read e ReadLn
var
  nome: string;
  idade: integer;

begin
  ReadLn(nome);       // lê uma linha
  ReadLn(idade);      // lê um inteiro
  WriteLn(nome, ' ', idade);
end.

ReadLn lê uma linha completa do teclado e converte para o tipo da variável. Read lê sem consumir a quebra de linha.

Ficheiro binário (tipado)
type
  TRegisto = record
    id: integer;
    nome: string[50];
  end;

var
  f: file of TRegisto;
  reg: TRegisto;
begin
  AssignFile(f, 'dados.dat');
  Rewrite(f);
  reg.id := 1;
  reg.nome := 'Ana';
  Write(f, reg);
  CloseFile(f);
end.

Um file of TRegisto guarda registos de tamanho fixo em binário. Write(f, reg) e Read(f, reg) leem/escrevem registos completos.

Apagar e renomear
var
  f: TextFile;

begin
  AssignFile(f, 'antigo.txt');
  Erase(f);          // apaga o ficheiro

  AssignFile(f, 'novo.txt');
  Rename(f, 'novo2.txt');  // renomeia
end.

Erase() apaga o ficheiro associado e Rename() muda o nome. A variável deve estar associada com AssignFile mas não aberta.

Escrever ficheiro de texto
var
  f: TextFile;

begin
  AssignFile(f, 'dados.txt');
  Rewrite(f);            // criar/escrever
  WriteLn(f, 'Linha 1');
  WriteLn(f, 'Linha 2');
  CloseFile(f);
end.

AssignFile associa a variável ao ficheiro, Rewrite abre para escrita (cria novo), escreve com WriteLn(f, ...) e fecha com CloseFile.

Ler ficheiro binário
var
  f: file of TRegisto;
  reg: TRegisto;

begin
  AssignFile(f, 'dados.dat');
  Reset(f);
  while not EOF(f) do
  begin
    Read(f, reg);
    WriteLn(reg.id, ' ', reg.nome);
  end;
  CloseFile(f);
end.

A leitura binária usa Read(f, reg) dentro de while not EOF(f). Cada iteração carrega um registo completo da estrutura.

TFileStream
uses Classes, SysUtils;

var
  fs: TFileStream;
  s: string;
begin
  fs := TFileStream.Create('dados.bin',
        fmCreate);
  try
    s := 'Olá';
    fs.WriteBuffer(s[1], Length(s));
  finally
    fs.Free;
  end;
end.

TFileStream dá controlo total sobre leitura/escrita binária. fmCreate cria o ficheiro e WriteBuffer escreve bytes em bruto.

Ler ficheiro de texto
var
  f: TextFile;
  linha: string;

begin
  AssignFile(f, 'dados.txt');
  Reset(f);              // abrir para leitura
  while not EOF(f) do
  begin
    ReadLn(f, linha);
    WriteLn(linha);
  end;
  CloseFile(f);
end.

Reset abre o ficheiro para leitura. O ciclo while not EOF(f) percorre até ao fim, lendo cada linha com ReadLn(f, linha).

Tamanho e posição (binário)
var
  f: file of TRegisto;

begin
  AssignFile(f, 'dados.dat');
  Reset(f);
  WriteLn(FileSize(f));     // nº de registos
  Seek(f, 2);               // ir ao registo 2
  WriteLn(FilePos(f));      // posição atual
  CloseFile(f);
end.

FileSize() devolve o número de registos e FilePos() a posição atual. Seek(f, n) move para o registo n (acesso aleatório).

Parâmetros de linha de comandos
var
  i: integer;

begin
  WriteLn('Nº args: ', ParamCount);
  for i := 1 to ParamCount do
    WriteLn(ParamStr(i));
end.

ParamCount devolve o número de argumentos da linha de comandos e ParamStr(i) cada argumento. ParamStr(0) é o nome do executável.

Classes e OOP


14 cards
Classe básica
type
  TPessoa = class
    Nome: string;
    Idade: integer;
    procedure Apresentar;
  end;

procedure TPessoa.Apresentar;
begin
  WriteLn(Nome, ', ', Idade);
end;

Uma classe declara-se com class e contém campos e métodos. Os métodos implementam-se fora com TPessoa.Apresentar. Instancia-se com Create.

Private e public
type
  TConta = class
  private
    FSaldo: real;  // oculto do exterior
  public
    procedure Depositar(v: real);
    function Saldo: real;
  end;

private restringe o acesso ao interior da classe (encapsulamento). public torna os membros acessíveis de fora. Campos privados usam prefixo F.

inherited
procedure TCao.Falar;
begin
  inherited Falar;  // chama o da superclasse
  WriteLn('... e abana a cauda');
end;

inherited chama a versão do método na superclasse. Útil para estender comportamento em vez de o substituir por completo.

Polimorfismo
var
  formas: array of TForma;
  f: TForma;
begin
  SetLength(formas, 2);
  formas[0] := TCirculo.Create;
  formas[1] := TQuadrado.Create;
  for f in formas do
    WriteLn(f.Area);  // chama o certo
end.

Com métodos virtual/override, a mesma chamada (f.Area) executa a implementação correta conforme o tipo real do objeto em runtime.

Criar e libertar objeto
var
  p: TPessoa;
begin
  p := TPessoa.Create;
  try
    p.Nome := 'Ana';
    p.Idade := 30;
    p.Apresentar;
  finally
    p.Free;  // libertar memória
  end;
end.

Objetos criam-se com Create e devem ser libertados com Free. O try..finally garante a libertação mesmo se houver erro.

Properties
type
  TPessoa = class
  private
    FNome: string;
  public
    property Nome: string read FNome write FNome;
    property SoLeitura: string read FNome;
  end;

Uma property expõe campos com read e write, controlando o acesso. Pode ligar-se a métodos getter/setter para validação.

is e as
var
  a: TAnimal;
begin
  a := TCao.Create;
  if a is TCao then
    WriteLn('é um cão');

  (a as TCao).Latir;
  a.Free;
end.

is verifica o tipo em runtime e as faz cast seguro (lança exceção se falhar). Essenciais para trabalhar com polimorfismo.

for in (coleções)
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.

O for in percorre coleções e arrays de forma limpa, sem índices. Funciona com arrays dinâmicos, TList e outros enumeráveis.

Constructor
type
  TPessoa = class
    Nome: string;
    constructor Create(n: string);
  end;

constructor TPessoa.Create(n: string);
begin
  inherited Create;
  Nome := n;
end;

var p: TPessoa;
begin
  p := TPessoa.Create('Ana');
end.

O constructor inicializa o objeto na criação. inherited Create chama o construtor da classe base. Permite passar parâmetros iniciais.

Herança
type
  TAnimal = class
    procedure Falar; virtual;
  end;

  TCao = class(TAnimal)
    procedure Falar; override;
  end;

procedure TCao.Falar;
begin
  WriteLn('Au au!');
end;

A herança usa class(TAnimal). virtual marca o método como redefinível e override reimplementa-o na subclasse (polimorfismo).

Classe estática e Self
type
  TContador = class
    class var Total: integer;
    class procedure Incrementar;
  end;

class procedure TContador.Incrementar;
begin
  Total := Total + 1;
end;

Membros class pertencem à classe e não à instância (partilhados). Self refere o objeto atual, como this noutras linguagens.

Destructor
type
  TRecurso = class
    destructor Destroy; override;
  end;

destructor TRecurso.Destroy;
begin
  WriteLn('A libertar recursos');
  inherited Destroy;
end;

O destructor Destroy (com override) executa ao libertar o objeto. Usa-se para limpar recursos. Chama-se com Free, que verifica nil.

Métodos abstract
type
  TForma = class
    function Area: real; virtual; abstract;
  end;

  TCirculo = class(TForma)
    Raio: real;
    function Area: real; override;
  end;

function TCirculo.Area: real;
begin
  Result := 3.14159 * Raio * Raio;
end;

Um método abstract declara-se sem implementação e obriga as subclasses a defini-lo. Torna a classe base num contrato (classe abstrata).

Interfaces
type
  IGravavel = interface
    ['{GUID-AQUI}']
    procedure Gravar;
  end;

  TDocumento = class(TInterfacedObject, IGravavel)
    procedure Gravar;
  end;

Uma interface define um contrato sem implementação. A classe herda de TInterfacedObject e implementa os métodos. Suporta contagem de referências.