Logo Passei Direto
Buscar

Algoritmo e Programacao 1 em C

User badge image

Enviado por Guilherme Jannotti Arantes em

left-side-bubbles-backgroundright-side-bubbles-background

Experimente o Premium!star struck emoji

Acesse conteúdos dessa e de diversas outras disciplinas.

Libere conteúdos
sem pagar

left-side-bubbles-backgroundright-side-bubbles-background

Experimente o Premium!star struck emoji

Acesse conteúdos dessa e de diversas outras disciplinas.

Libere conteúdos
sem pagar

left-side-bubbles-backgroundright-side-bubbles-background

Experimente o Premium!star struck emoji

Acesse conteúdos dessa e de diversas outras disciplinas.

Libere conteúdos
sem pagar

left-side-bubbles-backgroundright-side-bubbles-background

Experimente o Premium!star struck emoji

Acesse conteúdos dessa e de diversas outras disciplinas.

Libere conteúdos
sem pagar

left-side-bubbles-backgroundright-side-bubbles-background

Experimente o Premium!star struck emoji

Acesse conteúdos dessa e de diversas outras disciplinas.

Libere conteúdos
sem pagar

left-side-bubbles-backgroundright-side-bubbles-background

Experimente o Premium!star struck emoji

Acesse conteúdos dessa e de diversas outras disciplinas.

Libere conteúdos
sem pagar

left-side-bubbles-backgroundright-side-bubbles-background

Experimente o Premium!star struck emoji

Acesse conteúdos dessa e de diversas outras disciplinas.

Libere conteúdos
sem pagar

left-side-bubbles-backgroundright-side-bubbles-background

Experimente o Premium!star struck emoji

Acesse conteúdos dessa e de diversas outras disciplinas.

Libere conteúdos
sem pagar

left-side-bubbles-backgroundright-side-bubbles-background

Experimente o Premium!star struck emoji

Acesse conteúdos dessa e de diversas outras disciplinas.

Libere conteúdos
sem pagar

left-side-bubbles-backgroundright-side-bubbles-background

Experimente o Premium!star struck emoji

Acesse conteúdos dessa e de diversas outras disciplinas.

Libere conteúdos
sem pagar

Prévia do material em texto

Algoritmos e Programação
de Computadores
Norton Trevisan Roman 
norton@ic.unicamp.br
http://www.ic.unicamp.br/~norton/
Material obtido na Internet e editado
com autorização do autor através de e-mail
 disponibilizado na próxima página
Prof. José Garibaldi de Carvalho
zegariba@gmail.com
Data: Wed, 23 Jun 2004 01:00:26 +0100
De: ntr <Norton.Roman@itri.brighton.ac.uk>
Para: gariba@colegiosantanh.com.br
Assunto: Apostilas disponibilizadas
Boa noite. 
Bom, não posso responder pelos outros, mas da minha parte, tu podes usá- la à vontade. 
Aliás, me chamou a atenção... a apostila de grafos também é minha... tá errado no site (o link 
leva à minha página...) 
enfim, acredito que queiras a apostila de Pascal. Então não há problema algum. E se quiser a de 
grafos, pode usar também. 
Abraço 
Norton 
p.s. Por um lapso meu, a apostila não está completa... mas na página principal da disciplina, eu 
indico o que está completo e o que não está. Consulte: 
http://www.dcc.unicamp.br/~norton/paginas/mc102/mc102.html. 
p.s2. Gostaria muito de receber qualquer comentário sobre ela... partes que não estão claras, 
erros etc. Isso ajudaria muito a melhorá- la. Obrigado.
Prezados Professores: 
Sou professor do curso Técnico de Informática (segundo grau) do Colégio Santa 
Catarina em Novo Hamburgo - RS. 
Ministro as disciplinas de Algoritmos e Lógica e Programação. 
Nosso colégio participou da Olimpíada 2004 na modalidade programação. Na página 
disponibilizada pela OBI, encontram-se apostilas (excelentes) elaboradas pelos 
Senhores. 
Minha pergunta é: 
Existe a possibilidade de as utilizarmos (impressas - resguardando autoria) com os 
alunos do Colégio em nossas aulas? 
Desde já agradeço pela atenção. 
Prof. José Garibaldi de Carvalho 
mail: gariba@colegiosantanh.com.br 
Colégio Santa Catarina 
Rua General Osório, 729 Cep: 93510-160 Novo Hamburgo - RS 
Fone: (51) 527-4862
SUMÀRIO
INTRODUÇÃO ................................................................................................................5
ESTRUTURA DE UM PROGRAMA ............................................................................5
COMENTÁRIOS..............................................................................................................5
SAÍDA ...............................................................................................................................6
PROCEDIMENTOS.........................................................................................................9
IDENTIFICADORES.....................................................................................................11
EXPRESSÕES ................................................................................................................12
VARIÁVEIS ...................................................................................................................15
ATRIBUIÇÕES ..............................................................................................................15
O COMANDO FOR .......................................................................................................18
ITERAÇÃO.....................................................................................................................21
LAÇOS ANINHADOS ..................................................................................................24
ITERAÇÕES ANINHADAS .........................................................................................25
DOWNTO .......................................................................................................................26
RECURSÃO....................................................................................................................29
MEMÓRIA DINÂMICA ...............................................................................................37
LISTAS LIGADAS ........................................................................................................42
FILAS ..............................................................................................................................54
PILHAS ...........................................................................................................................54
ARQUIVOS DE ACESSO SEQÜENCIAL..................................................................56
STRINGS.........................................................................................................................67
VETORES (ARRAY).....................................................................................................72
MATRIZES .....................................................................................................................79
BUSCA BINÁRIA..........................................................................................................84
REGISTROS ...................................................................................................................88
TIPOS ENUMERADOS ................................................................................................98
PRED E SUCC..............................................................................................................100
O COMANDO CASE...................................................................................................102
TIPO SUBRANGE (INTERVALO) ...........................................................................107
TYPE .............................................................................................................................108
FUNÇÕES.....................................................................................................................111
PASSAGEM DE PARÂMETROS ..............................................................................116
POR VALOR E REFERÊNCIA ..................................................................................116
VARIÁVEIS LOCAIS E GLOBAIS...........................................................................124
PROCEDIMENTOS.....................................................................................................128
DIAGRAMAS DE EXECUÇÃO ................................................................................130
ENTRADA E SAÍDA...................................................................................................135
CARACTERES.............................................................................................................136
LENDO E ESCREVENDO CARACTERES .............................................................137
CARACTERES E A TABELA ASCII........................................................................140
TABELA ASCII............................................................................................................143
O COMANDO REPEAT..............................................................................................145
O COMANDO WHILE................................................................................................148
TIPO BOOLEAN..........................................................................................................153
OPERADORES BOOLEANOS ..................................................................................154
TIPO REAL...................................................................................................................155
CONVERSÃO DE TIPOS ...........................................................................................156
O COMANDO IF..........................................................................................................158
CONDIÇÕES ................................................................................................................159
ELSE..............................................................................................................................160
AND...............................................................................................................................162OR ..................................................................................................................................162
ANIMAÇÃO BÁSICA................................................................................................. 164
ENTRADA....................................................................................................................168
CONSTANTES.............................................................................................................171
5
INTRODUÇÃO
Para a parte prática do curso, a linguagem ensinada é o Pascal. A partir de agora, as 
notas de aula se destinarão ao aprendizado desta linguagem. Todos os programas 
apresentados aqui funcionam corretamente se compilados usando o Pascal 
ESTRUTURA DE UM PROGRAMA 
A estrutura de um programa pascal é a seguinte:
 PROGRAM nome;
 {declarações}
 BEGIN
 {comandos}
 END.
"PROGRAM nome" dá um nome ao programa, enquanto que "BEGIN" avisa o 
computador onde começa o programa e "END" onde termina. 
A parte de "{declarações}" será vista mais tarde. Já "{comandos}" deve conter os 
comandos a serem executados no programa (vistos a seguir). No caso acima, como não 
há nenhum comando no corpo do programa (espaço entre o BEGIN e o END), nosso 
programa não executa nada. 
COMENTÁRIOS 
Comentários são observações que o programador faz no código do programa para poder 
entendê-lo melhor mais tarde, ou permitir que outros possam entender mais facilmente o 
programa. É parte da documentação do programa. 
Em Pascal há 2 formas de escrevermos comentários:
Entre (* e *) 
Entre { e } 
Assim, as palavras "declarações" e "comandos" no código acima são comentários. Uma 
observação importante sobre comentários é que você não precisa "casar" os { ou (*. O 
computador, ao encontrar um { ou (* ignora o que vem após até encontrar um } ou *) 
(se você abriu com (*, ele ignora até encontrar um *) e se abriu com { até encontrar um 
}). 
Assim, {{{{comentário} está certo, enquanto que {{com}} está errado, pois o primeiro 
} é suficiente para terminar o comentário, e o segundo será visto como erro. 
6
SAÍDA 
A saída de dados padrão é a tela do computador. Então, agora vamos ver como escrever 
mensagens na tela da máquina. 
Para escrever algo na tela usamos o comando "write" ou "writeln". Write escreve a 
mensagem pura e simplesmente, enquanto que writeln escreve a mensagem e pula para 
a linha de baixo. 
Considere, então o seguinte programa:
PROGRAM escreve;
 BEGIN
 write('alô');
write('você');
 END.
Sua saída será:
 alôvocê
Notou a falta do espaço? Poi é, ele precisa ser explicitamente incluído:
PROGRAM escreve;
 BEGIN
 write('alô ');
write('você');
 END.
Sua saída será:
 alô você
Agora, qual a diferença entre write e writeln? Vejamos o mesmo programa com writeln:
PROGRAM escreve;
 BEGIN
 writeln('alô ');
writeln('você');
 END.
Sua saída será:
 alô
 você 
7
Notou? um em cada linha. O comando writeln pode também ser usado para incluir uma 
quebra de linha, assim:
PROGRAM escreve;
 BEGIN
 write('alô ');
writeln;
 write('você');
 END. 
Gera:
 alô
 você 
E:
 PROGRAM escreve;
 BEGIN
 writeln('alô ');
writeln;
 write('você');
 END. 
Gera:
 alô
 você 
Podemos também combinar os comandos:
PROGRAM escreve;
 BEGIN
 write('alô ');
 writeln('você');
 write('aí!');
END. 
E teremos:
 alô você
 aí! 
Uma consideração final: e se quisermos imprimir a aspa simples (')? Como vimos, ela é 
parte integrante do write e writeln. Para imprimir uma aspa simples precisamos usar 
duas aspas simples. Assim:
 PROGRAM escreve;
 BEGIN
 write('''');
END. 
8
Escreverá na tela:
 ' 
Ou seja:
 PROGRAM escreve;
 BEGIN
 write('copo d''água');
 END. 
Escreverá na tela:
 copo d'água 
9
PROCEDIMENTOS 
Suponha que queremos desenhar na tela dois quadros do tipo:
 ****
 * *
 * *
 ****
Como faremos? Pelo que sabemos até agora, temos que: 
 1) escrever ****
 2) escrever * *
 3) escrever * *
 4) escrever ****
 5) escrever uma linha em branco
 6) escrever ****
 7) escrever * *
 8) escrever * *
 9) escrever ****
Mas esse trabalho pode ser decomposto em duas partes: 
1) desenho um quadrado 
2) escrevo uma linha em branco 
3) desenho outro quadrado 
Agora, como uso essa segunda abordagem no programa? Através de um procedimento. 
Um procedimento é um pedaço de programa que executa um conjunto de comandos. 
Vejamos como declarar um procedimento:
 PROCEDURE nome;
 {declarações}
 BEGIN
 {comandos}
 END;
Notou a semelhança com o modo como definimos o programa? Pois é, podemos 
concluir, então, que um programa é um grande procedimento, ou que um procedimento 
é um pequeno programa dentro do programa. 
10
Agora vamos inserir o código para desenhar um quadrado nesse nosso procedimento:
PROCEDURE dois_quad;
 BEGIN
 writeln('****');
 writeln('* *');
 writeln('* *');
writeln('****');
 END; 
Ótimo, mas agora onde colocamos isso no programa?
 PROGRAM quad;
 PROCEDURE dois_quad;
BEGIN
 writeln('****');
 writeln('* *');
 writeln('* *');
 writeln('****');
END;
 BEGIN
 {comandos}
 END. 
Simples não? Lembre que esse é o lugar da definição de procedimentos.
Mas esse nosso programa não faz nada! Como fazemos para desenhar os dois 
quadrados? Bom, lembra o nosso segundo algoritmo? Desenho um quadrado, dou uma 
linha em branco e desenho o outro. Ou seja:
 PROGRAM quad;
 PROCEDURE dois_quad;
BEGIN
 writeln('****');
 writeln('* *');
 writeln('* *');
 writeln('****');
 END;
 BEGIN
 dois_quad;
 writeln;
dois_quad;
 END.
11
E a saída será:
 ****
 * *
 * *
 ****
 ****
 * *
 * *
 **** 
Você pode estar se perguntando: mas isso deu mais trabalho do que escrever os 2 
quadrados. Sim, para dois deu, mas veja que para 3 não mais e, se o número de 
quadrados a serem desenhados for grande, você pode poupar muito tempo de trabalho. 
Essa é a vantagem do uso de procedimentos, você só precisa escrever códigos 
repetitivos uma só vez. 
Agora, como isso funciona? É, de fato, simples. Cada vez que o computador encontra o 
nome de um procedimento ele faz um desvio para o início deste procedimento, executa 
seu código (o que está entre seu BEGIN e END) e, ao terminar o procedimento, retorna 
ao comando seguinte à chamada deste. A figura abaixo ilustra essa situação: 
Por fim, note que declaramos o procedimento antes de usá-lo. Em Pascal temos que 
fazer isso sempre. 
IDENTIFICADORES 
Um identificador é um nome que damos a algo no pascal, seja um procedimento, o 
nome do programa etc. 
12
Tais nomes, em Pascal estão sujeitos às seguintes regras:
? podem somente começar com letras ou "_". 
? devem conter somente letras, números e "_". 
? não devem ser palavras reservadas da língua, como "program", "procedure", 
"begin" etc. 
Uma observação importante é que em Pascal letras maiusculase minúsculas são 
consideradas iguais em identificadores, então, assim como chamamos o procedimento 
para escrever um quadrado com "um_quad", poderiamos chamar com "UM_quad" ou 
qualquer outra variação. 
Vale ressaltar também que é uma boa técnica de programação fazer com que os 
identificadores sejam uma pista do motivo pelo qual existem, assim como o 
procedimento "um_quad", que desenha um quadrado na tela. 
EXPRESSÕES 
O computador não serve somente para escrever na tela, podemos pedir para que ele 
execute operações aritméticas também:
Comando Saída
 write(5);
 write(3 + 2);
 write('3 + 2'); 
5
 5
 3 + 2 
Note a terceira linha, que é lida como texto. 
As operações permitidas são:
+ Soma
- Subtração
* Multiplicação
/ Divisão
DIV
parte inteira da divisão.
11 DIV 4 = 2
MOD
resto da divisão.
11 MOD 4 = 3 (o resto)
O "-" pode também ser usado para dizer que um número é negativo:
Comando Saída
 write(-(3*5));
 write(-11 DIV 4);
 write(-11 DIV -4);
write(-11 MOD 4);
 write(-11 MOD -4);
-15
-2
 2
-3
-3
13
Agora, vejamos um outro uso do write e writeln (os exemplos abaixo valem para os 
dois):
Comando Saída
 write(5+9,' é a soma');
write('5 + 9 = ',5+9);
 write('5 + 9 = ',5+9,' (total)');
14 é a soma
 5 + 9 = 14
 5 + 9 = 14 (total) 
Note o espaço no início da frase "é a soma". Se ele não existir, a saída será "14é a 
soma".
Podemos ter, também, operações múltiplas:
Comando Saída
 write(5 + 6 + 7);
 write(5 + 6 - 7);
 write(3 + 4 * 5); 
 18
 4
 ?? 
Ops. E agora? Qual o resultado de 3+4*5? Podemos escolher a operação que será 
executada antes usando parênteses:
Comando Saída
 write(3 + (4 * 5));
 write((3 + 4) * 5);
 23
 35 
Porém, nesse caso simples, onde queremos efetivamente 3 + (4 * 5), não precisamos de 
parênteses. Como o computador sabe a ordem então? Em pascal, cada operador tem 
uma precedência, indicando a ordem em que as operações podem ser executadas. 
A ordem em que as operações serão executadas é:
DIV, MOD, *, / , +, -
Quando dois operadores de igual precedência ocorrem, são executados da esquerda para 
a direita. Então:
3 + 4 * 5 equivale a 3 + (4 * 5)
6 - 7 + 8 equivale a (6 - 7) + 8 
Mas sempre podemos mudar a precedência, usando parênteses. Por exemplo, fazendo 4 
- 6 + 7 estaremos fazendo (4 - 6) + 7. Agora, se colocarmos os seguintes parênteses 4 -
( 6 + 7 ) e s t a r e m o s f o r ç a n d o a a d i ç ã o a s e r c a l c u l a d a a n t e s .
Nesse caso, o computador considera como sendo a subtração de dois termos, sendo um 
deles uma expressão que deve ser calculada antes da subtração. 
Isso nos mostra uma característica importante da linguagem: parênteses têm a maior 
precedência dentre todos os operadores e, se houverem parênteses dentro de parênteses, 
o mais interno tem precedência maior. 
14
Então, de um modo geral:
? Calculamos o que está dentro dos parênteses (do mais interno ao mais externo): 
3 + (4 + (5 + 6)) — › 
5 + 6 = 11
4 + 11 = 15
15 + 3 = 18 
? Calculamos as operações de maior precedência da esquerda para a direita: 
2 + 3 * 5 / 2 — › 
3 * 5 = 15
15 / 2 = 7.5 
? Por fim, calculamos os termos de menor precedência da esquerda para a direita. 
2 + 3 * 5 / 2 — › 2 + 7.5 = 9.5 
Agora, veja a saída desse comando:
Comando Saída
 writeln(2 + 3 / 2); 3.500000000000000e+00 
Naturalmente, essa não é a saída desejada. Gostaríamos que tivesse, por exemplo, 
apenas 2 casas decimais apenas. Mas como fazer isso?
Comando Saída
 writeln(2 + 3 / 2 : 2 : 2); 3.50 
O número após o primeiro ":" indica o tamanho mínimo reservado para a variável, já o 
número após o segundo ":" indica o número de casas decimais (no caso de variável 
REAL).
15
VARIÁVEIS 
São lugares onde armazenamos e de onde lemos valores. 
Devem ser declaradas antes de usadas. Veja onde declarar variáveis:
No programa No procedimento
 PROGRAM x;
 VAR variável : tipo;
 BEGIN
 ...
 END. 
 PROCEDURE y;
 VAR variável ; tipo;
BEGIN
 ...
 END; 
Uma variável declarada no programa é visível a partir de todo o programa (inclusive 
procedimentos) e é chamada de variável global. 
Já uma variável declarada em um procedimento só é visível dentro deste procedimento, 
não podendo ser vista por elementos de fora dele. Tal variável é chamada de local. 
Agora, o que acontece se temos uma variável local com um mesmo nome de uma 
variável global? Nada, só que dentro do procedimento onde esta local está declarada, a 
global não é vista. 
Então, de forma geral, a declaração de uma variável é:
 VAR var1 : tipo1;
 var2 : tipo2;
 var3, var4 : tipo3; 
O tipo da variável indica o tipo de dado que ela armazenará. O computador precisa 
desse dado para saber o quanto de memória vai reservar para guardar a variável. Veja 
alguns tipos numéricos:
INTEGER inteiros de -32768 a 32767
REAL reais de 2.9E-39 a 1.7E38 (negativo inclusive) 
SHORTINT inteiros de -128 a 127 
WORD inteiros de 0 a 65535 
LONGINT inteiros de -2147483648 a 2147483647 
BYTE inteiros de 0 a 255 
CHAR caracter 
Há outros tipos, mas esses são os tipos mais simples (outros serão vistos mais tarde). 
ATRIBUIÇÕES 
Serve para que possamos por valores nas variáveis. Sua sintaxe é:
16
 variável := expressão;
Onde "expressão" pode ser um número ou uma expressão matemática, por exemplo:
 x := 3; O valor 3 é armazenado na variável x. 
 y := 4; O valor 4 é armazenado na variável y. 
 z := x + y;
O valor que está em x é somado ao 
que está em y, sendo o resultado 
armazenado na variável z. 
Vale lembrar que quando guardamos um valor numa variável, o valor antigo que estiver 
lá será perdido. 
Agora não confunda! x := 2 não quer dizer "x é igual a 2", mas sim "o valor 2 será 
guardado em x". Assim:
Comando Significado
 x := y;
uma cópia do valor que está em y será guardada em 
x. O valor que estava antes em x, se havia algum, 
será perdido. 
 x := x; uma cópia do valor que está em x será guardada em 
x de volta, perdendo o valor antigo. 
Dessa forma podemos fazer coisas do tipo:
 x := x + 1; 
O que isso faz? O computador pega o valor de x, soma 1 a esse e guarda o resultado 
novamente em x. Então, se x continha o valor 2, após a atribuição x := x + 1; ele conterá 
3. 
Viram? Isso mostra por que não podemos ver x:=2 como "x é igual a 2", pois senão 
x:=x+1 seria um erro matemático. 
Agora que sabemos como abastecer valores em variáveis, como fazemos para escrever 
seus valores na tela?
Comando O que faz
 x := 2; Abasteço x com o valor 2. 
 write(x); Escreve o valor de x na tela, no caso, 2. 
mas podemos enfeitar ainda mais, veja abaixo:
Comando Saída
 write('x = ',x); 
 x = 2
 write('x = ',x,' (total)'); x = 2 (total) 
17
reparou nos espaços entre o "=" e o "'" e entre o "'" e "(total)"? São necessários, senão a 
saída seria x =2(total). 
Agora vamos ver uma aplicação bem simples:
 PROGRAM media;
 USES crt; {para entrada e saída}
 VAR p1 : REAL; {nota da prova 1}
 p2 : REAL; {nota da prova 2}
 p3 : REAL; {nota da prova 3}
 m : REAL; {média das provas}
 BEGIN
 {dou as 3 notas}
 p1 := 3.0;
 p2 := 5.5;
 p3 := 6.5;
 {calculo a média}
 m := (2*p1 + 3*p2 + 5*p3) / 10;
 writeln('A média de ',p1:3:2,', ',p2:3:2,' e ',p3:3:2,' é 
',m:3:2,'.');
 END.
 saída:
 A média de 3.00, 5.50 e 6.50 é 5.50.
Veja a seguinte seqüência de comandos e a saída:
Comandos Saída
 x := 2;
 y := 3;
 write(x,y); 
 23 
Viu como as duas variáveis foram escritas lado a lado? Tome cuidado com isso!Por fim, uma outra boa dica é sempre inicializar as variáveis antes de usá-las, atribuindo 
a elas um valor inicial. 
18
O COMANDO FOR 
Lembra de nosso procedimento para desenhar um quadrado na tela? Lembra como 
fazíamos para desenhar dois? Nós 
1. desenhávamos um quadrado 
2. dávamos uma linha em branco 
3. desenhávamos outro quadrado 
4. dávamos outra linha em branco 
Ou seja, nós fazíamos o seguinte programa:
 PROGRAM quadrados;
 PROCEDURE um_quad;
 {aqui ía o corpo do procedimento}
 BEGIN
 um_quad;
 writeln;
 um_quad;
 writeln;
 END.
Mas e se quiséssemos desenhar 10 triângulos? Teríamos de escrever 10 vezes um_quad; 
e 10 vezes writeln;. Nossa! Isso não parece certo. Não seria mais fácil ter um algoritmo 
assim?: 
1. faça 10 vezes: 
1.1 desenhe um quadrado 
1.2 dê uma linha em branco 
Ou seja, estaríamos dizendo uma só vez "desenhe 10 quadrados" em vez de dizer 10 
vezes "desenhe um quadrado". 
Como fazemos isso em Pascal? Usando FOR:
 FOR cont:=1 TO 10 DO
 BEGIN
 um_quad;
 writeln;
END;
E se quisermos um número de quadrados diferente de 10? Basta substituir o 10 por esse 
número. 
Reparou na variável cont? Ela é INTEGER, não esqueça de declará-la no VAR. 
Mas afinal, o que o FOR faz? Vamos ler o comando: 
 FOR cont:=1 TO 10 DO algo
19
Ou seja, "para cont valendo inicialmente 1 até 10 faça algo. Peraí, cont só recebeu 1. 
Como seu valor pode chegar a 10? é que, a cada repetição, o comando for incrementa 
cont, ou seja, soma 1 a cont. Assim, ele executa isso 10 vezes, pois após 10 vezes somar 
1 a cont, esse chegará a ter 10 (se teve 1 como valor inicial). 
Então, o for age assim: 
1. atribui um valor inicial a cont 
2. verifica se esse valor é menor ou igual ao limite 10 
3. se for: 
3.1. executa o corpo do for (o que está entre o begin e o end) 
3.2. faz cont := cont + 1 
4. se não for: 
4.1. sai do for 
5. volta a 2. 
Agora repare que poderíamos por o writeln dentro do procediemtno um_quad. Façamos:
 PROCEDURE um_quad;
 BEGIN
 writeln('****');
 writeln('* *');
 writeln('* *');
 writeln('****');
 writeln
 END;
Mas, e nesse caso, como usaríamos o for? simples: 
FOR cont:=1 TO 10 DO
 BEGIN
 um_quad
 END;
Somente assim? Não. Há um outro modo: como o corpo do FOR (o que está entre 
BEGIN e END) contém um só comando, podemos fazer assim:
 FOR cont:=1 TO 10 DO um_quad;
Economizamos duas linhas de escrita! 
Atenção! Não confunda! Se dentro do for você quiser mais de um comando, deve 
colocar esses comandos entre BEGIN e END. Por exemplo:
 FOR cont:=1 TO 10 DO
 um_quad;
 writeln('quad');
O que isso faz? Não deixe a edentação te enganar, isso é o mesmo que:
20
 FOR cont:=1 TO 10 DO um_quad;
 writeln('quad');
Ou seja, isso desenha 10 quadrados dando uma linha em branco após cada um e então 
escreve 'quad'. Se quisermos escrever quad 10 vezes temos que fazer assim:
 FOR cont:=1 TO 10 DO
 BEGIN
 um_quad;
 writeln('quad');
END;
Então, eis o programa completo:
 PROGRAM quad;
 VAR cont : integer;
PROCEDURE um_quad;
 BEGIN
 writeln('****');
 writeln('* *');
 writeln('* *');
 writeln('****');
 writeln;
 END;
 BEGIN
 FOR cont:=1 TO 10 DO um_quad
 END
Poderíamos também por tudo isso no procedimento. Veja onde foi posta agora a 
declaração da variável:
 PROGRAM quad;
 PROCEDURE dez_quad;
VAR cont : integer;
 BEGIN
 FOR cont:=1 TO 10 DO
 BEGIN
 writeln('****');
 writeln('* *');
 writeln('* *');
 writeln('****');
 writeln
 END
 END;
 BEGIN
 dez_quad
END.
21
ITERAÇÃO 
Suponha, agora, que queremos contar os quadrados desenhados. Então, queremos que a 
saída seja:
 quad 1
 ****
 * *
 * *
 ****
 quad 2
 ****
 * *
 * *
 ****
 .
 .
 .
 quad 10
 ****
 * *
 * *
 ****
Como fazemos? Podemos usar a variável cont. Para isso:
 BEGIN
 FOR cont:=1 TO 10 DO
 BEGIN
 writeln('quad ',cont);
 um_quad
 END
END.
Lembra que o for incrementava cont? Pois é. Podemos usar esse fator a nosso favor. 
Vejamos outro exemplo. Vamos imprimir os 10 primeiros pares:
 FOR cont:=1 TO 10 DO writeln(2*cont);
E a saída é: 
 2
 4
 6
 ...
 20
E agora os 10 primeiros ímpares:
22
FOR cont := 1 to 10 do writeln(2*cont -1);
E teremos:
 1
 3
 5
 ...
 19
Agora vejamos alguns exemplos (estude-os cuidadosamente, vendo a importância de 
comentar o código. Fica mais claro não?): 
1. Soma dos 100 primeiros inteiros
 VAR soma : integer; {soma dos números}
 cont : integer; {contador do for}
 BEGIN
 soma := 0; {inicializei a soma}
 FOR cont := 1 to 100 do
 soma := soma + cont; {vou somando os números}
 writeln(soma);
 END.
2. Soma dos termos de uma P.A.
 VAR soma : integer; {a soma dos termos}
 razao : integer; {a razão da PA} 
 cont : integer; {contador do FOR}
 termo : integer; {cada termo da PA} 
 BEGIN
 soma := 0; {inicializando a soma}
 razao := 3; {a razão da PA é 3}
 termo := 1; {primeiro termo da PA}
 FOR cont:=1 TO 10 DO
 BEGIN
 soma := soma + termo; {adiciono o termo anterior à soma}
 termo := termo + razão {calculo o próximo termo da PA}
 END;
 writeln('A soma de ',cont,' termos da PA de razão ',razao,' 
com início em 1 é ',soma)
 END.
Vamos ver agora o conteúdo de cada variável após cada iteração:
 cont soma termo
- 0 1
 1 1 4
 2 5 7
23
 3 12 10
 4 22 13
 5 35 16
 6 51 19
 7 70 22
 8 92 25
 9 117 28
 10 145 31
 A soma de 10 termos da PA de 
razao 3 com início em 1 é 145
24
LAÇOS ANINHADOS 
Suponha que quiséssemos desenhar um quadrado 10 X 10 de *. Como faríamos?
 Faça 10 vezes:
 escreva uma linha com 10 *
Naturalmente, um programa que use esse algoritmo fucniona:
FOR cont:=1 TO 10 DO writeln('**********');
Mas, e se quisermos deixar o tamanho do quadrado como variável?
 FOR cont:=1 TO l DO escreva l vezes um *
Como escrevemos l vezes um *? Da mesma forma que fizemos os l conjuntos de l *:
 faça l vezes:
 escreva um *
Ou seja:
 FOR cont:=1 TO l DO write('*');
Então, para nosso quadrado:
 FOR cont:=1 TO l DO
 BEGIN
 FOR cont2 := 1 to l do write('*');
writeln;
 END;
Rode o programa e veja sua saída. Será um quadrado com o lado que você determinar 
em l. 
Reparou que as duas variáveis contadoras são diferentes? Elas tem que ser diferentes, 
senão, ao mudarmos o valor de uma, estaremos mudando também o valor da que 
controla o outro for (pois são a mesma). Por exemplo, veja a execução do seguinte 
programa, observe o valor das variáveis:
l := 3;
 FOR cont:=1 TO l DO
 BEGIN
 FOR cont := 1 to l do write('*');
25
 writeln
 END;
 cont
 1 do primeiro FOR
1 do segundo FOR
 2 do segundo FOR
 3 do segundo FOR
 saída:
 ***
Por que parou? Porque cont já chegou a l no laço interno (de fato, l é 4), então o laço 
externo entende que já fez as 3 vezes dele também. Não confunda! Não use a mesma 
variável! 
Mas, e se tivermos 2 laços disjuntos? Aí podemos usar a mesma variável. Quer um 
exemplo? Vamos desenhar 2 quadrados l X l, um ao lado do outro:
FOR cont:=1 TO l DO
 BEGIN
 FOR cont2 := 1 TO l DO write('*');
 write(' ');FOR cont2 := 1 TO l DO write('*');
writeln
 END;
Então posso usar a mesma variável, mas somente para laços disjuntos. No caso acima, a 
coisa funciona porque quando o segundo FOR interno muda o valor de cont2, o 
primeiro laço não precisava mais desse valor. Mas se um FOR estiver dentro do outro, 
então eles não são disjuntos, e não posso usar a mesma variável para ambos os 
contadors. 
E se, agora, quisermos escrever n quadrados de lado l, um ao lado do outro?
FOR cont:=1 TO l DO
 BEGIN
 FOR cont2 := 1 TO n DO
 BEGIN
FOR cont3 := 1 TO l DO
 write('*');
write(' ')
 END;
 writeln
 END;
saída (n := 3, l := 3):
 *** *** ***
 *** *** ***
 *** *** *** 
ITERAÇÕES ANINHADAS 
26
Vejamos outro exemplo: desenhe o seguinte triângulo:
 ...*...
 ..***..
 .*****.
 *******
Primeiro, vamos observar que esse é um retângulo de pontos e asteriscos de tamanho l 
X (2l-1), onde l é o número de linhas e (2l-1) o de colunas. Então temos uma relação 
entre as dimensões do retângulo. 
Note também que: 
? O número de pontos na linha l é de (n-l) à esquerda dos * e (n-l) à direita. 
? O número de * na linha l é (2l-1) 
Ótimo! Temos uma fórmula. Então vamos ao algoritmo:
 para cada linha l, até n linhas faça:
 desenhe n-l '.'
 desenhe 2l-1 '*'
 desenhe n-l '.'
E como fazemos isso em pascal?
FOR l:=1 TO n DO
 BEGIN
 FOR cont := 1 TO (n-l) DO write('.');
 FOR cont := 1 TO (2*l-1) DO write('*');
 FOR cont := 1 TO (n-l) DO write('.');
writeln
 END;
Reparou que usei cont para todos? Mais do que isso, notou como os limites dos FOR 
internos depende do contador do FOR externo? Ou seja, tome o primeiro FOR interno, 
seu limite é (n-l), ou seja, a cada iteração do FOR externo, o valor de l aumenta, 
aumentando esse limite. Isso é uma iteração aninhada. 
Com isso vemos uma característica do FOR: o ponto de início e o de fim de um laço 
pode ser qualquer expressão de resultado inteiro. 
Note também que quando l valer n, o primeiro e o terceiro FOR interno não serão 
executados, pois (n-l) será 0, e o final do laço é menor que o início. 
DOWNTO 
27
Como vimos, o comando FOR incrementa seu contador de forma crescente. Mas, e se 
quiséssemos decrementar o contador, ou seja, subtrair 1 dele a cada laço, fazendo uma 
contagem regressiva? Para tal usamos downto:
 FOR cont:=10 DOWNTO l DO writeln(cont);
saída:
 10
 9
 8
 ...
 3
 2
 1
Simples não? Vejamos um exemplo, vamos gerar dois triângulos, um em cima do outro, 
assim:
 ..*..
 .***.
 *****
 *****
 .***.
 ..*..
Como fazemos isso? Usamos o seguinte algoritmo:
 escrevemos um triângulo normal
 escrevemos um triângulo de cabeça para baixo
A primeira parte já vimos como fazer, mas e a segunda? Como desenhamos um 
triângulo de cabeça para baixo? Vamos primeiro ver como desenhávamos um triângulo 
normal:
 escrevíamos a primeira linha
 escrevíamos a segunda linha
 ...
 escrevíamos a n-ésima linha
E como fazemos com o invertido?
 escrevemos a n-ésima linha
 escrevemos a (n-1)-ésima linha
 ...
 escrevemos a primeira linha
28
Ou seja:
 FOR l:=n DOWNTO 1 DO 
 BEGIN
 FOR cont := 1 TO (n-l) DO write('.');
 FOR cont := 1 to (2*l-1) DO write('*');
 FOR cont := 1 to (n-l) DO write('.');
writeln
 END;
Se antes o FOR não era executado se contador > limite, agora não será se contador < 
limite. Por exemplo, o seguinte for:
 FOR cont:=1 DOWNTO 2 DO write('não vai 
escrever');
não é executado nenhuma vez. 
29
RECURSÃO 
Recursão é uma técnica de programação na qual chamamos uma função ou 
procedimento de dentro dela mesma. Ou seja, a definição de recursão poderia ser: 
 Recursão -> vide Recursão
Mas essa é uma definição meio falha, pois ela nunca pára. Então, para que a recursão 
seja perfeita, temos que dar uma condição de parada para a função. Assim, uma 
definição melhor é: 
 Recursão ->
 se você não entendeu o que é
 vide Recursão
Vamos ver um exemplo prático: como calcular n! 
Sabemos que n! = n × (n-1)! e que 0! = 1. Então: 
1. FUNCTION fatorial(n : integer) : integer;
 BEGIN
2. IF n=0 THEN fatorial := 1
3. ELSE fatorial := n * fatorial(n-1)
 END;
Estranho, não? O que acontece aqui? Cada vez que chamamos uma função ou 
procedimento recursivamente, essa chamada, juntamente com todos seus parâmetros e 
variáveis locais do procedimento ou função, é colocada em uma pilha. Assim, quando a 
última chamada é feita, ou seja, quando essa última chamada retorna, o computador vai 
desempilhando. 
Se quisermos acessar alguma variável da função ou procedimento, estaremos acessando 
a variável da última chamada feita, ou seja, da que está no topo da pilha. 
Vamos ver o funcionamento da pilha no caso da função acima, para 3! Na linha 1 
chamei a função pela primeira vez: 
fatorial(3)
Como 3 ����HQWão a linha 3 é executada, e chamo novamente a função 
fatorial(2)
fatorial(3)
Como 2 ����HQWão a linha 3 é executada, e chamo novamente a função 
30
fatorial(1)
fatorial(2)
fatorial(3)
Como 1 ����HQWão a linha 3 é executada, e chamo novamente a função 
fatorial(0)
fatorial(1)
fatorial(2)
fatorial(3)
agora 0 = 0, então a linha 2 é executada, e a função retorna pela primeira vez, 
retornando o valor 1. Essa chamada é desempilhada: 
fatorial(1)
fatorial(2)
fatorial(3)
Como a chamada a fatorial(0) foi feita na linha 3 da chamada a fatorial(1), o programa 
continua a rodar de lá, fazendo 1 × 1. Ou seja, multiplicando o n pelo valor de retorno 
de fatorial(n-1). Esse valor é, então retornado, e a chamada é desemplidada: 
fatorial(2)
fatorial(3)
Como a chamada a fatorial(1) foi feita na linha 3 da chamada a fatorial(2), o programa 
continua a rodar de lá, fazendo 2 × 1. Esse valor é, então retornado, e a chamada é 
desemplidada: 
fatorial(3)
Como a chamada a fatorial(2) foi feita na linha 3 da chamada a fatorial(3), o programa 
continua a rodar de lá, fazendo 3 × 2. Esse valor é, então retornado, e a chamada é 
desemplidada. No caso, esse é o valor de retorno da função, pois não há mais chamadas 
recursivas a serem desempilhadas. E eis que a resposta será 6, ou seja 3!. 
Mas como nem tudo é maravilha, apesar de facilitar nossa vida, recursão tem um preço: 
empilhar tudo isso gasta memória. 
Vejamos agora como fazer x^y (x elevado a y). 
Note que x^y = x × x^(y-1), e x^0 = 1. Então: 
1. FUNCTION pot(x,y : integer) : integer;
 BEGIN
31
2. IF y=0 THEN pot := 1
3. ELSE pot := x * pot(x,y-1)
END;
Mas há outro modo de fazer isso, note que: 
 x^1024 = (x^512)^2
 x^512 = (x^256)^2
 x^256 = (x^128)^2
 ...
 x^4 = (x^2)^2
 x^2 = x × x
Então temos que 
 x^y = 1 se y = 0
 x × x^(y-1) se y for ímpar
(x^(y/2))^2 se y for par
Assim, se y for par, faremos menos chamadas recursivas. A função, então, é: 
1. FUNCTION pot(x,y : integer) : integer;
 BEGIN
2. IF y=0 THEN pot := 1
 ELSE
3. IF Odd(y) THEN pot := x * pot(x,y-1)
4. ELSE por := Sqr(pot(x, y DIV 2))
END;
Opa! quem é esse Odd? 
 Odd(x : Longint) : Boolean;
retorna True se x for ímpar e False se não. 
Mas será que esse algoritmo é realmente melhor? Analizemos o primeiro para 3^4: 
Na primeira chamada temos: 
pot(3,4)
como 4 ���H�p�SDU��D�OLQKD���p�H[HFXWDGD��FKDPDQGR�SRW�QRYDPHQWH��
pot(3,3)
pot(3,4)
32
como 3 ���H�p�SDU��D�OLQKD���p�H[HFXWDGD��FKDPDQGR�SRW�QRYDPHQWH��
pot(3,2)
pot(3,3)
pot(3,4)
assim vamos indo para 1: 
pot(3,1)
pot(3,2)
pot(3,3)
pot(3,4)
e, por fim 
pot(3,0)
pot(3,1)
pot(3,2)
pot(3,3)
pot(3,4)
Agora, 0 = 0, então, pela linha 2,pot retorna 1 
pot(3,1)
pot(3,2)
pot(3,3)
pot(3,4)
na linha 3, de onde pot(3,0) foi chamada, pot retorna x × 1 = 3 
pot(3,2)
pot(3,3)
pot(3,4)
na linha 3, de onde pot(3,1) foi chamada, pot retorna x × 3 = 9 
pot(3,3)
pot(3,4)
na linha 3, de onde pot(3,2) foi chamada, pot retorna x × 9 = 27 
pot(3,4)
33
finalmente, na linha 3, de onde pot(3,3) foi chamada, pot retorna x × 27 = 81. O 
resultado final. Note que chegamos a ter 5 elementos na pilha. 
Agora vamos analizar o segundo algoritmo: chamamos a função 
pot(3,4)
como 4 é ���H�SDU��HQWão a linha 4 é executada: 
pot(3,2)
pot(3,4)
como 2 é ���H�SDU��HQWão a linha 4 é executada: 
pot(3,1)
pot(3,2)
pot(3,4)
como 1 é ���H�tPSDU��HQWão a linha 3 é executada: 
pot(3,0)
pot(3,1)
pot(3,2)
pot(3,4)
agora, a linha 2 é executada, retornando 1 e desempilhando essa chamada: 
pot(3,1)
pot(3,2)
pot(3,4)
como a chamada no topo parou na linha 3, e pot(3,0) retornou 1, termino a linha 3, 
retornando 3 × 1 = 3. 
pot(3,2)
pot(3,4)
como a chamada no topo parou na linha 4, e pot(3,1) retornou 3, termino a linha 4, 
retornando 3^2 = 9. 
pot(3,4)
por fim, como a chamada no topo parou na linha 4, e pot(3,2) retornou 9, termino a 
linha 4, retornando 9^2 = 81. Eis nossa resposta. Qual o número máximo de elementos 
34
na pilha? 4, 1 a menos que no algoritmo 1. E isso com y=4 somente. Se fizermos um y 
grande essa diferença sobe. Ou seja, esse algoritmo é realmente melhor. 
Agora vejamos um último exemplo. Vamos rever um algoritmo de ordenação, só que 
dessa vez, usando recursão. 
Lembra da ordenação por seleção? Seu algoritmo era: 
 procuro o menor elemento do vetor
 coloco esse elemento na primeira posição
 ordeno o resto do vetor
Esse "ordeno o resto do vetor" é recursivo. Então vamos lá, o procedimento de 
ordenação fica: 
 {ordena o vetor v, com índices começando em início e
 terminando em fim}
 PROCEDURE ordena(VAR v : vetor; inicio, fim : integer);
 VAR menor : integer; {posição do menor elemento}
 BEGIN
 IF inicio < fim THEN
 BEGIN {senão já está ordenado, tem um só elemento}
 menor := PosMenor(v,inicio,fim);
 Troca(v[menor],v[inicio]);
 {ordeno o resto}
 Ordena(v,inicio + 1,fim)
 END
 END;
Bem mais simples que a não recursiva, não é? 
Agora precisamos de uma função chamada PosMenor que me retorne o índice do menor 
elemento de v começando a busca no índice "inicio" e terminando em "fim", e um 
procedimento que troque dois valores no vetor: 
FUNCTION PosMenor(v : vetor; i,f:integer) 
: integer;
 VAR men : tipo;
 cont : integer;
 BEGIN
 men := v[i];
 PosMenor := i;
 FOR cont:=i TO f DO
 IF men > v[cont] THEN
 BEGIN
 men := v[cont];
PosMenor := cont
 END
 END;
 PROCEDURE Troca(var a,b : tipo);
35
 VAR c : tipo;
 BEGIN
 c := a;
 a := b;
 b := c
 END;
Então o programa fica: 
 PROGRAM Selecao;
 CONST MAX = 10;
 TYPE tipo = real;
 vetor = ARRAY[1..MAX] OF tipo;
VAR v : vetor;
 FUNCTION PosMenor(v : vetor; i,f:integer) : integer;
VAR men : tipo;
 cont : integer;
 BEGIN
 men := v[i];
 PosMenor := i;
 FOR cont:=i TO f DO
 IF men > v[cont] THEN
 BEGIN
 men := v[cont];
PosMenor := cont
END
END;
 PROCEDURE Troca(var a,b : tipo);
 VAR c : tipo;
 BEGIN
 c := a;
 a := b;
 b := c
 END;
 PROCEDURE ordena(VAR v : vetor; inicio, fim : integer);
 VAR menor : integer; {posição do menor elemento}
 BEGIN
 IF inicio < fim THEN
 BEGIN {senão já está ordenado, tem um só elemento}
 menor := PosMenor(v,inicio,fim);
 Troca(v[menor],v[inicio]);
 {ordeno o resto}
 Ordena(v,inicio + 1,fim)
END
 END;
 BEGIN
 {carrego o vetor vet}
Ordena(vet);
 {imprimo vet}
 END.
36
o código para carregar e imprimir vet fica como exercício. 
37
MEMÓRIA DINÂMICA 
Até agora, quando queríamos guardar muitos dados na memória, usávamos vetores. Só 
que vetores têm limite, ou seja, temos que definir de antemão o número máximo de 
elementos que um vetor pode ter. O que acontece se não tivermos esse limite? Ou seja, 
o que fazemos se esse limite não for definido? Uma alternativa seria criar um vetor 
imenso, gastando um mundo de memória. Mas ainda assim correríamos o risco de 
estourar o limite do vetor. Então, o que fazer? 
A solução ideal seria se pudéssemos, à medida que recebemos algum dado, separar um 
espaço na memória para ele e armazená-lo lá. Ou seja, nosso limite seria dado pela 
quantidade de memória disponível no computador. 
Naturalmente, como separamos um espaço na memória e guardamos um valor lá, temos 
que, de algum modo, saber qual é esse pedaço de memória, ou seja, precisamos de uma 
espécie de endereço que nos leve a esse pedaço para que, futuramente, possamos 
acessar o que guardamos lá ou mesmo guardar algo lá. 
Então como fazemos isso em Pascal? Com ponteiros. Ponteiros nada mais são do que 
variáveis que guardarm o endereço de uma região de memória, podendo essa região 
conter a informação que quisermos. 
Vejamos como declaramos ponteiros em Pascal: 
 VAR nome_do_ponteiro : ^tipo_apontado;
Nesse caso, tipo_apontado é qualquer tipo, simples ou definido pelo usuário, do Pascal. 
Ou seja, não posso fazer: 
 VAR ptr : ^ARRAY[1..10] OF integer;
mas posso fazer:
 TYPE vetor = ARRAY[1..10] OF integer;
VAR ptr : ^vetor;
Agora vamos ver como usar um ponteiro. Suponha a declaração: 
 VAR ptr : ^integer;
O que temos aqui? Apenas uma variável, chamada ptr, que é um ponteiro para um 
inteiro, ou seja, ela guarda um endereço de memória onde pode ser armazenado um 
inteiro. Mas de qual pedaço ela tem o endereço? Nenhum. Para efetivamente dar um 
valor a ptr temos que fazer: 
38
 new(ptr);
A forma geral do new é 
 New(variável_de_ponteiro);
O que, então, isso faz? Esse comando simplesmente diz ao sistema operacional para que 
este separe um pedaço de memória em que caiba um inteiro (o tipo apontado por ptr), 
guardando o endereço deste pedaço em ptr. E qual é esse endereço? Não sabemos, e 
nem precisamos saber, pois o Pascal abstrai tudo isso. Ou seja, podemos agora usar a 
variável ptr quase como se fosse um integer comum. Por que quase? Veja abaixo: 
 VAR ptr : ^integer;
 BEGIN
 new(ptr); {separei um pedaço de memória para um inteiro}
 ptr^ := 2; {coloquei o valor 2 nesse pedaço de memória}
 ptr^ := ptr^ * 3; {faço esse pedaço de memoria receber o 
triplo
 do que lá havia}
 END.
Viu como fizemos? "ptr^" pode ser usada como qualquer variável integer. Veja agora o 
programa abaixo: 
 VAR p1 : ^integer;
 p2 : ^integer;
 BEGIN
new(p1); {reservei um pedaço de memória para um inteiro,
 fazendo p1 apontar para ele}
 p2 := p1; {fiz p2 apontar para o mesmo pedaço de memória
 que p1 aponta}
 p1^ := 4; {coloquei o valor 4 nesse pedaço de memória}
 writeln(p2^); {escrevi o valor que está no pedaço de
 memória apontado por p2, ou seja, 4, pois
 p2 aponta para o mesmo pedaço de memória
 que p1}
 p2^ := p2^ + 3; {adicionei 3 ao valor que havia no pedaço
 de memória apontado por p2 e armazenei
 novamente nesse pedaço o resultado}
 writeln(p1^); {escrevo o conteúdo da memória apontada por
 p1, ou seja, 7, pois p1 aponta para o mesmo
 pedaço de memória que p2 aponta}
 END.
39
Como isso funciona? Vejamos por partes: 
? Quando fizemos new(p1), separamos (ou, como dizemos, alocamos) espaço na 
memória suficiente para um inteiro, guardando o endereço desse espaço em p1, 
ou seja, fizemos p1 apontar para lá:
? Ao fazer p2 := p1 (note que nãoé p2^ := p1^), guardamos uma cópia do 
endereço que estava em p1 em p2. Ou seja, fazemos p2 apontar para a mesma 
região de memória que p1 apontava: 
? Ao fazermos p1^ := 4 guardamos 4 nessa região: 
? Ao lermos p2^ no write, simplesmente lemos o valor que está na região da 
memória apontada por p2, ou seja, 4. 
? Ao fazermos p2^ := p2^ + 3, pegamos o conteúdo da região de memória 
apontada por p2, somamos 3 a este e armazenamos o resultado de volta nessa 
mesma região: 
? Ao lermos p1^ no write, novamente lemos o valor que está na região de 
memória apontada por p1, ou seja, 7, já que esta é a mesma região que é 
apontada por p2 e que foi modificada no passo anterior. 
Então não confunda! Se fazemos 
 p2^ := p1^;
estamos copiando o conteúdo da região de memória apontada por p1 para a região de 
memória apontada por p2. Já se fizermos 
 p2 := p1;
estaremos fazendo p2 apontar para a mesma região de memória apontada por p1. 
40
Agora que sabemos como carregar valores com ponteiros, como fazemos para "zerar" 
um ponteiro? Ou seja, para dizer que ele não aponta para lugar nenhum? 
 p1 := NIL;
Se não fizermos isso, ele conterá um endereço de memória que pode já ter sido liberada 
pelo programa, ou que pode não pertencer ao programa, o que geraria um erro quando 
da execução. 
E, por falar em liberar memória, como fazemos se quisermos liberar a memória que 
reservamos com new? 
 Dispose(variável_de_ponteiro);
ou seja 
 Dispose(p1);
Dispose avisa ao sistema operacional que não vamos mais precisar desse pedaço de 
memória, liberando esta. SEMPRE libere a memória que não vai mais usar para não 
esgotar os recursos da máquina. 
Cuidado com o seguinte erro: 
VAR p1 : ^integer;
 p2 : ^integer;
 BEGIN
 new(p1);
 p2 := p1;
 p1^ := 4;
 Dispose(p2);
writeln(p1^)
 END.
isso pode gerar um erro, pois já liberei a memória apontada por p2, que é a mesma 
apontada por p1 
Vale também lembrar que, ao final do programa, se você não liberou a memória usada, 
o computador a libera para você. Ainda assim é uma boa prática limpar seu lixo. 
E se agora quisermos um ponteiro para um tipo mais complexo, como registro? 
TYPE reg = RECORD
41
 cp1 : real;
 cp2 : integer;
 cp3 : ARRAY[1..10] of char
 END;
 VAR p : ^reg;
 BEGIN
 New(p);
END.
Pronto! Aloquei espaço para o meu registro. Ou seja, na memória foi reservado espaço 
suficiente para guardar os 3 campos do nosso registro. E como acessamos ou mudamos 
o valor desses campos? 
 TYPE reg = RECORD
 cp1 : real;
 cp2 : integer;
 cp3 : ARRAY[1..10] of char
 END;
 VAR p : ^reg;
 i : integer;
 BEGIN
 new(p);
 p^.cp1 := 3.12;
 p^.cp2 := Round(p^.cp1); {guardei 3}
 FOR i:=1 TO 10 DO
 p^.cp3[i] := Chr(Ord('a') + i);
 writeln(p^.cpq,' - ', p^.cp2,' - ',p^.cp3[5]);
Dispose(p)
 END.
Ou seja, agimos como se "p^" fosse o nome do registro. E se em vez de registro 
quisermos lidar com um vetor? 
TYPE vet = ARRAY[1..10] of integer;
 VAR p : ^vet;
 BEGIN
 new(p);
p^[1] := 4;
 p^[2] := 5;
 p^[3] := p^[1] + p^[2];
 writeln(p^[1],' + ',p^[2],' = ',p^[3]);
Dispose(p)
 END.
42
Novamente, agimos como se "p^" fosse o nome do vetor. 
Com ponteiros, as operações permitidas são = e <>. Assim ,não posso fazer +, - etc. Ou 
seja, as únicas operações que posso usar com ponteiros são: 
 p1 = p2 -> True se ambos apontam para a mesma 
região de memória
 p1 <> p2 -> True se ambos apontam para regiões 
diferentes
Agora que já vimos o que são ponteiros, vamos aprender, na próxima seção, a usá-los. 
LISTAS LIGADAS 
Suponha que queremos ler uma lista de dados. Até aí tudo bem. Agora suponha que não 
conhecemos o número total de dados. Como fazemos então? 
Seria desejável seguir o seguinte algoritmo: 
 inicialmente a lista está vazia
 enquanto o usuário não manda parar de ler
 leio um dado
 coloco este dado na lista
assim fica fácil não? Mas como fazer isso em Pascal? Usando ponteiros. Como? Com 
uma lista ligada. O que, então, é uma lsita ligada? 
Uma lista ligada é uma lista onde cada elemento - chamado de nó - contém um valor e 
um ponteiro para o elemento seguinte. Assim, sabendo onde está o primeiro elemento 
da lista, podemos chegar a qualquer outro elemento. Há vários tipos de listas ligadas: 
? Simples:
O sinal de aterramento significa que este ponteiro é NIL, ou seja, não aponta 
para lugar nenhum. 
? Circular:
43
? Duplamente ligada:
e muitas outras mais. O limitante é apenas sua imaginação. Aqui iremos usar somente 
listas simples. 
Mas e qual as vantagens e desvantagens de cada uma? Listas duplamente ligadas são 
fáceis de se percorrer, mas ocupam mais espaço na memória. Note que nessas eu posso, 
a partir de um elemento, voltar na lista, percorrê-la de trás para frente, pois tenho 
ponteiros que medizem onde estão o próximo elemento e o anterior. 
As circulares simples são fáceis de percorrer e não ocupam muita memória. Mas se o 
número de elementos for grande, vai se comportar quase como uma lista simples. 
Qual lista é a melhor? Depende do problema a ser resolvido.,p> Agora vamos definir 
operações básicas em listas: 
? Criação de uma lista 
? Inclusão de um elemento na lista 
? Exclusão de um elemento da lista 
? Esvaziamento da lista 
? Contagem do número de elementos da lista 
? Inclusão de um elemento na posição i 
? Exclusão do iº elemento na lista 
? Busca da posição do primeiro elemento de valor x 
? Exclusão do primeiro elemento de valor x 
? etc 
Vamos ver então como criar uma lista ligada. Nos exemplos que seguem estaremos 
usando a lista ligada simples, conforme foi apresentada acima. 
Antes de mais nada, vamos definir nossa lista: 
 TYPE tipo = real;
 p_no = ^no;
 no = RECORD
44
 valor : tipo;
prox : p_no
 END;
Agora vamos definir o procedimento de criação da lista. 
 PROCEDURE Cria(VAR cabeca : p_no);
 BEGIN
 cabeca := NIL
 END;
Pronto! O que fizemos com isso? Dissemos que a lista está vazia ao darmos um valor 
"nada" à cabeça desta. Se não fizermos isso, a cabeça pode conter lixo indesejável. 
Agora vamos incluir um elemento na lista. A questão é: onde? Você decide. Pode ser no 
início, pode ser no meio (caso você queira ordenar a lista enquanto a constrói) e pode 
ser no fim. Nesse caso, vamos por no fim. Então, como faremos? 
Suponha que temos a seguinte lista:
Vamos, então, colocar um elemento em seu final 
? Alocamos o espaço para o novo elemento, fazendo q apontar para ele, e o 
abastecemos com valor
? Usamos um ponteiro auxiliar, p, para apontar para a cabeça da lista
? Precorremos a lista com p até que este aponte para o último elemento
45
? Fazemos o próximo elemento de p (que agora aponta para o fim da lista) ser q, 
ou seja, fazemos q ser o novo fim da lista
E se a lista estiver inicialmente vazia? Então 
? Alocamos o espaço para o novo elemento e o abastecemos com valor
? Fazemos a cabeça da lista ser esse novo elemento 
Assim, o procedimento fica: 
 PROCEDURE Inclui(VAR cabeca : p_no; elemento : tipo);
 VAR q : p_no; {o novo elemento}
 p : p_no; {auxiliar}
 BEGIN
 {aloco espaço para o novo elemento}
 New(q);
 {abasteço os valores nesse}
 q^.valor := elemento;
 q^.prox := NIL;
 {vejo onde coloco q na lista}
 IF cabeca <> NIL THEN
 BEGIN
 {a lista não estava vazia}
 p := cabeca;
 {vou até o fim da lista}
 WHILE p^.prox <> NIL DO p := p^.prox;
46
 {agora p é o último elemento, pois p^.prox = NIL}
 {faço o próximo elemento de p ser q, ou seja, q é o novo fim}
 p^.prox := q
 END
 ELSE {a lista está vazia. Façoq ser a cabeça}
 cabeca := q
 END;
Vamos agora excluir um elemento da lista. Novamente, qual? Você escolhe! Vamos 
tomar como política a exclusão do primeiro elemento da lista. Como faremos isso? 
Suponha a lista:
Vamos, então, retirar um elemento de seu início: 
? Primeiro fazemos p apontar para o início da lista:
? Depois fazemos a cabeça apontar para o segundo elemento:
? Eliminamos agora o elemento apontado por p 
E o procedimento fica: 
 PROCEDURE Exclui(VAR cabeca : p_no; VAR valor:tipo);
47
 VAR p : p_no; {auxiliar}
 BEGIN
 IF cabeca <> NIL THEN
 BEGIN
 {a lista não está vazia}
 p := cabeca;
 {faço a cabeça apontar para o próximo}
 cabeca := cabeca^.prox;
 {retorno o valor que está em p}
 valor := p^.valor;
 {mato o elemento apontado por p}
 Dispose(p);
 END
 {else a lista está vazia, não há o que tirar}
 END;
Suponha que queremos simplesmente matar a lista inteira, como fazemos isso? Da 
mesma forma que excluímos um elemento, só que não devolvemos valor algum: 
? Coloco um ponteiro p na cabeça da lista 
? Enquanto p não for nil 
o Faço a cabeça apontar para o próximo de p 
o Mato p 
o Faço p apontar para a cabeça 
O procedimento fica: 
 PROCEDURE Limpa(VAR cabeca : p_no);
 VAR p : p_no; {auxiliar}
 BEGIN
 p := cabeca;
 WHILE p <> NIL DO
 BEGIN
 cab := p^.prox;
Dispose(p);
 p := cab
 END
 END;
E como fazemos para contar os elementos de uma lista? Basta criar um contador e 
percorrer a lista incrementando o contador: 
? Coloco um ponteiro p na cabeça da lista e zero o contador cont 
? Enquanto p não for nil 
o Incremento cont 
o Faço p apontar para o próximo elemento 
Ou seja: 
 FUNCTION NumEl(cabeca : p_no) : integer;
VAR p : p_no; {auxiliar}
48
 BEGIN
 p := cabeca;
 NumEl := 0;
 WHILE p <> NIL DO
 BEGIN
p := p^.prox;
 NumEl := NumEl + 1
 END
 END;
Agora, usando algumas das funções acima, vamos incluir um novo nó na posição i da 
nossa lista. Como faremos isso? Suponha a seguinte lista
? Primeiro fazemos p apontar para o início da lista:
? Em seguida movemos p até o elemento anterior à posição em que queremos 
incluir (suponha que queremos incluir na 3ª posição):
? Criamos, então, espaço para o novo elemento, fazendo q apontar para ele:
? Fazemos, então, o próximo elemento de q ser o próximo de p:
49
? E o próximo elemento de p ser q:
pronto! Incluímos na posição i = 3. 
E se quisermos incluir na última posição? Funciona? Claro! Pois pararei com p no 
último elemento. 
E se a lista estiver vazia? Nesse caso, basta criar o elemento e fazer a cabeça apontar 
para ele (veja abaixo como incluir na primeira posição). Note que nesse caso, o único i 
aceitável é 1. 
E se a posição pedida for 1? Esse é um caso um pouco mais complicado, pois não há 
como parar um elemento antes, o que indica que nosso algoritmo falha. Como fazer, 
então? 
? Primeiro criamos espaço para o novo elemento, fazendo q apontar para ele:
? Fazemos, então, o próximo elemento de q ser a cabeça:
50
? E a cabeça apontar para q:
Pronto! Incluímos na primeira posição. Vamos agora ao procedimento: 
 PROCEDURE IncluiEmPos(VAR 
cabeca:p_no;valor:tipo;posicao:integer);
 VAR p : p_no; {auxiliar}
 q : p_no; {o novo elemento}
 i : integer; {contador do FOR}
 BEGIN
 {testo se a posição é válida}
IF (posicao <= (NumEl(cabeca) + 1)) AND (posicao > 0) THEN
BEGIN
 {é uma posição válida. O +1 é porque se tem 5 elementos
 posso por na posição 6, por exemplo (embora não na 7)}
 {crio o novo elemento}
 new(q);
 q^.valor := valor;
 q^.prox := NIL;
 IF posicao=1 THEN {quero na primeira posição}
 BEGIN
 {se a lista estiver vazia, não há problema aqui}
{faço o próximo de q ser a cabeça}
q^.prox := cabeca;
{faço a cabeça ser q}
cabeca := q
 END
 ELSE BEGIN {é outra posição}
 {note que aqui a lista jamais estará vazia, senão
 NumEl retornaria 0 e posição > 1}
{faço p apontar para a cabeça}
p := cabeca;
{movo p até o elemento anterior à posição. Como p já
 está em 1, movo posicao-2 posições}
51
FOR i:=1 TO posicao-2 DO
 p := p^.prox;
{agora p aponta para o elemento anterior}
{faço o próximo de q ser o próximo de p}
q^.prox := p^.prox;
{faço o próximo de p ser q}
p^.prox := q
 END
 END
 {ELSE não faz nada!}
 END;
Ótimo! Vamos agora excluir um elemento da posição i. Suponha a seguinte lista:
? Primeiro fazemos p apontar para o início da lista:
? Em seguida movemos p até o elemento anterior à posição do elemento que 
queremos excluir (suponha que queremos excluir da 3ª posição):
? Marcamos a posição a ser excluída com um ponteiro q:
? Fazemos, então, o próximo elemento de p ser o próximo de q:
52
? Eliminamos q:
pronto! Excluímos o nó da posição i = 3. 
E se a lista estiver vazia? Nesse caso, Nada poderá ser excluído. 
E se a posição pedida for 1? Esse, novamente, é um caso um pouco mais complicado, 
pois não há como parar um elemento antes, o que indica que nosso algoritmo falha. 
Como fazer, então? Basta seguir o algoritmo dado acima para retirar um elemento do 
início da lista. 
Vamos, então, à função que retira o iº elemento da lista. Essa função retorna o valor que 
estava nesse elemento: 
 FUNCTION TiraDaPos(VAR cabeca:p_no;posicao:integer):tipo;
 VAR p : p_no; {auxiliar}
 q : p_no; {auxiliar}
 i : integer; {contador do FOR}
 BEGIN
 {testo se a posição é válida}
IF (posicao <= NumEl(cabeca)) AND (posicao > 0) THEN
BEGIN
 {é uma posição válida. Note que se a lista estiver 
vazia
 nada é feito, pois posicao >=1, o que é > 0}
 {faço p apontar para a cabeça}
 p := cabeca;
 IF posicao=1 THEN {quero na primeira posição}
 BEGIN
{faço a cabeça ser o segundo elemento}
cabeca := cabeca^.prox;
{dou o valor de retorno}
TiraDaPos := p^.valor;
{mato o nó}
Dispose(p)
 END
 ELSE BEGIN {é outra posição}
{movo p até o elemento anterior à posição. Como p já
53
 está em 1, movo posicao-2 posições}
FOR i:=1 TO posicao-2 DO
 p := p^.prox;
{agora p aponta para o elemento anterior}
{faço o próximo de p ser q}
q := p^.prox;
{faço o próximo de p ser o próximo de q}
p^.prox := q^.prox;
{retorno o valor de q}
TiraDaPos := q^.valor;
{mato o nó apontado por q}
Dispose(q)
 END
 END
 END;
Agora vamos ver como buscar a posição do primeiro elemento que contenha o valor x 
na nossa lista. Para tal, o procedimento é simples: 
? Coloco um ponteiro p na cabeça da lista e crio um contador, inicializando-o com 
1. 
? Enquanto p não for NIL e não encontrei o valor vou incrementando p e o 
contador. 
? Se encontrei o valor, retorno o valor do contador, senão, retorno 0. 
Vamos, então, à função: 
 FUNCTION Pos(cabeca:p_no; elemento:tipo):integer;
 VAR p : p_no; {auxiliar}
 BEGIN
 {inicializo o contador}
 Pos := 1;
 {aponto p para a cabeça da lista}
 p := cabeça;
 WHILE (p <> NIL) AND (p^.valor <> elemento) DO
BEGIN
 p := p^.prox;
 Pos := Pos+1
 END;
 IF p = NIL THEN Pos := 0
{o else é automático, pos terá o valor certo}
 END;
E para excluir o primeiro elemento de valor x? Basta 
? Buscar a posição do primeiro elemento de valor x 
? Excluir o elemento nessa posição 
54
Ou seja: 
 PROCEDURE ExcluiX(VAR cabeca:p_no; elemento:tipo);
 VAR el : tipo; {o elemento a ser excluído, é auxiliar}
BEGIN
 el := TiraDaPos(cabeca,Pos(cabeca,elemento))
{excluí, el jogo fora}
 END;
FILAS 
Uma fila é uma lista que tem como característica o fato de que o primeiro elemento a 
entrar nela é o primeiro a sair. Assim, ela funciona como uma filacomum. 
Pense numa fila de banco. Quem será o primeiro a ser atendido? O primeiro que 
chegou. E onde os que chegam depois devem entrar na fila? No final desta. 
Assim é uma fila: se quero retirar um elemento, retiro da frente; se quero incluir, incluo 
no final da fila. 
Note que este foi o modo como implementamos as listas acima, ou seja, quando 
fazíamos nossa lista, estávamos na verdade construindo uma fila. A única diferença é 
que em uma fila não posso retirar um elemento do meio da fila, ou lá colocar um, coisa 
que implementamos acima. Mas, de resto, as funções são as mesmas. 
PILHAS 
Uma pilha é uma estrutura de dados que, pasmem, funciona como uma pilha! 
Pense numa pilha de livros. É assim que ela funciona. Se queremos por mais um livro 
na pilha, onde colocamos? No topo! E se queremos tirar um livro, de onde tiramos? Do 
topo. 
Então, uma pilha nada mais é do que uma lista ligada que tem como característica o fato 
de que, se queremos incluir um elemento na lista, temos de incluí-lo no início desta, e se 
queremos tirar um elemento da lista, tiramos do início desta. 
Dessa forma, uma pilha tem as seguintes funções: 
? Criação da pilha (como nas listas acima) 
? Empilhamento (quando coloco um elemento no topo da pilha, ou seja, no início 
da lista) 
? Desempilhamento (quando tiro um elemento do topo da pilha, ou seja, do início 
da lista) 
Note que não há como eu tirar um elemento do meio da pilha. 
55
É como nossa pilha de livros, para retirar um livro do meio, tenho que desempilhar 
todos os que estão acima. Da mesma forma, para tirar um dado do meio da pilha, tenho 
que desempilhar os que estão antes dele. Vejamos, agora, funções para criação, 
empilhamento e desempilhamento: 
 TYPE tipo = real;
 p_pilha = ^pilha;
 pilha = RECORD
 dado : tipo;
 prox : p_pilha
END;
 VAR topo : p_pilha;
PROCEDURE IniciaPilha(VAR topo : p_pilha);
 BEGIN
 topo := NIL
 END;
 PROCEDURE Empilha(VAR topo : p_pilha; dado : tipo);
 VAR p : p_pilha; {auxiliar}
 BEGIN
 {crio o novo elemento e dou valor a ele}
 new(p);
 p^.valor := dado;
 {faço ele apontar para o topo da pilha}
 p^.prox := topo;
 {faço o topo apontar para ele}
 topo := p
 END;
 FUNCTION Desempilha(VAR topo : p_pilha) : tipo;
 VAR p : p_pilha; {auxiliar}
 BEGIN
 {faço p apontar para o topo}
 p := topo;
 {retorno o valor de p}
 Desempilha := p^.valor;
 {baixo o topo, para o segundo elemento}
topo := topo^.prox;
 {elimino p}
Dispose(p)
 END;
Acima você encontra ilustrações de como retirar um elemento do início da lista, ou seja, 
do topo da pilha, e de como incluir um elemento na posição 1 da lista, ou seja, no topo 
da pilha. 
56
ARQUIVOS DE ACESSO SEQÜENCIAL 
Até agora, todos os dados lidos por nossos programas vinham do teclado, e todas as 
saídas íam para a tela. 
Mas, e se quiséssemos guardar alguns resultados para reaproveitar mais tarde? Como 
faríamos? Simples, basta guardarmso esses dados em arquivos no computador. 
Quando digitamos um texto, para guardá-lo, não salvamos em um arquivo? E quando 
queremos usar esse texto novamente não lemos o que salvamos anteriormente no 
arquivo? O princípio é o mesmo. Então, como usamos arquivos em Pascal? 
Antes de mais nada, devemos declarar uma variável de arquivo. Como fazemos isso? 
Atenção!!! Os programas escritos até a metade desta lição não devem ser executados. A 
razão é que eles estão incompletos. Mais adiante veremos o que falta neles. 
 VAR nome_da_variável : FILE OF tipo_do_dado;
Assim, para definirmos uma variável de arquivo, temos que saber o tipo de dado que 
colocaremos lá. Então, suponha que nosso arquivo é texte, então teremos: 
 VAR arq : FILE OF char;
Mas, afinal, para que precisamos de uma variável de arquivo? Mais adiante veremos 
que é através dela que teremos acesso a nosso arquivo. 
Esse tipo de arquivo texto já é pré-definido no pascal, ou seja, o Pascal tem um tipo pré-
definido para arquivos texto: o text. Então, as duas declarações abaixo são equivalentes 
 VAR arq : FILE OF char;
VAR arq : text;
pois o pascal já fez essa declaração para você: 
TYPE text = FILE OF char;
Naturalmente, se você quiser arquivos de algum outro tipo que não char, você deve 
fazer, por exemplo: 
VAR arq1 : FILE OF integer;
57
arq2 : FILE OF real;
 etc
só que, nesse caso, os arquivos são tratados de modo um pouco diferente pelo Pascal. 
Confira a lição de arquivos de acesso aleatório para ver como o Pascal trata esses 
arquivos. 
Nesse momento, trataremos somente de arquivos texto. 
Bom, agora já sabemos como declarar uma variável de arquivo. Agora, como a usamos? 
Antes de querer lidar com o arquivo, precisaremos associar essa variável a um arquivo 
real no disco. Ou seja, precisamos associá-la ao nome de um arquivo que queiramos 
criar ou ao nome de um já existente que queiramos abrir. Como fazemos isso? 
 Assign(variável_de_arquivo, nome_do_arquivo);
Por exemplo, o programa: 
 VAR arq : text;
 BEGIN
 Assign(arq,'oba.txt');
END.
associa à variável "arq" o arquivo de nome "oba.txt". Lembre-se que tal arquivo não 
necessariamente precisa existir no disco. 
Após associar o nome ao arquivo, qual o próximo passo? Aí depende: queremos criar 
um novo arquivo ou abrir um existente? 
Suponha que queremos criar um arquivo novo: 
VAR arq : text;
 BEGIN
 Assign(arq,'oba.txt');
Rewrite(arq);
 END.
Pronto! O comando Rewrite cria um novo arquivo e o abre para gravação (escrita). E se 
o arquivo "oba.txt" já existir no disco? Nesse caso o Rewrite o apaga, escrevendo o 
novo conteúdo por cima dele. Ou seja, cuidado! Pois se o arquivo a ser criado já existir 
no disco, tudo que havia nele antes do Rewrite será perdido. Assim, a forma geral do 
Rewrite é: 
58
 Rewrite(variável_de_arquivo);
Agora que criamos o arquivo, como fazemos para guardar algo nele? Como fazemos 
para escrever nele? De um modo bem semelhante a como escrevíamos na tela: 
VAR arq : text;
 BEGIN
 Assign(arq,'oba.txt');
 Rewrite(arq);
 write(arq, 'mensagem');
 writeln(arq, 'para');
write(arq,'o arquivo')
 END.
Isso irá gravar 
 mensagempara
 o arquivo
no arquivo. Ou seja, do mesmo modo que o write e o writeln agem na tela, agem no 
arquivo. 
O write e o writeln também podem ser usados para escrever outros tipos de dados. Eles 
convertem automanticamente os valores de dados numéricos para strings de dígitos 
antes de armazenar no arquivo texto. Assim, posso escrever: 
 VAR arq : text;
 idade : integer;
str : string;
 BEGIN
 Assign(arq,'oba.txt');
Rewrite(arq);
 idade := 25;
 writeln(arq,'João',idade);
 str := 'Pedro Souza';
 idade := 12;
 writeln(arq,str,idade)
 END.
E se, em vez de cirarmos um arquivo, quisermos escrever em um já existente, sem 
apagar o conteúdo prévio deste? Neste caso, em vez de Rewrite usamos Append: 
 VAR arq : text;
59
 idade : integer;
str : string;
 BEGIN
 Assign(arq,'oba.txt');
 Append(arq);
 idade := 25;
 writeln(arq,'Jnova linha')
 END.
Nesse exemplo, se o arquivo continha: 
 linha 1
 escrevo linha 2
agora terá: 
 linha 1
 escrevo linha 2
 nova linha
se "escrevo linha 2" foi gravada com writeln, ou: 
 linha 1
 escrevo linha 2nova linha
se "escrevo linha 2" foi gravada com write. 
Assim, Append abre um arquivo já existente, de modo que possamos adicionar texto ao 
FINAL deste. Note que só adiciono ao fim do arquivo. 
A forma geral do comando é: 
 Append(variável_de_arquivo);
Como o Append assume que o arquivo existe, se este não existir, um erro em tempo de 
execução será gerado. 
Agora, digamos que queremos apenas ler o conteúdo de um arquivoque está no disco, 
como fazemos? Com Reset: 
 Reset(variável_de_arquivo);
Por exemplo, o seguinte programa 
60
 VAR arq : text;
 s : string[5];
 s1 : string;
 BEGIN
 Assign(arq,'oba.txt');
 Reset(arq);
 read(arq,s);
readln(arq,s1);
 END.
lê 2 strings de "oba.txt". O read lê até o tamanho máximo de s (5). Já o readln lê uma 
linha inteira do arquivo, armazenando-a em s1 (lê a linha ou até 255 caracteres, que é o 
máximo de string). Assim, se o arquivo contiver 
 este texto é grande
 eu o escrevi
s terá "este " (repare que o espaço foi junto) e s1 terá o resto da linha, ou seja, "texto é 
grande". 
Então, Reset abre um arquivo existente somente para leitura. 
da mesma forma que o write, o read pode transformar o texto lido em valores 
numéricos. Por exemplo, lembra nosso arquivo anterior onde gravamos "João 25"? 
Como lemos isso? 
VAR arq : text;
 s : string;
 id : integer;
 BEGIN
 Assign(arq,'oba.txt');
Reset(arq);
 readln(arq,s,id);
 END.
Aqui, s terá "João" e id terá 25. 
assim, tanto real quanto integer podem ser lidos, lembrando que, em um arquivo texto, 
quando lemos várias variáveis, como no exemplo acima, os caracteres delimitadores são 
os espaços, tabulação e CR (enter). 
Se tentarmos ler uma seqüência não numérica com read e guardarmos em uma variável 
numérica, um erro ocorre (da mesma forma como quando recebemos do teclado). 
61
Assim, é melhor escrever informações diferentes em linhas diferentes, ou seja, se estou 
guardando nomes e idades, gravo numa linha o nome e na outra a idade. É bem verdade 
que precisarei de dois writeln para gravar e dois readln para ler, mas fica mais 
organizado. 
Suponha, então, que temos um arquivo chamado "idades.txt" com nomes e diades: 
 Rolando Caio da Rocha
 23
 Jacinto Dores
 12
 Armando Machado
 34
Como fazemos para imprimir na tela o conteúdo desse arquivo? 
VAR arq : text;
 s : string;
 id : integer;
 BEGIN
 Assign(arq,'oba.txt');
 Reset(arq);
 WHILE NOT eof(arq) DO
 BEGIN
 readln(arq,s);
 readln(arq,id);
 writeln(s,' - ',id)
END
 END.
O que eof faz? Sua sintaxe é: 
 Eof(variável_de_arquivo) : 
boolean;
e ele retorna True se o arquivo chegou ao fim (EOF = End Of File). É útil quando não 
sabemos quantas linhas tem o arquivo. 
Por fim, já que com Reset, Rewrite e Append abrimos um arquivo, sempre devemos 
fechá-lo. Como? 
 Close(variável_de_arquivo);
Então, nosso programa acima fica: 
VAR arq : text;
62
 s : string;
 id : integer;
 BEGIN
 Assign(arq,'oba.txt');
 Reset(arq);
 WHILE NOT eof(arq) DO
 BEGIN
 readln(arq,s);
 readln(arq,id);
 writeln(s,' - ',id)
END;
 Close(arq)
 END.
Sempre feche seus arquivos assim que terminar de usá-los. 
Vale notar que, apesar de fechar o arquivo, close não termina com a associação entre a 
variável de arquivo e o nome deste. Ou seja, podemos jsar Reset, Rewrite e Append 
novamente para tratar com o mesmo arquivo sem precisarmos usar Assign. 
Assim, valem as seguintes observações: 
? Um arquivo texto só pode ser aberto para uma operação por vez: leitura, escrita 
ou junção (append). 
? O nome do arquivo, passado com assign, deve conter o caminho até este no 
diretório. Se não contiver, o compilador assumirá que está no mesmo diretório 
do programa. 
Então, em suma, para ler ou escrever em um arquivo texto temos que: 
? Definir uma variável de arquivo texto e associar a ela o nome que o arquivo tem 
ou terá no disco. 
? Abrir o arquivo para ler ou escrever. 
? Ler os dados do arquivo, ou escrever os dados nele. 
? Fechar o arquivo. 
Como um arquivo texto só pode ser aberto para inclusão em seu final, como podemos 
fazer para modificar um dado no meio deste? E apagar algum dado do meio? 
Considere um sistema onde guardamos o nome da pessoa e sua data de nascimento. 
Então, vamos criar as estruturas para tal: 
 TYPE data = RECORD
 dia : word;
 mes : word;
 ano : word
 END;
pessoa = RECORD
 nome : string[25];
63
 nasc : data
END;
Agora, vamos criar o arquivo e abaster os dados: 
PROGRAM PROG;
 CONST NOMEARQ = 'niver.txt';
 TYPE data = RECORD
 dia : word;
 mes : word;
 ano : word
 END;
 pessoa = RECORD
 nome : string[25];
 nasc : data
END;
 VAR sai : boolean;
 arq : text;
 p : pessoa;
 BEGIN
 sai := false;
 Assign(arq,NOMEARQ);
 Rewrite(arq);
 WHILE NOT sai DO
 BEGIN
 write('nome: ');
 readln(p.nome);
 IF p.nome='sai' THEN sai:=true
 ELSE BEGIN
 write('nascimento(dd mm aa):');
readln(p.nasc.dia,p.nasc.mes,p.nasc.ano);
writeln(arq,p.nome);
writeln(arq,p.nasc.dia:2,' ',p.nasc.mes:2,' 
',p.nasc.ano:2)
{o :2 é para escrever com 2 dígitos}
END
 END;
 Close(arq)
 END.
Esse programa fica executando até que o usuário digite 'sai'. Note que, se o arquivo 
existir, o que havia nele será apagado. Se você não quiser que isso ocorra use Append 
em ves do Rewrite. 
Então, nosso arquivo será: 
 Rolando Caio da Rocha
64
 12 05 98
 Jacinto Dores
 01 01 87
 Armando Machado
 15 06 76
 Paula Aguiar Cavalo
 23 02 88
Agora suponha que queremos apagar do arquivo o Armando Machado, como fazemos? 
Parece estranho, mas como esse tipo de arquivo é seqüencial, ou seja, não consigo 
modificar o meio dele, devemos usar o seguinte algoritmo: 
 Abro "niver.txt" para leitura
 Crio "temp.txt"
 Enquanto "niver.txt" não chegar ao fim
 Leio nome e data do "niver.txt"
 Se nome 
 Senão ignoro e não copio nada
Após rodarmos o algoritmo no arquivo da esquerda, teremos o da direita: 
 NIVER.TXT
 Rolando Caio da 
Rocha
 12 05 98
 Jacinto Dores
 01 01 87
 Armando Machado
 15 06 76
 Paula Aguiar 
Cavalo
 23 02 88
 TEMP.TXT
 Rolando Caio da Rocha
 12 05 98
 Jacinto Dores
 01 01 87
 Paula Aguiar Cavalo
 23 02 88
Note que "temp.txt" é o "niver.txt" que queríamos. Então completo meu algoritmo: 
 Abro "niver.txt" para leitura
 Crio "temp.txt"
 Enquanto "niver.txt" não chegar ao fim
 Leio nome e data do "niver.txt"
 Se nome 
 Senão ignoro e não copio nada
 Apago "niver.txt"
 Troco o nome de "temp.txt" para "niver.txt"
Agora podemos passar ao programa que faz isso: 
PROGRAM PROG;
 CONST NOMEARQ = 'niver.txt';
65
 NOMEAUX = 'temp.txt';
 TYPE data = RECORD
 dia : word;
 mes : word;
 ano : word
 END;
 pessoa = RECORD
 nome : string[25];
 nasc : data
END;
 VAR arq1 : text;
 arq2 : text;
 p : pessoa;
 proc : string[25];
 BEGIN
sai := false;
 proc := 'Armando Machado';
 {abro o arquivo de dados para leitura}
 Assign(arq1,NOMEARQ);
 Reset(arq1);
 {crio o arquivo temporário}
Assign(arq2,NOMEAUX);
 Rewrite(arq2);
 WHILE NOT Eof(arq1) DO
 BEGIN
 readln(arq1,p.nome);
 readln(arq1,p.nasc.dia,p.nasc.mes,p.nasc.ano);
 IF p.nome<>proc THEN
 BEGIN
 writeln(arq2,p.nome);
writeln(arq2,p.nasc.dia:2,' ',p.nasc.mes:2,' 
',p.nasc.ano:2)
END
 END;
 {fecho os arquivos}
 Close(arq1);
 Close(arq2);
 {apago niver.txt}
 Erase(arq1);
 {renomeio temp.txt para niver.txt}
Rename(arq2,'niver.txt')
 END.
Viu como apagamos e renomeamos um arquivo? 
 Erase(variável_de_arquivo); {apaga o arquivo do disco}
 Rename(variável_de_arquivo,'novo_nome'); {renomeia o 
arquivo, dando 'novo_nome' a ele}
66
Agora suponha que, nesse arquivo de onde "Armando Machado" foi removido,queremos mudar a data de nascimento de "Jacinto Dores" para 01/02/87, como 
fazemos? O algoritmo é muito semelhante: 
 Abro "niver.txt" para leitura
 Crio "temp.txt"
 Enquanto "niver.txt" não chegar ao fim
 Leio nome e data do "niver.txt"
 Se nome 
 Senão gravo os dados modificados
 Apago "niver.txt"
 Troco o nome de "temp.txt" para "niver.txt"
ou seja: 
 PROGRAM PROG;
 CONST NOMEARQ = 'niver.txt';
 NOMEAUX = 'temp.txt';
 TYPE data = RECORD
 dia : word;
 mes : word;
 ano : word
 END;
 pessoa = RECORD
 nome : string[25];
nasc : data
END;
 VAR arq1 : text;
 arq2 : text;
 p : pessoa;
 proc : string[25];
 nova : data;
 BEGIN
 sai := false;
 proc := 'Jacinto Dores';
 nova.dia := 1;
 nova.mes := 2;
 nova.ano := 87;
 {abro o arquivo de dados para leitura}
 Assign(arq1,NOMEARQ);
 Reset(arq1);
 {crio o arquivo temporário}
Assign(arq2,NOMEAUX);
 Rewrite(arq2);
 WHILE NOT Eof(arq1) DO
 BEGIN
67
 readln(arq1,p.nome);
 readln(arq1,p.nasc.dia,p.nasc.mes,p.nasc.ano);
 writeln(arq2,p.nome);
 IF p.nome<>proc THEN
writeln(arq2,p.nasc.dia:2,' ',p.nasc.mes:2,' 
',p.nasc.ano:2)
ELSE {substituo a data}
writeln(arq2,nova.dia:2,' ',nova.mes:2,' ',nova.ano:2)
 END
 END;
 {fecho os arquivos}
 Close(arq1);
 Close(arq2);
 {apago niver.txt}
 Erase(arq1);
 {renomeio temp.txt para niver.txt}
Rename(arq2,'niver.txt')
 END.
Pronto, modificamos. 
STRINGS 
Até agora vimos como ler, escrever e lidar com caracteres. O problema é que, muitas 
vezes, queremos lidar com palavras ou frases. Como fazemos, então, para ler uma frase 
que o usuário digita? 
Um possível algoritmo seria: 
 enquanto o usuário não digitou < enter >
 leio o caracter
 guardo o caracter lido
e onde guardaríamos esses caracteres? Poderia ser em um vetor de caracteres. Um tanto 
quanto complicado, não? Bom, acontece que o Pascal descomplicou isso, criando o tipo 
String 
PROGRAM P;
 VAR s : String;
 BEGIN
writeln('Sua frase: ');
 readln(s);
 writeln('Você disse: ',s)
 END.
68
O tipo string guarda uma cadeia de caracteres, da mesma forma que um vetor de 
caracteres. Assim, ao rodar o programa acima teríamos 
 sua frase:
 essa é minha frase< enter >
 Você disse: essa é minha frase
Simples, não? 
Uma coisa interessante sobre Strings é que o Pascal os trata como vetores de caracteres. 
Na verdade, String não é exatamente um ARRAY[1..255] OF char, mas é quase. 
Agora espera um pouco. De onde veio esse 1..255? Pois é! String, em Pascal, é limitado 
a 255 caracteres. 
Mas, e se quisermos um string maior ou menor? Basta definir o tamanho quando da 
declaração da variável: 
 VAR s1 : String[10]; {s1 conterá no máximo 10 
caracteres}
 s2 : String[1000]; {s2 conterá no máximo 1000 
caracteres}
Ou seja, de uma forma geral: 
 VAR nome : String[limite];
 ou
 VAR nome : String; {255 é o limite}
Também posso declarar tipos com strings: 
TYPE nomes : String[20];
 endereco : String[300];
VAR nome : nomes;
 end : endereco;
Pelo fato do String ser semelhante a um vetor, posso fazer: 
PROGRAM P;
 VAR s : String;
 BEGIN
writeln('Sua frase: ');
 readln(s);
69
 writeln('Você disse: ',s);
 writeln(s[4]); {escreve o "a" de "essa é minha frase"}
 s[5] := 'z'; {agora s contém "essazé minha frase" - mudei 
o 5º caracter}
 END.
Ou seja, posso usar o String como vetor de caracteres. 
mas será que a única vantagem de Strings é dar um nome a ARRAY[1..255] OF char? 
Não! Pascal tem facilidades embutidas. Por exemplo, para concatenar (juntar) 2 strings 
basta usar o sinal "+": 
PROGRAM P;
 VAR s1,s2,s3 : String;
 BEGIN
 readln(s1);
 readln(s2);
 writeln(s1+s2);
 s3 := s1 + s2;
 writeln(s3)
END.
Nesse caso, se a entrada for: 
 Alô
 Mundo
A saída será: 
 AlôMundo
 AlôMundo
Sendo o segundo "AlôMundo" o conteúdo da variável s3. 
Agora, como abastecemos uma variável string? 
PROGRAM P;
 VAR s1,s2,s3,s4 : String;
 BEGIN
readln(s1); {leio s1}
70
 readln(s2); {leio s2}
 s4 := 'Alô mundão!'; {carrego s4}
s3 := s1 + ' -- ' + s2;
 s2 := s4;
 writeln('s1: ',s3);
 writeln('s2: ',s3);
 writeln('s3: ',s3);
 writeln('s4: ',s3)
 END.
Repare nas aspas simples. É como em char. Se a entrada para esse programa for: 
 Alô
 Mundo
A saída será: 
 Alô
 Alô mundão!
 Alô -- Mundo
 Alô mundão!
Agora vamos ver algumas funções para tratamento de strings: 
Length(s : String) : Integer: Retorna o número de caracteres do string s. 
VAR s : string;
 n : integer;
 BEGIN
s := 'Alô mundo!';
 n := Length(s); {n terá 10}
 n := Length('Teste do length'); {n terá 15}
 END.
Copy(s : String; inicio, tamanho : integer) : String: Retorna um substring de s, 
começando em início e com o tamanho especificado. 
VAR s : string;
 l : string;
 BEGIN
 s := 'Alô mundo!';
l := Copy(s,2,5); {l terá 'lô mu'}
71
 l := Copy('Testando copy!',5,4); {l terá 'ando'}
 END.
Delete(VAR s : String; começo, tamanho : integer): Elimita parte do string s, começa 
em início com o tamanho especificado. 
VAR s : string;
 l : string;
 BEGIN
 s := 'Alô mundo!';
Delete(s,3,5); {s terá 'Aldo', eliminando 'ô mun'}
 END.
Str(x; VAR s : string) ou str(x:largura; VAR s : string) ou str(x:largura:decimais; 
VAR s : string): Transforma um número x em sua prepresentação string. x pode ser 
integer ou real, s terá x na forma string com largura e casas decimais especificadas. 
VAR s : string;
 x : real;
 BEGIN
 x := 3.14;
 Str(x,s); {s terá '3.14'}
Str(-12,s); {s terá '-12'}
 END.
72
VETORES (ARRAY) 
Lembra de nosso programa que tirava a média de n números inteiros? Vamos repetí-lo 
para 10 números: 
 PROGRAM notas;
 VAR num : integer; {número digitado}
 media : real; {média dos dados}
 cont : integer; {contador do for}
 soma : integer; {soma dos dados}
BEGIN
 soma := 0;
 FOR cont := 1 TO 10 DO
BEGIN
 write('entre um dado: ');
 readln(num);
 soma := soma + num
 END;
 media := soma / n;
 writeln('a média é ',media:4:2)
 END.
Mas, e se quiséssemos guardar os vários valores de num? Como fazemos? Usamos um 
vetor (array): 
 PROGRAM notas;
1. VAR num : ARRAY[1..10] OF integer; {vetor dos números 
digitados}
 media : real; {média dos dados}
 cont : integer; {contador do FOR}
 soma : real; {soma dos dados}
BEGIN
 soma := 0;
 FOR cont := 1 TO 10 DO
BEGIN
 write('entre um dado: ');
2. readln(num[cont]);
3. soma := soma + num[cont]
 END;
 media := soma / n;
 writeln('a média é ',media:4:2)
 END.
Agora vamos por partes. antes de mais nada, o que é um vetor? Um vetor pode ser 
pensado como uma variável que consegue guardar vários valores de um determinado 
tipo. Assim, quando definimos: 
 VAR num : ARRAY[1..10] OF integer; {vetor dos 
números digitados}
73
estamos criando uma variável, chamada num, que é capaz de guardar até 10 inteiros. Ou 
seja, na prática, esta seria uma variável assim: 
1 2 3 4 5 6 7 8 9 10
onde em cada quadrado cabe um inteiro. 
Então, quando fazemos 
 n[5] := 20;
estamos colocando o inteiro 20 na 5ª posição do vetor: 
1 2 3 4 5 6 7 8 9 10
20
Veja que, na linha 2 do nosso programa acima, abastecemos cada posição de "num" 
(usando, para isso, o contador "cont") com o inteiro dadopelo usuário. 
Agora, como usamos esses valores armazenados? Da mesma forma que uma variável 
comum, só que com sintaxe um pouco diferente (veja a linha 3 do nosso programa): 
VAR n : ARRAY[1..10] OF integer;
x : integer;
 BEGIN
 x := n[8]; {x recebe o valor que está na 8ª posição do 
vetor}
 x := n[3] + 2*n[5]; {x recebe o dobro do valor que está na 
5ª posição
 somado ao que está na 3ª posição do 
vetor}
A forma geral da declaração de um vetor é: 
 ARRAY[limite_inferior..limite_superior] OF tipo;
Naturalmente, podemos definir um tipo com o vetor: 
TYPE vetor = ARRAY[1..10] OF integer;
VAR v : vetor;
74
A vantagem desse uso é que posso passar um vetor como parâmetro de uma função ou 
procedimento. Assim, posso fazer: 
 TYPE vetor = ARRAY[1..10] OF integer;
VAR v : vetor;
 PROCEDURE P(x : vetor);
 BEGIN
 ...
 END;
Vale notar que, como na passagem por valor, o valor da variável é copiado para o 
parâmetro, x será um vetor que conterá uma cópia dos valores contidos no vetor a ele 
passado. 
Como isso pode consumir muita memória, se o vetor for grande, é aconselhável efetuar 
a passagem por referência, desse modo: 
TYPE vetor = ARRAY[1..10] OF integer;
VAR v : vetor;
 PROCEDURE P(VAR x : vetor);
 BEGIN
 ...
 END;
Essa, na verdade, é a única maneira de se passar um vetor como parâmetro, já que o 
seguinte não é permitido: 
PROCEDURE P(x : ARRAY[1..10] OF integer;);
BEGIN
 ...
 END;
Da mesma forma, posso usar esse tipo como o retorno de uma função: 
TYPE vetor = ARRAY[1..10] OF integer;
 VAR v : vetor;
 FUNCTION F(x : real) : vetor;
 BEGIN
 ...
 END;
 BEGIN
 v := F(2.3);
 END.
75
enquanto que o mostrado abaixo não é permitido: 
TYPE vetor = ARRAY[1..10] OF integer;
 VAR v : vetor;
 FUNCTION F(x : real) : ARRAY[1..10] OF integer;
 BEGIN
 ...
 END;
 BEGIN
 v := F(2.3);
END.
Atenção: alguns compiladores só aceitam tipos simples como retorno de função, ou 
seja, nem esse artifício acima funciona. Para esses, você não poderá usar funções, terá 
que escrever tudo na forma de precedimentos. 
Vamos agora dar uma olhada no tipo dos dados que um vetor pode conter. Primeiro, que 
tipos são aceitos? Qualquer um! Então, posso ter: 
 TYPE cor = (verde,vermelho,azul);
complexo = RECORD
 re :real;
 im : real
 END;
 vetor1 = ARRAY[1..10] OF cor;
 vetor2 = ARRAY[1..10] OF complexo;
 vetor3 = ARRAY[1..10] OF real;
VAR v1 : vetor1;
 v2 : vetor2;
 v3 : vetor3;
 BEGIN
 {carrego a 2ª posição de v1 com "verde"}
 v1[2] := verde;
 {carrego a 5ª posição de v2 com "3 - 4i"}
 v2[5].re := 3;
 v2[5].im := -4;
 {carrego a 3ª posição de v2 com "2 + 3i"}
 v2[3].re := 2;
 v2[3].im := 3;
 {somo o imaginário da 3ª posição ao da 5ª e guardo na 10ª}
 v2[10].re := v2[5].re + v2[3].re;
 v2[10].im := v2[5].im + v2[3].im;
 {guardo na 1ª posição de v3 o módulo do complexo na posição 
10 de v2}
v3[1] := Sqr(v2[10].re) + Sqr(v2[10].im)
END.
76
Reparou como faço para guardar e usar valores registro que estão dentro de vetores? É 
só fazer 
variável_do_vetor[índice].nome_do_campo
E quanto aos limites do vetor? Bom, esses, na verdade, devem ser um conjunto de 
valores seqüenciais: 
 TYPE limites = 15..20;
 cor = (vermelho, verde, azul);
inferior = 12;
 superior = 15;
 VAR v1 : ARRAY[inferior..superior] OF real;
 v2 : ARRAY[limites] OF integer;
 v3 : ARRAY[cor] OF char;
 v4 : ARRAY['a'..'z'] OF cor;
 v5 : ARRAY['1'..'5'] OF boolean;
e como acessamos ou guardamos valores nos vetores acima? 
 TYPE limites = 15..20;
 cor = (vermelho, verde, azul);
inferior = 12;
 superior = 15;
 VAR v1 : ARRAY[inferior..superior] OF real;
 v2 : ARRAY[limites] OF integer;
 v3 : ARRAY[cor] OF char;
 v4 : ARRAY['a'..'z'] OF cor;
 v5 : ARRAY['1'..'5'] OF boolean;
BEGIN
 v1[14] := 3.16;
 v2[16] := 12;
 v3[verde] := 'a';
 v4['d'] := azul;
v5['3'] := true;
 v1[2] := v1[14] + v2[16] / 5;
v3[azul] := Chr(Ord(v3[verde]) + 3); {terá 'd'}
 v4[v3[verde]] := vermelho; {v4['a'] := vermelho}
v5['2'] := v5['3'] OR v5['5']
END.
Note que os limites não precisam começar de 1. Esses valores são apenas índices, 
podem começar de qualquer valor, desde que o limite inferior seja maior que o superior 
e os valores escolhidos como índices sejam seqüenciais. 
77
Agora, como exemplo do uso de vetores, vamos fazer um programa que conte o número 
de vezes que cada letra foi digitada pelo usuário. O usuário termina o texto com '#'. 
Repare como fazemos para contar cada letra: 
 PROGRAM contador;
 TYPE vetor = ARRAY['A'..'Z'] OF integer;
 VAR ch : char; {o caracter digitado}
 v : vetor; {guarda o número de vezes que cada letra 
foi digitada}
 cont : integer; {contador do FOR}
 {retorna true se c for letra, false se não}
FUNCTION letra(c : char) : boolean;
 BEGIN
 letra := ((c>='a') AND (c<='z')) OR ((c>='A') AND (c<='Z'))
 END;
 BEGIN
 ch := readkey;
 WHILE ch<>'#' DO
BEGIN
 {escrevo o ch na tela}
write(ch);
 {se for letra...}
 IF letra(ch) THEN
 BEGIN
 {transformo em maiúscula}
ch := Upcase(ch);
{conto a letra correta - veja como faço}
 v[ch] := v[ch] + 1
 END;
 {leio o próximo}
 ch := readkey
 END;
 {imprimo o vetor}
writeln('Resultado:');
FOR cont:='A' TO 'Z' DO
 BEGIN
 writeln('v[',cont,'] = ',v[cont])
END
 END.
Ao final desse programa, o vetor v será algo como: 
'A' 'B' 'C' 'D' 'E ' 'F ' 'G' 'H' ' I ' ' J ' 'K ' 'L ' 'M' 'N' 'O' 'P ' 'Q' 'R' 'S ' 'T ' 'U' 'V' 'W' 'X' 'Y' 'Z '
100 20 10 5 7 6 12 3 43 23 6 7 54 3 6 0 23 65 23 1 9 57 0 12 5 0
78
Ou seja, cada índice contém, em seu elemento correspondente no vetor, o número de 
vezes que a letra do índice foi digitada no texto. 
Vejamos outro exemplo, a coidificação de um texto. Nesse exemplo, o usuário digita 
um caracter e, se este for letra, nós o codificamos conforme a seguinte chave: 
Caracter Código Caracter Código
'A' 'C' 'N' 'K'
'B' 'Z' 'O' 'L'
'C' 'O' 'P' 'S'
'D' 'R' 'Q' 'E'
'E' 'A' 'R' 'H'
'F' 'G' 'S' 'M'
'G' 'B' 'T' 'P'
'H' 'N' 'U' 'I'
'I' 'U' 'V' 'X'
'J' 'T' 'W' 'Q'
'K' 'D' 'X' 'V'
'L' 'Y' 'Y' 'J'
'M' 'F' 'Z' 'W'
Queremos, então, um programa que leia o caracter digitado pelo usuário, o substitua 
pelo caracter do código e escreva este último, mostrando ao usuário. Novamente, 
façamos o texto ser terminado por '#'. 
 PROGRAM codigo;
 TYPE vetor = ARRAY['A'..'Z'] OF integer;
VAR ch : char; {o caracter digitado}
 chave : vetor; {guarda a chave do código}
 {retorna true se c for letra, false se não}
FUNCTION letra(c : char) : boolean;
 BEGIN
 letra := ((c>='a') AND (c<='z')) OR ((c>='A') AND (c<='Z'))
END;
 {retorna true se c for letra maiuscula}
FUNCTION maiuscula(c : char) : boolean;
 BEGIN
 maiuscula := letra(c) AND (c >= 'A') AND (c <= 'Z')
END;
 {retorna a correspondente minúscula de c}
FUNCTION mai_para_min(c : char) : char;
 BEGIN
 IF maiuscula(c) THEN mai_para_min := Chr(Ord(c) - Ord('A') 
+ Ord('a'))
ELSE mai_para_min := c
79
 END;
 {inicializa a chave}
PROCEDURE inicializa(c : vetor);
 BEGIN
 v['A'] := 'C';
 v['B'] := 'Z';
 v['C'] := 'O';
 v['D'] := 'R';
 v['E'] := 'A';
 v['F'] := 'G';
 v['G'] := 'B';
 v['H'] := 'V';
 v['I'] := 'U';
 v['J'] := 'T';
 v['K'] := 'D';
 v['L'] := 'Y';
 v['M'] := 'F';
 v['N'] := 'K';
 v['O'] := 'L';
 v['P'] := 'S';
 v['Q'] := 'E';
 v['R'] := 'H';
 v['S'] :='M';
 v['T'] := 'P';
 v['U'] := 'I';
 v['V'] := 'X';
 v['W'] := 'Q';
 v['X'] := 'V';
 v['Y'] := 'J';
 v['Z'] := 'W'
 END;
 BEGIN
 ch := readkey;
 WHILE ch<>'#' DO
 BEGIN
 IF letra(ch) THEN
 BEGIN
 IF maiuscula(ch) THEN write(v[ch])
ELSE {é minúscula}
 write(mai_para_min(v[Upercase(ch)]))
 END
ELSE {não é letra}
 write(ch);
 {leio a próxima}
 ch := readkey
 END
 END.
Estude bem esse programa. 
MATRIZES 
80
Vetores também podem ser usados para representar matrizes. Considere a matriz: 
[ 1 23 4 ]
Seria interessante podermos representar isso, não? Como faríamos? Podemos criar um 
vetor de vetores: 
TYPE coluna = ARRAY[1..2] OF integer;
matriz = ARRAY[1..2] OF coluna;
e como abasteceríamos a matriz nessa estrutura de dados? 
TYPE coluna = ARRAY[1..2] OF integer;
matriz = ARRAY[1..2] OF coluna;
 VAR m : matriz;
BEGIN
 m[1][1] := 1;
 m[1][2] := 2;
 m[2][1] := 3;
 m[2][2] := 4
 END.
Bastante truculento, não é? Bem, felizmente o Pascal tem um modo mais fácil de 
representar uma matriz: 
TYPE matriz = ARRAY[1..2,1..2] OF integer;
VAR m : matriz;
 BEGIN
 m[1,1] := 1;
 m[1,2] := 2;
 m[2,1] := 3;
 m[2,2] := 4
 END.
Simples, não? Nós agora representamos uma matriz 2 × 2. Considere agora a matriz 3 × 
3: 
A = [
1 2 3
4 5 6
7 8 9
]
Como podemos representá-la em Pascal? 
81
TYPE matriz = ARRAY[1..3,1..3] OF integer;
VAR A : matriz;
 BEGIN
 A[1,1] := 1;
 A[1,2] := 2;
 A[1,3] := 3;
 A[2,1] := 4;
 A[2,2] := 5;
 A[2,3] := 6;
 A[3,1] := 7;
 A[3,2] := 8;
 A[3,3] := 9
 END.
Note que a prepresentação do elemento Ai,j é A[i,j]. Realmente mnemônico. 
Como representamos agora uma matriz 3 × 2, como a abaixo? 
A = [
1 2
3 4
5 6
]
Assim: 
 TYPE matriz = ARRAY[1..3,1..2] OF integer;
VAR A : matriz;
 BEGIN
 A[1,1] := 1;
 A[1,2] := 2;
 A[2,1] := 3;
 A[2,2] := 4;
 A[3,1] := 5;
 A[3,2] := 6
 END.
E a 2 × 3 abaixo? 
A = [ 1 2 34 5 6 ]
Assim: 
 TYPE matriz = ARRAY[1..2,1..3] OF integer;
VAR A : matriz;
82
 BEGIN
 A[1,1] := 1;
 A[1,2] := 2;
 A[1,3] := 3;
 A[2,1] := 4;
 A[2,2] := 5;
 A[2,3] := 6
 END.
Agora podemos criar funções para soma e multiplicação de matrizes: 
 PROGRAM matrizes;
 TYPE matriz = ARRAY[1..2,1..2] OF integer;
 VAR m1,m2,m3 :matriz;
 FUNCTION soma(m1,m2:matriz) : matriz;
 BEGIN
 soma[1,1] := m1[1,1] + m2[1,1];
 soma[1,2] := m1[1,2] + m2[1,2];
 soma[2,1] := m1[2,1] + m2[2,1];
soma[2,2] := m1[2,2] + m2[2,2]
 END;
 BEGIN
 m1[1,1] := 1;
m1[1,2] := 2;
 m1[2,1] := 3;
 m1[2,2] := 4;
 m2[1,1] := 5;
 m2[1,2] := 6;
 m2[2,1] := 7;
L A Ç O S A N I N H A D O S 
 m3 := soma(m1,m2);
writeln(m3[1,1],' ',m3[1,2],' ',m3[2,1],' ',m3[2,2])
END.
Novamente, alguns compiladores podem não aceitar isso, então, uma versão alternativa 
com procedimentos é: 
 PROGRAM matrizes;
 TYPE matriz = ARRAY[1..2,1..2] OF integer;
 VAR m1,m2,m3 :matriz;
 PROCEDURE soma(m1,m2:matriz; VAR m3:matriz);
BEGIN
 m3[1,1] := m1[1,1] + m2[1,1];
 m3[1,2] := m1[1,2] + m2[1,2];
m3[2,1] := m1[2,1] + m2[2,1];
 m3[2,2] := m1[2,2] + m2[2,2]
 END;
83
 BEGIN
m1[1,1] := 1;
 m1[1,2] := 2;
 m1[2,1] := 3;
 m1[2,2] := 4;
 m2[1,1] := 5;
 m2[1,2] := 6;
 m2[2,1] := 7;
 m2[2,2] := 8;
 soma(m1,m2,m3);
writeln(m3[1,1],' ',m3[1,2],' ',m3[2,1],' ',m3[2,2])
END.
as funções para subtração, multiplicação e divisão ficam como exercício. 
Então, como vimos, matrizes nada mais são que vetores em 2 dimensões. Mas, será que 
posso fazer em 3 dimensões? Posso fazer em quantas eu quiser... 
 PROGRAM matrizes;
 TYPE matriz3D = ARRAY[1..2,1..2,1..2] OF integer;
 matriz5D = ARRAY[1..3,1..5,1..2,1..2,1..1] of integer;
 etc
E como acesso valores nessas matrizes? 
 PROGRAM matrizes;
 TYPE matriz3D = ARRAY[1..2,1..2,1..2] OF 
integer;
 matriz5D = 
ARRAY[1..3,1..5,1..2,1..2,1..1] of integer;
 VAR m1 : matriz3D;
 m2 : matriz5D;
 BEGIN
 m1[1,2,1] := 3;
 m2[1,1,3,2,1] := 5;
 etc...
 END.
Quando você usará isso? Não sei, mas se precisar... 
Por fim, como fazemos para ler todos os valores de uma matriz n × m, dados n e m, e 
imprimí-los na tela? (Suponha que ela já está carregada) 
 PROGRAM matrizes;
84
 CONST n = 20;
 m = 30;
 TYPE matriz = ARRAY[1..n,1..m] OF integer;
 VAR mat : matriz; {a matriz}
 cont1 : integer; {contador do primeiro FOR}
 cont2 : integer; {contador do segundo FOR}
BEGIN
 FOR cont1:=1 TO n DO
 FOR cont2:=1 TO m DO 
writeln('mat[',cont1,',',cont2,'] = ',mat[cont1,cont2])
END.
E para "zerarmos" uma matriz n × m? 
 PROGRAM matrizes;
 CONST n = 20;
 m = 30;
 TYPE matriz = ARRAY[1..n,1..m] OF integer;
 VAR mat : matriz; {a matriz}
 cont1 : integer; {contador do primeiro FOR}
 cont2 : integer; {contador do segundo FOR}
BEGIN
 FOR cont1:=1 TO n DO
 FOR cont2:=1 TO m DO mat[cont1,cont2] := 0
END.
Simples, não? Apenas 2 FORs. Na verdade, você deve usar um FOR para cada 
dimensão do vetor. Como uma matriz é um vetor em 2 dimensões, usamos 2 FORs, se
tivesse k dimensões, teríamos que usar k FORs. 
BUSCA BINÁRIA 
Suponha que temos um vetor ordenado, com n elementos, e queremos verificar se um 
dado elemento, x, está nesse vetor. Como faríamos? 
A primeira idéia é comparar x a todo elemento do vetor. Mas isso é lento, pois temos 
que fazer n comparações, onde n é o número de elementos do vetor. 
Podemos usar do fato do vetor estar ordenado para reduzir o tempo de busca. Considere 
o algoritmo: 
 1. Seja y0 o 1º elemento do vetor e y1 o último.
85
 2. Seja y o elemento do meio do vetor, ou seja, y = 
(y0 + y1) DIV 2.
 3. Comparo x com y e, se x > y, então x está na 
metade superior do vetor.
 Nesse caso faço y0 = y + 1 e volto a 2.
 Se y0 = y1, x não está no vetor.
 4. Se x < y, x está na metade inferior. Então faço y1
= y - 1 e volto a 2.
 Se y0 = y1, x não está no vetor.
 5. Se x = y, achei. y0 = y1, x não está no vetor.
Notou como é mais rápido? Não comparo com todos, apenas com alguns. Vejamos um 
exemplo: suponha que queremos saber seo 27 está no vetor abaixo: 
1 2 3 4 5 6 7 8
1 5 8 9 12 15 27 30
vamos rodar o algoritmo: 
1: y0 = 1 e y1 = 8 
2: y = 4 
3: como 27 > 4, ignoro a 1ª metade do vetor, fazendo y0 = 5. Ou seja, nosso vetor ficou: 
5 6 7 8
12 15 27 30
2: y = 6 
3: como 27 > 15, ignoro a 1ª metade do novo vetor, fazendo y0 = 7. Nosso vetor ficou: 
7 8
27 30
2: y = 7 
3: falhou, pois 27 não é > 27 
4: falhou, pois 27 não é < 27 
5: como 27 = 27, achei. 
Agora vamos procurar o número 7: 
1 2 3 4 5 6 7 8
86
1 5 8 9 12 15 27 30
1: y0 = 1 e y1 = 8 
2: y = 4 
3: falha, pois 7 não é > 9 
4: Como 7 < 9, ignoro a 2ª metade do vetor, fazendo y1 = 3. Nosso vetor fica: 
1 2 3
1 5 8
2: y = 2 
3: como 7 > 5, ignoro a 1ª metade do vetor, fazendo y0 = 3. Nosso vetor fica: 
3
8
2: y = 3 
3: falha, pois 7 não é > 8. 
4: 7 < 8, mas como y0 = y1, então 7 não está no vetor. 
Agora, vamos estruturar mais nosso algoritmo: 
 Seja y0 o 1º elemento do vetor, V, e y1 o último.
 Seja y o elemento do meio do vetor, ou seja, y = 
(y0 + y1) DIV 2.
enquanto x 0 < y1
 se x > V[y] faço y0 = y + 1
 senão
 se x < V[y] faço y1 = y - 1
 faço y = (y0 + y1) DIV 2
se x = V[y] achei
 senão não achei
Em Pascal isso fica: (Suponha que o vetor já foi carregado com os valores) 
CONST MAX = 8;
 VAR v : ARRAY[1..MAX] OF integer;
y0 : integer;
 y1 : integer;
87y : integer;
x : integer;
 BEGIN
 {carreguei o vetor...}
{começo o algoritmo}
 y0 := 1;
 y1 := MAX;
 y := (y0 + y1) DIV 2;
 write('Entre o inteiro a ser buscado: ');
readln(x);
 WHILE (x <> v[y]) AND (y0 < y1) DO
 BEGIN
 IF x > v[y] THEN {parte superior}
y0 := y + 1
 ELSE
 IF x < v[y] THEN y1 := y - 1;
 y := (y1 + y0) DIV 2
 END;
 IF x = v[y] THEN writeln('encontrado na posição: 
',y)
ELSE writeln('elemento não encontrado no vetor)
 END.
O nome dessa busca é busca binária, pois, a cada passo, jogo fora metade do vetor em 
que estou trabalhando. 
88
REGISTROS 
Registros são variáveis que podem guardar mais de um dado, inclusive de tipos 
diferentes. Por exemplo, suponha que queremos trabalhar com datas, no formato dia, 
mês e ano. Como faríamos? Uma alternativa é transformar nossa data em dias (ou meses 
ou anos) e então, após termos trabalhado com ela, transformar novamente para dia, mês 
e ano. Trabalhoso, não? Seria muito mais fácil se pudéssemos trabalhar no formato dia, 
mês e ano. Como fazemos isso? 
 TYPE meses = (jan, fev, mar, abr, 
mai, jun, jul, ago, set, out, nov, 
dez);
dias = 1..31;
 VAR data : RECORD
 dia : dias;
 mes : meses;
 ano : integer
 END;
Aqui definimos uma variável do tipo "data", que é um registro composto de 3 campos: 
dia, do tipo "dias"; mes, do tipo "meses" e ano, do tipo integer. 
Assim, quando temos várias variáveis que dizem respeito à mesma coisa, as agrupamos 
em um registro. 
Também, podemos criar um tipo com registros: 
TYPE meses = (jan, fev, mar, abr, 
mai, jun, jul, ago, set, out, nov, 
dez);
dias = 1..31;
 datas = RECORD
 dia : dias;
 mes : meses;
 ano : integer
 END;
 VAR data : datas
Como sempre esse segundo enfoque é melhor, pois se precisarmos passar uma data 
como parâmetro de função ou procedimento ou como retorno de função fazemos 
PROCEDURE Q(d : datas);
 FUNCTION F1(l : datas) : boolean;
FUNCTION F2(l : datas) : datas;
uma vez que o seguinte não é permitido 
89
 PROCEDURE Q(d : RECORD dia : dias; mes : meses; ano : 
integer END;);
 FUNCTION F1(l : RECORD dia : dias; mes : meses; ano : 
integer END;) : boolean;
 FUNCTION F2(l : RECORD dia : dias; mes : meses; ano : 
integer END;) :
 RECORD dia : dias; mes : meses; ano : integer END;
Como foi dito, os campos de um registro podem ser de qualquer tipo, inclusive outro 
registro. 
A forma geral de um registro é: 
RECORD
 campo1 : tipo1;
 campo2 : tipo2;
 campo3 : tipo1;
 ...
 campon : tipon
 END;
Voltando à nossa data, como carregamos um valor na nossa variável? O segmento a 
seguir inicializa data com 26 de outubro de 2002: 
data.dia := 26;
 data.mes := out;
data.ano := 2002;
Ou seja, acessamos o campo de uma variável do tipo record fazendo: 
 nome_da_variável.campo
E para ler o valor de um registro? Fazemos da mesma forma que atribuímos, o conjunto 
nome_da_variável.campo pode ser usado como uma variável comum de tipo igual ao 
tipo do campo: 
PROGRAM P;
 TYPE meses = (jan, fev, mar, abr, mai, jun, jul, ago, set, out, 
nov, dez);
dias = 1..31;
 datas = RECORD
 dia : dias;
 mes : meses;
 ano : integer
 END;
 VAR data : datas;
90
BEGIN
 data.dia := 26;
 data.mes := out;
 data.ano := 2002;
 write(data.dia,'/',Ord(data.mes)+1,'/',data.ano);
 IF data.ano>0 THEN writeln(' d.C.')
 ELSE writeln(' a.C.')
END.
O programa acima escreve "26/10/2003 d.C.". Viu? Podemos usar o conjunto 
nome_da_variável.campo como variáveis comuns. 
Um outro detalhe, como o campo "ano" é integer, ele é tratado como integer: 
PROGRAM P;
 TYPE meses = (jan, fev, mar, abr, mai, jun, jul, ago, 
set, out, nov, dez);
dias = 1..31;
 datas = RECORD
 dia : dias;
 mes : meses;
 ano : integer
 END;
 VAR data : datas;
FUNCTION quad(x : integer) : integer;
 BEGIN
 quad := x*x
 end;
 BEGIN
 data.dia := 26;
 data.mes := out;
 data.ano := 2002;
 write(data.dia,'/',Ord(data.mes)+1,'/',data.ano);
 IF data.ano>0 THEN writeln(' d.C.')
 ELSE writeln(' a.C.');
data.ano := quad(data.ano) {data.ano recebe 4008004 
(2002 × 2002)}
 END.
Vejamos alguns exemplos: 
Somar tempos: suponha que tenhamos dois tempos no formato hora, minuto e 
seguindo e queiramos somá-los, dando a resposta em hora, minuto e segundos, como 
faremos? 
Primeiro criamos um registro para o tempo: 
91
 TYPE tempo = RECORD
 hora : integer;
min : word;
 seg : word
 END;
Quem é esse word? Word é um tipo inteiro do Pascal, que vai de 0 a 65535. 
Agora, fazemos o programa: 
 PROGRAM P;
 TYPE tempo = RECORD
 hora : integer;
min : word;
 seg : word
 END;
VAR t1 : tempo;
 t2 : tempo;
t3 : tempo;
 BEGIN
 write('hora: ');
 readln(t1.hora);
 write('minuto: ');
 readln(t1.min);
 write('segundo: ');
 readln(t1.seg);
 write('hora: ');
 readln(t2.hora);
 write('minuto: ');
 readln(t2.min);
 write('segundo: ');
readln(t2.seg);
 {calculo o número total de segundos}
t3.seg := t1.seg + t2.seg;
{calculo a soma dos minutos mais o número de 
segundos que virou minuto}
t3.min := t1.min + t2.min + t3.seg DIV 60;
{somo as horas mais o número de minutos que 
virou hora}
 t3.hora := t1.hora + t2.hora + t3.min DIV 60;
 {como seg não pode ser >60, guardo a parte 
menor, pois o resto
 transformei em min}
 t3.seg := t3.seg MOD 60;
 {como min não pode ser >60, guardo a parte 
menor, pois o resto
 transformei em hora}
 t3.min := t3.min MOD 60;
 {escrevo o resultado}
92
 writeln(t3.hora,':',t3.min,':',t3.seg)
Agora, e se quisermos fazer uma função que retorne a soma? Como definimos um tipo 
com o RECORD, podemos fazer tal função: 
 PROGRAM P;
 TYPE tempo = RECORD
 hora : integer;
min : word;
 seg : word
 END;
VAR t1 : tempo;
 t2 : tempo;
 t3 : tempo;
 FUNCTION soma(t1,t2:tempo) : tempo;
 BEGIN
 {calculo o número total de segundos}
soma.seg := t1.seg + t2.seg;
{calculo a soma dos minutos mais o número de segundos que 
virou minuto}
soma.min := t1.min + t2.min + soma.seg DIV 60;
{somo as horas mais o número de minutos que virou hora}
 soma.hora := t1.hora + t2.hora + soma.min DIV 60;
 {como seg não pode ser >60, guardo a parte menor, pois o 
resto
 transformei em min}
 soma.seg := soma.seg MOD 60;
 {como min não pode ser >60, guardo a parte menor, pois o 
resto
 transformei em hora}
 soma.min := soma.min MOD 60
END;
 BEGIN
 write('hora: ');
 readln(t1.hora);
 write('minuto: ');
 readln(t1.min);
 write('segundo: ');
 readln(t1.seg);
 write('hora: ');
 readln(t2.hora);
 write('minuto: ');
 readln(t2.min);
 write('segundo: ');
 readln(t2.seg);
 t3 := soma(t1,t2);
{escrevo o resultado}
 writeln(t3.hora,':',t3.min,':',t3.seg)
93
Vale lembrar que nem todos os compiladores aceitam tipos assim como retorno de uma 
função. Para esses compiladores, uma saída é definir um procedimento: 
 PROGRAM P;
 TYPE tempo = RECORD
 hora : integer;
min : word;
 seg : word
 END;
VAR t1 : tempo;
 t2 : tempo;
 t3 : tempo;
 PROCEDURE soma(t1,t2:tempo; VAR t3:tempo);
 BEGIN
 {calculo o número total de segundos}
t3.seg := t1.seg + t2.seg;
{calculo a soma dos minutos mais o número de segundos quevirou minuto}
t3.min := t1.min + t2.min + t3.seg DIV 60;
{somo as horas mais o número de minutos que virou hora}
 t3.hora := t1.hora + t2.hora + t3.min DIV 60;
 {como seg não pode ser >60, guardo a parte menor, pois o 
resto
 transformei em min}
 t3.seg := t3.seg MOD 60;
 {como min não pode ser >60, guardo a parte menor, pois o 
resto
 transformei em hora}
 t3.min := t3.min MOD 60
END;
 BEGIN
 write('hora: ');
 readln(t1.hora);
 write('minuto: ');
 readln(t1.min);
 write('segundo: ');
 readln(t1.seg);
 write('hora: ');
 readln(t2.hora);
 write('minuto: ');
 readln(t2.min);
 write('segundo: ');
 readln(t2.seg);
 soma(t1,t2,t3);
{escrevo o resultado}
 writeln(t3.hora,':',t3.min,':',t3.seg)
94
Números complexos: Sabemos que um número complexo possui sua parte real e 
imaginária. Assim, em (2+3i), 2 é a real e 3 a imaginária. 
Como podemos, então, fazer procedimentos ou funções que executem as quatro 
operações em complexos? Antes de mais nada, vamos definir um tipo complexo: 
 TYPE complexo = RECORD
 re : real;
im : real
 END;
Agora, vejamos como são calculadas as 4 operações: 
(a + bi) + (c + di) = (a + c) + (b + d)i
 (a + bi) - (c + di) = (a - c) + (b - d)i
 (a + bi) × (c + di) = (ac - db) + (bc + ad)i
 (a + bi) ÷ (c + di) = (ac + bd)/(c² + d²) + 
((cb - ad)/(c² + d²))i
Vejamos como ficam a soma e a multiplicação. A subtração e a divisão ficam como 
exercício para você. 
 PROGRAM P;
 TYPE complexo = RECORD
 re : real;
 im : real
 END;
 VAR n1, n2, n3 : complexo;
 FUNCTION soma(n1,n2:complexo) : complexo;
 BEGIN
 soma.re := n1.re + n2.re;
 soma.im := n1.im + n2.im
END;
 FUNCTION mult(n1,n2:complexo) : complexo;
 BEGIN
mult.re := n1.re*n2.re - n1.im*n2.im;
 mult.im := n1.im*n2.re + n1.re*n2.im
END;
 BEGIN
 {faço n1 := 2 + 3i}
n1.re := 2;
 n1.im := 3;
 {faço n2 := 4 - 2.3i}
 n2.re := 4;
 n2.im := 2.3;
 n3 := soma(n1,n2);
 writeln(n3.re,' + ',n3.im,'i'); {escreve 6 + 0.7i}
95
 n3 := mult(n1,n2);
 writeln(n3.re,' + ',n3.im,'i') {escreve 14.9 + 7.4i}
 END.
Observações: 
Comparação entre registros: No caso dos números complexos, como faço para 
verificar se um complexo é igual a outro? Infelizmente não há como fazer isso em 
Pascal: 
 TYPE complexo = RECORD
 re : real;
 im : real
 END;
 VAR t1,t2 : complexo;
BEGIN
 {abasteço t1 com 2-3i}
 t1.re := 2;
 t1.im := -3;
 {abasteço t2 com 4+2.3i}
t2.re := 4;
 t2.im := 2.3;
 IF t1 = t2 THEN
{faz algo}
 END.
Como fazemos para testar registros então? Testamos campo a campo: 
 TYPE complexo = RECORD
 re : real;
 im : real
 END;
 VAR t1,t2 : complexo;
BEGIN
 {abasteço t1 com 2-3i}
 t1.re := 2;
 t1.im := -3;
 {abasteço t2 com 4+2.3i}
t2.re := 4;
 t2.im := 2.3;
 IF (t1.re = t2.re) AND (t1.im = t2.im) THEN
{faz algo}
 END.
Pronto. Testado. 
96
Registro dentro de registros: Vejamos agora, um exemplo de registro dentro de 
registro. Suponha que teremos que trabalhar com uma estrutura que deve conter uma 
data e um horário. O horário é algo assim: 
 TYPE horario = RECORD
 hora : integer;
 min : word;
seg : word
 END;
Então, nossa estrutura seria algo assim: 
TYPE horario = RECORD
 hora : integer;
 min : word;
 seg : word
 END;
 TYPE data = RECORD
dia : 0..31;
 mes : 1..12;
 ano : integer
 END;
 TYPE tempo = RECORD
 dia : data;
 hora : horario
 END;
Note que posso por nomes duplicados de campos (como "dia" e "hora"), desde que 
pertençam a registros diferentes. 
Agora, como fazemos para armazenar uma data? E para ler? 
 TYPE horario = RECORD
 hora : 0..23;
 min : 0..60;
 seg : 0..60
 END;
TYPE data = RECORD
 dia : 0..31;
 mes : 1..12;
 ano : integer
 END;
 TYPE tempo = RECORD
 dia : data;
 hora : horario
 END;
 VAR t : tempo;
 BEGIN
 {vou armazenar 12 de janeiro de 2002, 14h:05':30''}
 t.dia.dia := 12;
97
 t.dia.mes := 1;
 t.dia.ano := 2002;
 t.hora.hora := 14;
 t.hora.min := 5;
 t.hora.seg := 30;
 {imprimo "12/1/2001 - 14:5:30"}
 writeln(t.dia.dia,'/',t.dia.mes,'/',t.dia.ano,' -
',t.hora.hora,':',t.hora.min,':',t.hora.seg)
 END.
Viu como funciona? Ao fazer t.dia estou acessando o campo "dia" do registro "t". Mas 
esse campo, por sua vez, é um registro também, então, não posso acessá-lo diretamente, 
tenho que acessar seus registros. Assim, para acessar o campo "mes" do registro 
correspondente ao campo "dia" do registro "t" faço "t.dia.mes". 
98
TIPOS ENUMERADOS 
Suponha que tenhamos uma variável que só possa assumir um dentre um conjunto de 
valores. Por exemplo, suponha que estejamos criando um registro de pessoas que 
conhecemos para, por exemplo, fazer um programa que nos lembre de seus aniversários. 
Assim, cada pessoa ou é parente, ou amigo. Então, como marcaríamos se a pessoa é um 
ou outro? Poderíamos associar a cada pessoa uma variável booleana que assumisse true 
se a pessoa é parente e false se é amigo. Isso funcionaria. Mas, e se, além desses, 
quisermos incluir os colegas, ou seja, a pessoa ou é parente, ou amigo, ou colega? 
Poderíamos associar um número a cada tipo de pessoa: 0 para parente, 1 para colega e 2 
para amigo, ou seja, construímos a tabela: 
Código Tipo
0 Parente 
1 Colega 
2 Amigo 
Nada mnemônico, não é mesmo? Será que há como fazer melhor? Há. Podemos criar 
um tipo enumerado: 
 TYPE pessoa = (parente, amigo, colega);
 VAR p : pessoa;
Aqui criamos um tipo, chamado pessoa, que aceita apenas um dos valores da lista e, em 
seguida, declaramos uma variável desse tipo. Como fazemos para abastecer um valor 
nessa variável? 
 BEGIN
 p := amigo;
 p := parente;
 p := colega;
 p := conhecido {erro de compilação}
 END.
De fato, o compilador representa esses 3 valores como 0, 1 e 2. Exatamente como nossa 
tabela acima. A vantagem do uso de enumerações é que, além do código ficar 
mnemônico, ele ocupa menos espaço na memória pois, para guardar 0, 1 e 2 na 
memória 1 byte é suficiente, enquanto que para guardar um inteiro são necessários de 4 
a 8 bytes, dependendo da máquina. 
Naturalmente, não podemos declarar nada com os nomes dos valores usados na lista, 
pois eles são tidos como identificadores. Se tentarmos declarar algo com o mesmo nome 
o compilador acusará um erro. Por exemplo, o programa a seguir está errado: 
99
 TYPE estado = (estudante, faculdade, docente); {certo}
 naoAdministrativo = (estudante, professor); {declaração 
duplicada de "estudante"}
 VAR faculdade : estado; {declaração duplicada de 
"faculdade"}
 BEGIN
 estudante := 2; {estudante não é variável, é valor}
 END.
Veja que não precisamos, de fato, criar uma enumeração para obter o resultado, 
bastaríamos criar constantes. Por exemplo, o seguinte programa tem o mesmo efeito do 
programa inicialmente desenvolvido: 
 CONST parente = 0;
 amigo = 1;
colega = 2;
 VAR p : integer;
 BEGIN
 p := amigo;
 p := parente;
 p := colega;
 p := conhecido {erro de compilação}
 END.
Mas, apesar disso, a vantagem de usar enumerações é que estou atrelando os valores ao 
tipo da variável. Por exemplo, em: 
 TYPE pessoa = (parente, amigo, colega);
 VAR p : pessoa;
sóposso por "q := parente" se "q" for do tipo "pessoa". 
Devido ao modo como o Pascal representa as listas enumeradas (mostrado acima), os 
valores nestas são ordenados. Assim, no nosso exemplo, parente < amigo < colega. 
Esses valores, justamente por serem ordenados, podem ser usados dentro de um FOR: 
 FOR p:=parente TO colega DO
 ou
 FOR p:=colega DOWNTO parente DO
100
PRED E SUCC 
Como fazemos se quisermos determinar o predecessor e o sucessor de um tipo 
enumerado? Usamos Pred e Succ. Considere o exemplo: 
 TYPE digitos = (zero, um, dois, tres, quatro, cinco, 
seis, sete, oito, nove);
 cores = (azul, vermelho, verde);
 VAR x : digitos;
y : digitos;
 c : cores;
 z : cores;
BEGIN
 y := dois;
 x := Pred(y); {x recebe "um"}
y := Succ(y); {y recebe "tres"}
c := Pred(verde); {c recebe "vermelho"}
 z := Succ(c); {z recebe "verde"}
 END.
Essas funções não trabalham só com tipos enumerados, mas também com qualquer tipo 
escalar que seja ordenado, exceto real. Assim: 
 VAR x : integer;
 a : boolean;
 BEGIN
x := Pred(6); {x recebe 5}
 a := Succ(false) {a recebe "true"}
 END.
Mas, e se eu estiver no limite? Ou seja, quanto valem Pred(zero) ou Succ(nove) no 
exemplo acima? Bom, esses valores não estão definidos, ou seja, darão erro. 
Agora, suponha que temos uma lista enumerada e queremos saber a posição de cada 
valor na lista: 
 TYPE pessoa = (parente, amigo, colega);
 VAR p : pessoa;
 x : integer;
BEGIN
 x := Ord(amigo); {x recebe 1}
END.
Isso mesmo! Ord serve também para dar a posição de determinado valor em uma lista 
enumerada. Assim, podemos imprimir a tabela criada pelo computador da seguinte 
maneira: 
101
 TYPE pessoa = (parente, amigo, colega);
 VAR p : pessoa;
 x : integer;
BEGIN
 FOR p:= parente TO colega DO
 write(Ord(p),' ')
END.
Esse programa imprime: 
 0 1 2
102
O COMANDO CASE 
Suponha que, em um determinado programa, temos a seguinte interface 
 Escolha um planeta:
 (M)ercúrio
 (V)ênus
 (T)erra
 M(a)rte
 (J)úpiter
 (S)aturno
 (U)rano
 (N)etuno
 (P)lutão
 Sua escolha:
e queremos processar aentrada, ou seja, ler o caracter do usuário (que pode ser 
maiúsculo ou minúsculo) e abastecer uma variável com a gravidade do planeta 
escolhido. Como fazemos isso? Até agora teríamos que fazer: 
 PROGRAM Planetas;
 VAR g : real; {a gravidade}
 p : char; {o planeta escolhido}
 {mostra a interface e devolve a letra digitada}
FUNCTION interface : char;
 BEGIN
 writeln('Escolha um planeta:');
 writeln(' (M)ercúrio');
 writeln(' (V)ênus');
 writeln(' (T)erra');
 writeln(' M(a)rte');
 writeln(' (J)úpiter');
 writeln(' (S)aturno');
 writeln(' (U)rano');
 writeln(' (N)etuno');
 writeln(' (P)lutão');
write('Sua escolha: ');
 readln(interface)
END;
 BEGIN
 p := interface;
 IF (p='m') OR (p='M') THEN g := 1 {valor fictício}
 ELSE
 IF (p='v') OR (p='V') THEN g := 2
 ELSE
 IF (p='t') OR (p='T') THEN g := 3
ELSE
 IF (p='a') OR (p='A') THEN g := 4
 ELSE
 IF (p='j') OR (p='J') THEN g := 5
 ELSE
 IF (p='s') OR (p='S') THEN g := 6
 ELSE
103
 IF (p='u') OR (p='U') THEN g := 7
ELSE
 IF (p='n') OR (p='N') THEN g := 8
 ELSE
 IF (p='p') OR (p='P') THEN g := 9
 ELSE writeln('planeta não existente')
 END.
Deve haver um modo melhor de fazer isso não? E tem: 
 PROGRAM Planetas;
 VAR g : real; {a gravidade}
 p : char; {o planeta escolhido}
 {mostra a interface e devolve a letra digitada}
FUNCTION interface : char;
 BEGIN
 writeln('Escolha um planeta:');
 writeln(' (M)ercúrio');
 writeln(' (V)ênus');
 writeln(' (T)erra');
 writeln(' M(a)rte');
 writeln(' (J)úpiter');
 writeln(' (S)aturno');
 writeln(' (U)rano');
 writeln(' (N)etuno');
 writeln(' (P)lutão');
write('Sua escolha: ');
 readln(interface)
END;
 BEGIN
 p := interface;
 CASE p OF
 'm' : g := 1;
 'v' : g := 2;
 't' : g := 3;
'a' : g := 4;
 'j' : g := 5;
 's' : g := 6;
 'u' : g := 7;
 'n' : g := 8;
'p' : g := 9
 else writeln('Planeta inexistente')
 END
END.
Simples não? Assim o case permite testar se uma expressão é um de vários valores. Se 
nenhum dos valores for igual ao da expressão, o ELSE é ativado. Vale lembrar que, 
como no IF, esse ELSE é totalmente opcional, se o omitirmos e o usuário digitar uma 
letra não prevista, o programa simplesmente sai do CASE, passando à próxima linha de 
programa. 
Mas note que nosso programa acima aceita somente letras minúsculas. E se o usuário 
digitar M? O programa dará a mensagem de "Planeta inexistente".Como fazemos para 
104
resolver isso? Uma solução é transformar tudo em minúscula antes de testar, outra é 
usar o CASE para testar as maiúsculas também: 
 PROGRAM Planetas;
 VAR g : real; {a gravidade}
 p : char; {o planeta escolhido}
 {mostra a interface e devolve a letra digitada}
FUNCTION interface : char;
 BEGIN
 writeln('Escolha um planeta:');
 writeln(' (M)ercúrio');
 writeln(' (V)ênus');
 writeln(' (T)erra');
 writeln(' M(a)rte');
 writeln(' (J)úpiter');
 writeln(' (S)aturno');
 writeln(' (U)rano');
 writeln(' (N)etuno');
 writeln(' (P)lutão');
write('Sua escolha: ');
 readln(interface)
END;
 BEGIN
 p := interface;
 CASE p OF
 'm','M' : g := 1;
 'v','V' : g := 2;
 't','T' : g := 3;
 'a','A' : g := 4;
 'j','J' : g := 5;
 's','S' : g := 6;
'u','U' : g := 7;
 'n','N' : g := 8;
'p','P' : g := 9
 else writeln('Planeta inexistente')
 END
END.
Viu como fazemos um OU dentro do CASE? Com "," separando as opções. 
Assim, a forma geral do CASE é: 
 CASE expressão OF
 valor1 : comando1;
 valor2, valor3 : comando2;
 ...
 valorn : comandon
 else comandom
 END;
Agora, algumas observações sobre o CASE; 
? Expressão pode ser qualquer expressão, variável, ou chamada de função. 
105
? Comando é um único comando, ou chamada a um procedimento. 
? Se quisermos por mais de um comando no CASE devemos fazer: 
 CASE expressão OF
 valor1 : BEGIN
 comando1;
 comando2;
 ...
 comandon
END;
 valor2, valor3 : BEGIN
 comandoj;
 ...
 comandol;
 END;
 ...
 valorn : comandom
 END;
? mas isso não é considerado boa programação, pois não gera um código limpo. O 
ideal é que criemos procedimentos: 
 PROCEDURE P1
 BEGIN
 comando1;
 comando2;
 ...
 comandon
 END;
 PROCEDURE P2;
 BEGIN
 comandoj;
 ...
 comandol
 END;
 BEGIN
 CASE expressão OF
 valor1 : P1;
 valor2, valor3 : P2;
 ...
 valorn : comandom
END
 END.
? CASE não aceita coisas do tipo (c é inteiro): 
CASE c OF
 30..40 : P1
 END;
? mas aceita 
106
 CASE c OF
 30+40 : P1 {verifica se é igual a 70}
 END;
107
TIPO SUBRANGE (INTERVALO) 
Suponha que queremos um programa em que uma variável, v, só pode ter valores 
inteiros de 0 a 100. Poderíamos declarar: 
 VAR v : integer;
mas isso permitiria que fizéssemos 
 v := 1000;
o que não deveria ser permitido! Como fazemos para, então, limitar os valores que 
podemos atribuir à nossa variável? 
 VAR v : 0..100;
O que fizemos aqui? Declaramos uma variável de um tipo especial, um intervalo, que 
vai de 1 a 100. 
O tipo intervalo (subrange) é, na verdade, um subintervalo de algum tipo do Pascal. No 
exemplo acima, como 0 e 100 são inteiros, é um intervalode 0 a 100 de inteiros. De 
fato, podemos ter intervalos de qualquer tipo padrão do Pascal, exceto real, desde que o 
tipo permita valores seqüenciais ('a', 'b' etc, 0, 1 etc). Então, podemos ter intervalos do 
tipo: 
 VAR v : 0..100;
 x : 'a'..'d';
 y : '5'..'9'; {note que são caracteres, não números}
Assim, de uma forma geral, um intervalo é representado da seguinte maneira: 
 limite_inferior..limite_superior
note que não há espaços entre os limites e os "..". 
Qual a vantagem do uso de intervalo? Não cometemos erros de programação, como os 
abaixo: 
 PROGRAM P;
 VAR x : 1..100;
 BEGIN
 x := 5; {aceito}
 x := 0; {erro de compilação}
 x := 200; {erro de compilação}
108
 x := 'a'; {erro de compilação}
 x := 3.24 {erro de compilação}
 END.
Assim, o uso de intervalos é mais uma técnica de auto-contenção usada pelo 
programador do que uma estrutura de dados mais elaborada. 
TYPE 
Suponha agora que, em vez de sempre digitarmos 1..100 queremos dar um jeito de criar 
um tipo que represente esse intervalo. Como faremos? 
 PROGRAM P;
 TYPE intervalo = 1..100;
 VAR x : intervalo;
BEGIN
 x := 10;
 x := x + 5*x
 END.
Pronto! Repare na sintaxe: 
 TYPE nome_do_tipo_criado = o tipo;
Assim, o que fizemos foi criar um tipo novo, chamado intervalo, que é um intervalo de 
1 a 100 de inteiros. Esse tipo pode ser usado normalmente como qualquer outro tipo do 
Pascal. Assim conseguimos criar tipos diferentes de real, boolean, integer e char. Por 
exemplo: 
 PROGRAM Exemplo;
 TYPE LetraMai = 'A'..'Z';
 Digito = '0'..'9'; {note que é caracter}
 hora = 1..24;
 VAR inicial : LetraMai;
 tempo : Hora;
 num : Digito
Agora a pergunta é: precisamos mesmo usar TYPE? Não! Como vimos acima, podemos 
definir direto na declaração da variável, sem precisar de TYPE. Então, qual a vantagem 
de declararmos um tipo novo com TYPE? 
Bem, antes de mais nada, o fato de eu poder dar nome aos meus tipos deixa o programa 
mais legível, de mais fácil compreensão e, dependendo da estrutura de dados que o tipo 
criado representa, o uso de TYPE pode poupar tempo de programação. 
109
Mas essa não é a principal vantagem de TYPE. A grande vantagem deste está no retorno 
de funções e na passagem de parâmetros para funções e procedimentos. Uma 
característica da linguagem Pascal é que NÃO posso definir procedimentos e funções 
como os abaixo: 
 PROGRAM Exemplo;
 PROCEDURE P(x : 1..20);
BEGIN
 ...
 END;
 FUNCTION F1(x : 1..20);
 BEGIN
 ...
 END;
 FUNCTION F2(y : integer) : 1..20;
BEGIN
 ...
 END;
 BEGIN
 ...
 END.
Já se eu der nome ao meu intervalo, com TYPE, o compilador ACEITA: 
 PROGRAM Exemplo;
 TYPE intervalo = 1..20;
 PROCEDURE P(x : intervalo);
BEGIN
 ...
 END;
 FUNCTION F1(x : intervalo) : integer;
 BEGIN
 ...
 END;
 FUNCTION F2(y : integer) : intervalo;
BEGIN
 ...
 F2 := 15 {se não estiver no intervalo 1..20, o 
compilador reclama}
 END;
 BEGIN
 ...
 END.
Mas por que ele não aceita da primeira forma e aceita da segunda se as duas são 
equivalentes? Porque em Pascal somente nomes de tipos podem aparecer nos 
parâmetros de procedimentos e funções. Assim, para fazer nosso programa rodar, temos 
110
que dar nome aos tipos diferentes de Integer, Real, Char e Boolean (há outros, variações 
destes 4 básicos). 
111
FUNÇÕES 
Lembra como fazíamos para retirar um valor de um procedimento? 
 PROGRAM P;
 VAR c,a,b:integer;
PROCEDURE Soma(a,b : integer; VAR resp : integer);
 BEGIN
 resp := a+b
 END;
 BEGIN
 a := 2;
 b := 4;
 Soma(a,b,c);
writeln(c) {escreve 5}
 END.
Será que não há um modo mais direto? Vamos ver, como tiramos, em Pascal, a raiz de 
um número y? 
 x := Sqrt(y);
E o módulo de y? 
 x := Abs(y);
Não seria interessante fazer c := Soma(a,b)? Como posso vazer isso? Fazendo uma 
função, cuja forma geral é: 
 FUNCTION nome(parâmetros) : tipo de retorno;
 VAR variáveis locais;
 BEGIN
 corpo da função, com cálculos etc;
 nome := resposta {carrego a resposta a ser devolvida pela 
função}
 END;
Vamos fazer um paralelo entre função e procedimento (ambos fazem a mesma coisa): 
VAR x;
 PROCEDURE 
soma(a,b:integer; 
VAR r:integer);
 BEGIN
 r := a+b
 END;
 FUNCTION soma(a,b:integer) : integer;
 BEGIN
 soma := a+b
 END;
 BEGIN
 x := soma(2,3);
writeln(x) {escreve 5}
112
 BEGIN
 soma(2,3,x);
 writeln(x) 
{escreve 5}
 END;
 END.
Vejamos as diferenças: 
? Uma função exige a palavra FUNCTION. 
? Exige um tipo de retorno, que é o tipo do valor que ela devolve. 
? Como último ato da função, você abastece o valor que ela deve devolver em 
uma variável local com o mesmo nome da função. Essa variável não pode ser 
declarada, pois, quando a função é criada, essa variável, com o mesmo nome e 
tipo igual ao tipo de retorno da função é criada automaticamente pelo 
compilador. 
? Dessa forma, o nome da função pode ser usada como uma variável local. De 
fato, o resultado da função será o valor que está armazenado nessa variável 
quando a função termina de executar (chega ao END de seu corpo). 
? A única restrição com relação a essa variável é que ela deve ficar sempre à 
esquerda em comandos de atribuição, ou seja, não temos como ver o que está 
armazenado nela dentro da função, apenas podemos atribuir valores a ela.
Atenção: essa restrição não é válida em todos os compiladores, ou seja, para 
alguns, essa é uma variável local comum. 
? Não posso chamar funções como procedimentos. 
Vamos ver um exemplo de erro: 
 {retorna a soma de 1 até "limite"}
 FUNCTION soma(lim:integer) : integer;
 VAR n : integer;
 BEGIN
 soma := 0;
 FOR n:=1 TO lim DO soma := soma + n {erro em alguns 
compiladores!}
 END;
Novamente: esse erro só existe em alguns compiladores. No free pascal, por exemplo, 
esse programa está correto e roda normalmente sem erro. 
Ou seja: antes de usar isso, verifique se o teu compilador aceita! Se aceitar, use à 
vontade. Caso seu compilador não aceite, você pode substituir a função acima por essa: 
 {retorna a soma de 1 até "limite"}
 FUNCTION soma(lim:integer) : integer;
 VAR n,t : integer;
BEGIN
 t := 0;
 FOR n:=1 TO lim DO t := t + n;
 soma := t
 END;
113
Como foi mencionado antes, não podemos chamar uma função como procedimento. Ela 
devolve um valor que deve ser usado, pois a função representa esse valor. Assim, posso 
até passá-la como parâmetro: 
 BEGIN
 writeln('2 + 3 = ', soma(2,3)) 
{escreve "2 + 3 = 5"}
END.
ou: 
 BEGIN
 a := soma(soma(2,3),6);
 writeln(a) {escreve "11"}
 END.
Com relação aos parâmetros, funções são como procedimentos. Sua grande utilidade é 
podermos usá-las em expressões: 
 CONST PI = 3.1416;
 VAR raio, lado : real;
vol_esfera : real;
 vol_cubo : real;
 FUNCTION cubo(n:real):real;
BEGIN
 cubo := n*n*n
 END;
 BEGIN
raio := 3;
 lado := 2;
 vol_esfera := 4*PI*Cubo(raio)/3;
vol_cubo := Cubo(lado)
 END.
Então, como funciona a FUNCTION? 
? Primeiro ela recebe os parâmetros 
? Depois executa os comandos em seu corpo 
? Ao final, retorna o último valor armazenado na variável local de nome igual ao 
da função. 
Mas, e se quisermos devolver dois valores? Por exemplo, suponha que queremos uma 
função que calcule a média de alguém e me diga se este passou. Como faríamos? 
 PROGRAM P;
 VAR media : real;
 {n1, n2 e n3 são as notas. A função retorna true se ele 
passou
114
 e false se não, carregando media com a média do sujeito}
 FUNCTION Passou(n1,n2,n3:real; VAR media:real):boolean;
 BEGIN
 media := (n1 + n2 + n3) /3;
 Passou := media >= 5 {truese media >=5, false se não}
 END;
 BEGIN
 IF Passou(5,3,7,media) THEN writeln('Passou com média 
',media)
 ELSE writeln('Reprovou com média ',media)
 END.
Nesse programa, a média é calculada e armazenada em "media" e, se esta for •����D�
função retorna true, senão retorna false. 
Note que antes do retorno da função, que se dá somente no END do corpo desta, ou 
seja, quando ela termina, "media" já havia sido modificada. 
Talvez, para entender melhor, devamos notar a similaridade entre uma função 
matemática e uma FUNCTION. Como dizemos que y é uma função de x? Fazendo: 
 y = f(x)
Ou seja, a cada valor de x, corresponde um y dado por essa relação. Como, então, 
representamos essa mesma função em Pascal? 
 y := f(x);
Parecidíssimo, não? Aqui, dado um valor de x, y é abastecido com o valor dado por f(x). 
Notou a semelhança do modo de pensar? Não é à toa, FUNCTION foi projetada para ter 
essa semelhança. 
Mas será que o concei to de função nos é tão novo? Não, já usamos funções 
anteriormente, vejamos alguns exemplos: 
 VAR ch : char;
 n : integer;
m : real;
 BEGIN
 ch := readkey;
 n := ord(ch);
 m := Sqrt(n)
 END.
essas funções correspondem às seguinte definições: 
FUNCTION readkey : char;
115
 BEGIN
 ...
 END;
 FUNCTION ord(c : char) : integer;
 BEGIN
 ...
 END;
 FUNCTION sqrt(x:real) : real;
BEGIN
 ...
 END;
e já vêm pré-definidas com o Pascal. 
Em suma:
Use procedimentos quando tiver um pedaço de código que se repete (recebendo ou não 
parâmetros), e use funções quando esse pedaço de código precisar retornar um valor. 
Obs: Com o que sabemos, FUNCTION só retorna valores simples, com nomes, como 
real, integer, boolean, char etc. Para saber como retornar valores mais complexos, 
verifique as próximas notas. 
116
PASSAGEM DE PARÂMETROS 
POR VALOR E REFERÊNCIA 
Até agora, tudo que podíamos fazer com procedimentos era passar valores a eles. Mas, e 
como retirar um valor deles? 
Considere o seguinte exemplo: quero um procediemtno que, dadas 3 notas, tire sua 
média conforme a fórmula: 
m = (2 × n1 + 3 × n2 + 5 × n3 ) ÷ 10 
como faço? Até o que sabemos, podemos fazer: 
 PROCEDURE media(n1,n2,n3 : real);
 VAR m : real;
 BEGIN
 m := (2*n1 + 3*n2 + 5*n3) / 10;
 write(m)
 END;
Mas, e se quisermos usar o valor de m depois? Podemos fazê-lo global: 
 PROGRAM P;
 VAR m : real;
 PROCEDURE media(n1,n2,n3 : real);
BEGIN
 m := (2*n1 + 3*n2 + 5*n3) / 10
 END;
 BEGIN
media(3.5,8,10);
 write(m)
 END.
Funciona? Claro! MAs é horrível. Por que? Porque não é desejável que variáveis 
globais sejam modificadas dentro de procedimentos, pois, se tivermos dezenas de 
procedimentos em nosso programa, podemos nos confundir. Então o que faremos? 
Temos que ter um meio de calcular a média no procedimento e retirar o valor de lá. 
Como? Passando uma variável por referência: 
 PROGRAM P;
1. VAR m : real;
4. PROCEDURE media(n1,n2,n3 : real; VAR resp : real);
 BEGIN
5. resp := (2*n1 + 3*n2 + 5*n3) / 10
END;
 BEGIN
2. media(3.5,8,10,m);
117
3. write(m)
END.
Notou o VAR no parâmetro de "media"? Ele indica que a variável que segue a ele é 
passada por referência. 
Como funciona um parâmetro por referência? Pense nele como uma variável local sem 
personalidade. Ela precisa de personalidade e, quando passamos a ela uma variável 
(como na linha 2. do programa acima), essa variável (no caso resp) assume a 
personalidade da variável passada (m). Ou seja, no nosso exemplo, tudo que fizermos 
com resp estaremos, na verdade, fazendo com m. 
Vamos ver o diagrama de execução do programa: 
1: 
2: 
5: 
3: 
Veja em 2 como representamos que resp recebeu m por referência: usamos uma seta 
indicando que qualquer mudança em resp será feita em m, o que de fato ocorre em 5, 
quando, ao darmos valor para resp, estamos dando para m. 
Essa seta póde ser vista como resp apontando para seu chefe, m. Então quando 
queremos algo com resp e vamos a ela (para por exemplo, ler seu val.or ou guardar algo 
118
nela), resp diz: "Não é comigo, é com ela!" e aponta para m. Assim, ao lermos resp 
lemos m, e ao modificarmos resp, modificamos m. 
Vamos ver um exemplo: 
 PROGRAM A;
1. VAR x,y : real;
2. a,b : integer;
3. PROCEDURE B(x : real; VAR y : integer);
4. VAR z : integer;
BEGIN
5. z := Trunc(x / 2);
6. y := 2*z
 END;
 BEGIN
7. x := 3.1416;
8. B(x,a);
9. write(a);
10. y := 2*x;
11. B(x+y,b);
12. write(b)
 END.
1 e 2: 
7: 
8, 3 e 4: 
5: 
119
6: 
Note que modifiquei o "a". 
9: 
10: 
11, 3 e 4: 
5: 
120
6: 
12: 
Estude atentamente os quadros acima e note que: 
? As variáveis podem ter o mesmo nome, não há confusão. O compilador 
diferencia local de global. De fato, podemos ter até: 
 PROGRAM A;
1. VAR x : integer;
2. PROCEDURE B(VAR x : integer);
 BEGIN
3. x := 2
 END;
 BEGIN
4. B(x);
5. write(x)
 END.
121
? Aqui, o x de A é diferente do de B. Em 3. modificamos o de B, mas como em 4. 
passamos o x de A para o x de B, modificações no x de B refletirão node A. 
Verifique. 
? Parâmetros por referência exigem variáveis! Assim, não é possível chamar B 
desse modo: 
 B(2,2);
 B(2,x+a);
 etc
? Um parâmetro VAR exige que eu passe uma variável. 
? Posso ter múltiplos parâmetros VAR. Por exemplo: 
 B(x:int; VAR y: int; VAR z,a : real);
? tem 4 parâmetros, sendo 3 deles por referência, ou seja, posso modificar o que 
passo a eles. 
Então, em suma: B(x) 
? Passagem por valor: passo ao procedimento uma cópia do valor que está em x, 
se a definição de B for B(a : tipo); 
? Passagem por referência: passo a B uma referência a x, se a definição for 
B(VAR a : tipo);, ou seja, qualquer mudança em "a" refletirá em x. De fato, 
parâmetros por referência são simplesmente nomes que o procedimento dá a 
variáveis que estão em outro lugar. O parâmetro pode, então, ser visto como um 
nome local para uma variável externa ao procedimento. 
Observação: uma vez que posso ler de dentro do procedimento o valor que há na 
variável que foi passada por referência, posso fazer coisas do tipo: 
 PROGRAM A;
 VAR x : integer;
PROCEDURE B(VAR n : integer);
 BEGIN
 n := (n * 5) MOD 3
 END;
 BEGIN
 x := 4;
 B(x);
 write(x) {x = 2}
 END.
Em B, pego o valor anterior de x, 4, multiplico por 5, pego o resto da multiplicação 
dividida por 3 e guardo em x. 
Por fim, podemos chamar procedimentos de dentro de procedimentos, passando os 
parametros por referencia. Por exemplo: 
122
1. PROGRAM A;
2. VAR x : integer;
3. PROCEDURE B(VAR n : integer);
 BEGIN
4. n := (n * 5) MOD 3
 END;
5. PROCEDURE C(VAR m : integer);
 BEGIN
6. B(m);
7. m := m + 3
 END;
 BEGIN
8. x := 4;
9. C(x);
10. write(x) {x = 5}
END.
Vamos fazer o diagrama de execuçao: 
1 e 2 - o programa é definido: 
8 - atualizo x: 
9 e 5 - chamo C passando x por referência: 
6 e 3 - chamo B passando m por referência. Note que, como m é uma encarnação de x, o 
que passo a B é x por referência: 
123
4 - aqui é mais truculento. Primeiro devo pegar o valor de n e então fazer a conta e por 
em n novamente: 
Então vamos pegar o valor de n. Primeiro o compilador busca em n, esse diz: "não é 
comigo, é com o m", aí o compilador vai buscar em m o valor que ele quer, e m diz: 
"não é comigo, é com x". Finalmente, o compilador busca o valor em x. É muito 
semelhante a uma repartição pública não?
Agora, após feito o cálculo, o compilador tenta colocar o resultado em n, esse diz que 
não é com ele, e sim com m. O compilador, então tenta por em m e essediz que não é 
com e le , e s im com x , a í o compilador tenta, e consegue, por o valor em x.
Notou qual variável foi modificada no final das contas? x. 
7 - modificamos m, modificando x: 
10 - a saída é impressa: 
124
VARIÁVEIS LOCAIS E GLOBAIS 
Se em seu programa você tem procedimentos, é possível declarar variáveis dentro de 
cada um deles, bem como dentro do programa em si. As constantes e variáveis 
declaradas após PROGRAM e fora dos procedimentos são chamadas de globais. 
Constantes e variáveis declaradas após PROCEDURE, ou seja, dentro do procedimento, 
são chamadas locais. Então, no programa abaixo: 
 PROGRAM exemplo;
 CONST c1 = 3;
 c2 = 4;
VAR v1 : integer;
 v2,v3 : real;
 PROCEDURE P;
 CONST c3 = 5;
 VAR v4,v5 : real;
 BEGIN
...
 END;
 BEGIN
 ...
 END.
c1 e c2 são constantes globais, enquanto que c3 é local, e v1, v2 e v3 são variáveis 
globais, enquanto que v4 e v5 são locais. 
O que essa diferença significa? Variáveis globais são visíveis de todo o programa, as 
locais somente de dentro do procedimento onde foram declaradas. 
Assim, c3, v4 e v5 só são vistas em P, enquanto que c1, c2, v1, v2 e v3 podem ser 
acessadas de qualquer lugar no programa. 
Mas, o que acontece se tenho variáveis locais e globais com o mesmo nome? 
 PROGRAM P;
 VAR v1,v2,v3 : integer;
PROCEDURE Q;
 VAR v1,v2 : real;
 BEGIN
...
 END;
 BEGIN
 ...
 END.
Dentro de Q, qualquer referência a v1 e v2 se tratará da v1 e v2 de Q. As globais não 
são visíveis, ou seja, as globais foram eclipsadas pelas locais de mesmo nome. 
125
Quando, de dentro de Q, você chama v1, o compilador entende que é v1 de Q. Talvez 
seja mais fácil de entender assim: v1 é João, assim, v1 de P é João Silva, enquanto que 
v1 de Q é João Souza. Ambos são João, mas são diferentes. Como o compilador aceita 
conhecer no máximo um João, ele escolhe o mais próximo do lugar onde João foi 
chamado (na hierarquia). 
Mas isso não é tudo! Podemos ter procedimentos dentro de procedimentos: 
PROGRAM A;
 PROCEDURE B;
 PROCEDURE D;
 BEGIN
 ...
 END; {D}
 BEGIN
 ...
 END;{B}
 PROCEDURE C;
 PROCEDURE E;
 BEGIN
 ...
 END; {E}
 PROCEDURE F;
 BEGIN
 ...
 END; {F}
 BEGIN
 ...
 END; {C}
BEGIN
 ...
 END. {A}
Aqui, E e F estão dentro de C; D está dentro de B e B e C dentro de A. E agora? de onde 
posso chamar cada procedimento? 
Procedimento:
Pode ser chamado por 
comandos em:
B A, C, E, F, B 
C A, C 
D B, D 
E C, F, E 
F C, F 
Obs: O caso de chamar um procedimento de dentro dele mesmo será visto mais tarde no 
curso. 
Esteja seguro de ter entendido isso! Considere, se ajudar, cada procedimento como um 
micro-programa que, por sua vez, pode ter dentro dele novos procedimentos. 
126
Note que um procedimento pode ser chamado de dentro daqueles que estão no mesmo 
nível, mas abaixo dele na definição. Assim, apesar de B e C estarem no mesmo nível, B 
é visto de C, mas C não é visto de B, pois B foi declarado antes e, quando B é lido, C 
não é conhecido ainda. Assim, como quando chegamos em B C não foi declarado ainda, 
fazer uma chamada a ele de B causará um erro. 
E as variáveis, como ficam? Onde posso referenciá-las? 
Variáveis 
declaradas em:
Podem ser 
referenciadas em:
A A, B, C, D, E, F 
B B, D 
C C, E, F 
D D 
E E 
F F 
Viu? As variáveis de um nível são vistas em todos os níveis abaixo. E se, agora, 
tivermos variáveis de mesmo nome (repare que os tipos podem ser diferentes): 
 PROGRAM P;
 VAR a : tipo1;
 PROCEDURE Q1(a : tipo1);
 PROCEDURE Q2;
 VAR b : tipo2;
 PROCEDURE Q3;
VAR a : tipo3;
BEGIN
 ...
END; {Q3}
 BEGIN
 ...
 END; {Q2}
BEGIN
 ...
 END;{Q1}
 PROCEDURE Q4;
 VAR b : tipo2;
 PROCEDURE Q5;
 VAR a : tipo1;
 BEGIN
 ...
 END; {Q5}
 BEGIN
 ...
 END; {Q4}
BEGIN
 ...
 END. {P}
127
Se eu fizer a:=5 dentro de cada procedimento, qual "a" modifico? 
Dentro de: Modifico "a" de:
Q1 Q1 
Q2 Q1 (não há "a" em Q2) 
Q3 Q3 
Q4 P (não há declaracção de "a" em Q4) 
Q5 Q5 
P P 
Note que, em Q1, "a" é parâmetro. Parâmetros são variáveis locais também. 
Então, como o compilador, ao encontrar uma referência a uma variável, acha essa 
variável? 
? Primeiro ele olha no procedimento atual (ou programa). 
? Se não estiver declarada lá, olha no procedimento (ou programa) onde o 
procedimento atual foi declarado; dentro de onde o atual está, o procedimento 
pai deste. 
? Se não estiver lá, ele busca no pai do pai do atual, no avô, e assim por diante, até 
que encontre um procedimento (ou o próprio programa) em que a variável esteja 
declarada. 
? Se ainda assim não achou a declaração, reporta um erro. 
128
PROCEDIMENTOS 
Já vimos parte de procedimentos, agora vamos ver mais a fundo o que eles são e como 
usá-los. Mas, antes, é bom lembrarmos a principal razão de usarmos procedimentos: 
evitar código duplicado, tornando os programas menores e mais inteligíveis. 
Considere o ovo se movendo. Como fazíamos isso? Tinhamos 2 procedimentos: apaga e 
desenha: 
PROCEDURE Desenha; PROCEDURE Apaga;
 BEGIN BEGIN
gotoxy(x+1,y); gotoxy(x+1,y);
write('*'); write(' ');
gotoxy(x,y+1); gotoxy(x,y+1);
write('*'); write(' ');
gotoxy(x,y+2); gotoxy(x,y+2);
write('*'); write(' ');
gotoxy(x+1,y+3); gotoxy(x+1,y+3);
write('*') write(' ')
END; END;
São incrivelmente parecidas não? Não haveria um modo melhor de fazer isso? Claro! 
Note que o que fizemos foi imprimir "*" num procedimento e " " em outro. O que 
fazemos então? Passamos o caracter a ser impresso para dentro do procedimento. 
Como? Com parâmetros: 
 PROCEDURE ovo(c : char);
 BEGIN
 gotoxy(x+1,y);
 write(c);
 gotoxy(x,y+1);
 write(c,' ',c);
gotoxy(x,y+2);
 write(c,' ',c);
 gotoxy(x+1,y+3);
write(c)
 END;
Agora, se quisermos desenhar o ovo chamamos: 
 ovo('*');
 ou:
 ch := '*';
 ovo(ch);
Qualquer uma das duas maneiras vale. E para apagar? 
 ovo(' ');
129
 ou:
 ch := ' ';
 ovo(ch);
Fácil, não? Agora você pode estar perguntando: em vez de parâmetro, c podia ser 
global, não? Sim, mas veja essa regrinha: evite variáveis globais. Por que? Porque em 
um programa grande você pode se confundir se começar a usar variáveis globais dentro 
de procedimentos. Use globais somente quando for usá-las no corpo do programa. Se 
algum procedimento as usar, passe como parâmetro. 
Então, vamos melhorar nosso procedimento? Como? Arrancando as variáveis globais: 
PROCEDURE ovo(c : char; x,y : integer);
 BEGIN
gotoxy(x+1,y);
 write(c);
 gotoxy(x,y+1);
write(c,' ',c);
 gotoxy(x,y+2);
 write(c,' ',c);
 gotoxy(x+1,y+3);
 write(c)
 END;
Peraí, eu não mudei o código! Mudei sim!. Quando ovo acessa x e y no gotoxy, ele está 
acessando o x e o y dos parâmetros. Ao declarar um parâmetro com o mesmo nome de 
uma variável global, impeço o procedimento de enxergar essa global. Ou seja, para ovo, 
x e y são relativas aos parâmetros, ele não "enxerga" mais as globais x e y. 
Lembra de nossa discussão sobre variáveis globais e locais? Pois é, parâmetros são um 
tipo de variáveis locais, ou seja, são vistas somente de dentro do procedimento, 
deixando invisível (de dentro deste procedimento) qualquer variável global que 
contenha o mesmo nome de alguma local. 
quando o procedimento é chamado, o computador cria um espaço para ele, passando os 
parâmetros, e o executa. Vamos ver a animação do ovo: 
 PROGRAM anima;1. CONST xin = 10; {x inicial}
 yin = 10; {y inicial}
 numpos = 20; {número de posições que 
cairá}
2. VAR cont : integer; {contador do for}
PROCEDURE ovo(c : char; x,y : integer);
 BEGIN
gotoxy(x+1,y);
 write(c);
 gotoxy(x,y+1);
write(c,' ',c);
 gotoxy(x,y+2);
130
 write(c,' ',c);
 gotoxy(x+1,y+3);
 write(c)
 END;
BEGIN
 {desenho o ovo}
3. ovo('*',xin,yin);
4. delay(500);
 {faço cair numpos posições}
5. FOR cont := yin TO (yin + numpos - 1) DO
BEGIN
 {apago o ovo}
6. ovo(' ',xin,cont);
 {desenho uma posição abaixo}
7. ovo('*',xin,cont+1);
8. delay(500)
 END
 END.
Note que, ao passar valores aos parâmetros de ovo, posso dar o valor, como '*', dar uma 
variável, como xin, ou uma expressão, como cont+1. O que acontece é que o valor de 
cada um destes ('*', valor de xin e resultado de cont+1) é copiado para cada uma das 
variáveis dos parâmetros de ovo, em ordem, ou seja, na primeira chamada a ovo, as 
locais de ovo c, x e y recebem, respectivamente, '*', o valor de xin e o valor de yin. 
Note também que delay nada mais é que um procedimento com um parâmetro. 
Atenção!
Se você fizer isso: 
PROCEDURE ovo(c : char; x,y : integer);
 BEGIN
...
 c := 'a';
 ...
 END;
você mudou o valor da variável local c, ou seja, o que foi passado no parâmetro foi 
perdido. 
DIAGRAMAS DE EXECUÇÃO 
Agora vamos fazer um diagrama de execução para nosso programa do ovo. Um o que? 
O diagrama de execução mostra o estado das variáveis do programa. Veja o exemplo 
com o ovo. Primeiro crio um diagrama para o programa, com variáveis e constantes 
(nesse caso, fiz numpos=2, para ficar mais rápido): 
131
Começo a execução do programa e, como na linha 3 chamamos um procedimento, crio 
novo diagrama para ele, dando valor aos parâmetros: 
agora executamos ovo, marcando sua saída. Note que nenhum parâmetro foi mudado. 
na linha 4, o delay não é um procedimento meu, então não represento. Na linha 5 
atualizo o contador: 
na linha 6, chamo novamente o procedimento: 
nas linhas 7 e 8 desenho novamente o ovo, uma posição abaixo e espero um momento: 
132
voltando ao FOR na linha 5: 
passando novamente pela linha 6: 
linhas 7 e 8: 
133
incrementa o contador e faz o teste do FOR, como passou do limite, sai do FOR, saindo 
do programa: 
Isso é um diagrama de execução. Vejamos com outro exemplo: 
 PROGRAM A;
 VAR x,y : real;
PROCEDURE B(z : real);
 VAR h : real;
 BEGIN
h := z * 5;
134
writeln('B: ',h)
END;
 BEGIN
0. y := 3;
1. x := y + 2;
2. y := x * y;
3. B(y);
4. B(x)
 END.
Vamos executar: crio um diagrama com o nome do programa e suas variáveis (e 
constatnes se houver). Começo a rodar do BEGIN (linha 0): 
linha 1: 
linha 2: 
linha 3: 
mudo o valor de h, no procedimento: 
linha 4: 
135
mudo o valor de h, no procedimento: 
Naturalmente, você deve fazer todos os desenhos num só. As figuras mostram apenas a 
evolução temporal do diagrama. 
Para ver mais sobre diagramas consulte as notas sobre passagem de parâmetros. 
ENTRADA E SAÍDA 
Já vimos como escrever, com write e writeln, e como ler uma entrada, com read e 
readln. Mas, como lemos mais de uma entrada por vez, sem usarmos vários reads ou 
readlns? 
 PROGRAM P;
 VAR i1,i2:integer;
BEGIN
 read(i1, i2); {lê dois inteiros}
END.
Só que para que isso funcione, o usuário deve separar os dois inteiros com um ou mais 
espaços. Veja algumas entradas válidas: 
 2 3
 2 -3
-2 2
-2 -2
 etc
136
Da mesma forma, podemos ler outros tipos: 
 PROGRAM P;
 VAR r1,r2:real;
b1,b2:boolean;
 BEGIN
 read(r1, r2); {lê dois reais}
 read(b1, b2); {lê dois booleanos}
END.
Algumas entradas válidas são: 
 2.3e22 2.345E2
 true false
-2.3e22 2.45E-2
false true
 0.4 -3.980
 false false
 0.498e-2 12.3
 true true
etc
Em suma, o read lê de forma diferente os diferentes tipos de entrada (tipo este 
determinado pela variável que é passada como parâmetro para o read, que receberá a 
entrada): 
? Inteiros: todos os espaços e caracteres de nova linha iniciais são pulados até que 
se encontre um caracter diferente destes. Se este caracter não for um dígito, ou 
'+' ou '-', um erro é acusado. Se for dígito, o read vai lendo cada caracter até 
encontrar um não-dígito, quando o read pára e transforma o monte de dígitos 
lidos em um inteiro. 
? Reais: novamente o read pula espaços e caracteres de nova linha até encontrar 
um caracter diferente. Esse caracter deve ser '+', '-' ou número, senão um erro é 
reportado. Então o read vai lendo os dígitos até que encontre um caracter 
diferente de número, '.', 'e', 'E', 'e+', 'E+', 'e-' ou 'E-', ou seja, as entradas 
permitidas são do tipo 2, -2, +2, 2.0, +2.0E10, -2.05e-10 etc. 
? Booleanos: da mesma forma, o read pula espaços e nova linha até encontrar as 
palavras 'true' ou 'false seguidas de ' ' ou algum outro delimitador('.', ',' etc). 
? Char : o read lê o próximo caracter, sem pular nada. 
CARACTERES 
Em Pascal, caracteres são guardados em um tipo de variável especial, declarada assim: 
137
 VAR ch : char;
Aqui, ch é do tipo caracter, o que significa que pode guardar qualquer caracter (mas 
apenas um), quer seja, letra, número, sinais gráficos etc. 
Mas, e como armazenamos caracteres nessas variáveis? 
 ch := 'a';
 ch := 'A';
 ch := ' '; {espaço}
 ch := '"'; {aspas duplas}
Note que 'a' é diferente de 'A', ou seja, há distinção entre caracteres maiúsculos e 
minúsculos. 
Um outro ponto interessante é que caracteres são ordenados e seqüenciais: 
 'A' < 'B' < 'C' < ... < 'Z'
 'a' < 'b' < 'c' < ... < 'z'
 '0' < '1' < '2' < ... < '9'
Não confunda 9 com '9', o primeiro é um número e o segundo um caracter. 
Então podemos fazer: 
 FOR ch:='A' TO 'Z' DO write(ch);
e teremos o alfabeto. 
LENDO E ESCREVENDO CARACTERES 
Para ler um único caracter, fazemos: 
 read(ch);
onde ch é do tipo char. Já para escrever: 
 write(ch);
Isso é muito útil na interação com o usuário, por exemplo: 
ch := 's';
 WHILE (ch<>'n') AND (ch<>'N') DO
BEGIN
138
 faz algo
 write('quer continuar? (s/n) ');
 readln(ch)
 END;
ou 
 REPEAT
 faz algo
 write('quer continuar? (s/n) ');
 readln(ch)
 UNTIL (ch='n') OR (ch='N');
Novamente, como o usuário pode entrar tanto com 'n' quanto com 'N', e como 'n' �
1
��
devo testar os dois. 
Agora suponha que temos a seguinte entrada: 
 Esta é uma frase .
e queremos gerar a saída: 
 Esta
 é
 uma
 frase
Ou seja, pegamos uma frase que termina com '.' e separamos as palavras dela. Como 
faremos? 
 enquanto for diferente de '.' 
(senão acabou a frase)
 enquanto for diferente de ' ' 
(senão ainda é a palavra)
 leio uma letra
 escrevo essa letra
 dou nova linha
ou 
 repito
 enquanto for diferente de ' '
 leio uma letra
 escrevo a letra lida
 dou nova linha
 até que encontre um '.'
139
mas isso tem um problema, ' ' será lido e escrito. Quero testar antes de escrever, então 
ler tem que ser a última coisa a fazer: 
 leio uma letra
 enquanto for diferente de '.' (senão acabou a frase)
 enquanto for diferente de ' ' (senão ainda é a palavra)
 escrevo a letra lida
 leio uma letra
 dou nova linha
mas isso também tem um problema: repare que, se lemos um ' ', entraremos num laço 
infinito (confira!). Então, para corrigir, devemos fazer: 
 leio uma letra
 enquanto for diferente de '.' (senão acabou a frase)
 enquanto for diferente de ' ' (senão ainda é a palavra)
 escrevo a letra lida
 leio uma letra
 dou nova linha
 leio uma letra
Pronto!Como fica isso em Pascal? 
read(ch);
 WHILE ch<>'.' DO
 BEGIN
 WHILE ch<>' ' DO
 BEGIN
 write(ch);
 read(ch)
 END
 writeln;
 read(ch)
 END;
Mas, em vez de 2 WHILEs, não poderíamos por tudo em um só? Claro, mas teríamos 
que mudar o código, se fizermos somente: 
 enquanto for direrente de '.' e 
diferente de ' ' faça
o programa pararia no primeiro espaço, o que não queremos. Então, como fazemos? 
 read(ch);
 WHILE ch<>'.' DO
 IF ch<>' ' THEN
 BEGIN
 write(ch);
 read(ch)
 END
 ELSE BEGIN {é = ' '}
140
 read(ch);
 writeln
 END
 END;
Agora, qual o maior problema com esse código? O read exige . Não seria legal o usuário 
digitar e nós lermos no mesmo isntante, sem precisar do ? Como faríamos isso? Com: 
 ch := readkey;
readkey espera que o usuário digite algo e, assim que ele digitar, pega o caracter que ele 
digitou. Então não preciso do . 
Legal, não? Mas como nem tudo é uma maravilha, há um detalhe sobre o readkey: 
como o nome diz, ele lê uma tecla somente. Você não consegue ler integer, real ou 
palavras com ele, somente char. Outra coisa, enquanto que com read você escreve, vê o 
que escreveu na tela e então dá enter, com readkey isso não acontece. Ao você digitar 
algo, readkey lê diretametne a tecla, sem mostrar o que você digitou na tela. Se você 
quiser que mostre, terá que ecoar o caracter lido, ou seja, escrevê-lo na tela, com write. 
Então o programa fica: 
 ch := readkey;
 WHILE ch<>'.' DO
 BEGIN
 WHILE ch<>' ' DO
 BEGIN
 write(ch);
 ch := readkey
 END
writeln;
 ch := readkey
 END;
CARACTERES E A TABELA ASCII 
Até agora vimos como usar caracteres, mas como será que o computador entende 
caracteres? Bem, ele não entende. Quando você digita um caracter, o Sistema 
Operacional se encarrega de traduzí-lo para um código numérico que ele possa 
manipular mais tarde. Assim, os caracteres nada mais são do que números. Mas como 
ele faz essa tradução? 
Para fazer a tradução de caracteres em números, o Sistema Operacional usa uma tabela, 
chamada ASCII (veja no próximo tópico). Existem vários tipos de tabela, dependendo 
do computador que é usado e do país em que é usado, apesar disso, ela não muda dos 
números 0 ao 127. 
141
Mas você não precisa decorar essa tabela para brincar com caracteres. O Pascal tem 
duas funções para lidar com caracteres: 
 VAR n : integer;
 c : char;
 BEGIN
 n := Ord('a'); {n recebe o código ascii de 'a'}
 c := 'z';
 n := Ord(c); {n recebe o código ascii do caracter 
armazenado em c, ou seja, 'z'}
 c := Chr(120); {c recebe 'x' (veja tabela abaixo)}
c := Chr(Ord('z')); {c recebe 'z'}
 END.
Assim, Ord recebe um caracter e retorna o código ascii deste, e Chr recebe um código 
ascii e retorna o caracter correspondente a este. 
Mas para que podemos usar isso? Vejamos alguns exemplos: 
Exemplo 1 : Uma codificação simples. Suponha que queremos codificar uma 
determinada frase de 10 letras digitada, para isso, lemos cada caracter e somamos 5 ao 
seu ascii, resultando num caracter diferente: 
 PROGRAM codifica;
 VAR n : integer; {ascii de c1}
 c1 : char; {caracter digitado}
 c2 : char; {caracter codificado}
 i : integer; {contador do FOR}
BEGIN
 FOR i:=1 TO 10 DO
 BEGIN
c1 := readkey; {leio o caracter digitado}
 n := Ord(c1); {pego o ascii do caracter digitado}
 n := n + 5; {incrementei o código em 5}
 c2 := Chr(n); {pego o caracter desse novo código}
 write(c2) {escrevo o caracter codificado}
 END
 END.
Exemplo 2: Transformar minúsculas em maiúsculas e vice-versa.
Nesse caso, o Pascal já tem uma função pré-definida 
 ch1 := Uppercase(ch2);
para transformar minúsculas (ch2) em maiúsculas (ch1), apesar disso, não tem uma 
função para transformar maiúsculas em minúsculas. Então vamos construir a nossa 
função 
Para tal, precisamos de algumas informações: 
142
? Tanto as letras maiúsculas quanto as minúsculas são seqüenciais na tabela ascii, 
ou seja, se 'C' está ná segunda posição após 'A', 'c' estará na segunda posição 
após 'a' também. 
? Dessa forma, na tabela ascii, 'C' - 'A' = 'c' - 'a'. 
? Assim, dado um caracter x (não confunda com 'x'), minúsculo, sei que X - 'A' = 
x - 'a', ou seja, X = x - 'a' + 'A'. Assim, tenho como calcular a maiúscula de x, a 
partir da minúscula, x. 
? Da mesma forma, dado um caracter maiúsculo X, sei que X - 'A' = x - 'a', ou 
seja, x = X - 'A' + 'a'. Tenho, então, a minúscula a partir da maiúscula. 
Agora, sim, vamos fazer procedimentos que transformem minha minúscula em 
maiúscula e vice-versa: 
 PROGRAM transforma;
 VAR l : char; {a letra a ser transformada}
 {recebe c por referência, e o substitui pela sua maiúscula}
 PROCEDURE Maiuscula(VAR c : char);
 VAR mai : integer; {guarda o ascii da maiúscula}
BEGIN
 IF (c>='a') AND (c<='z') THEN {c é minúscula}
 BEGIN
 mai := Ord(c) - Ord('a') + Ord('A');
c := Chr(mai)
 END
 {se não for minúscula (ou mesmo não for letra), deixa como 
está}
 END;
 {recebe c por referência, e o substitui pela sua minúscula}
 PROCEDURE Minuscula(VAR c : char);
 VAR mai : integer; {guarda o ascii da maiúscula}
BEGIN
 IF (c>='A') AND (c<='Z') THEN {c é maiúscula}
 BEGIN
 mai := Ord(c) - Ord('A') + Ord('a');
c := Chr(mai)
 END
 {se não for maiúscula (ou mesmo não for letra), deixa como está}
END;
 BEGIN
 l := 'd';
 Minuscula(l);
writeln(l); {escreve 'd', não alterou}
 Maiuscula(l);
 writeln(l); {escreve 'D', a maiúscula}
 l := 'P';
 Maiuscula(l);
 writeln(l); {escreve 'P', não alterou}
Minuscula(l);
 writeln(l) {escreve 'p', a minúscula}
 END.
note que o procedimento "Maiuscula" poderia ser tão somente: 
143
 {recebe c por referência, e o substitui pela maiúscula dela}
PROCEDURE Maiuscula(VAR c : char);
 BEGIN
 IF (c>='a') AND (c<='z') THEN {c é minúscula}
 c := Chr(Ord(c) - Ord('a') + Ord('A'))
{se não for minúscula (ou mesmo não for letra), deixa como está}
 END;
mas fizemos mais longo para ficar mais legível a operação. 
TABELA ASCII 
Essa é a tabela usada em linux (ISO 8859-1): 
 Dec Char Dec Char Dec Char Dec 
Char
--------------------------------------------------------------------
-----
 0 NUL '\0' 32 SPACE 64 @ 96 
`
 1 SOH 33 ! 65 A 97 
a
 2 STX 34 " 66 B 98 
b
 3 ETX 35 # 67 C 99 
c
 4 EOT 36 $ 68 D 100 
d
 5 ENQ 37 % 69 E 101 
e
 6 ACK 38 & 70 F 102 
f
 7 BEL '\a' 39 ' 71 G 103 
g
 8 BS '\b' 40 ( 72 H 104 
h
9 HT '\t' 41 ) 73 I 105 
i
 10 LF '\n' 42 * 74 J 106 
j
 11 VT '\v' 43 + 75 K 107 
k
 12 FF '\f' 44 , 76 L 108 
l
13 CR '\r' 45 - 77 M 109 
m
 14 SO 46 . 78 N 110 
n
 15 SI 47 / 79 O 111 
o
 16 DLE 48 0 80 P 112 
p
 17 DC1 49 1 81 Q 113 
q
 18 DC2 50 2 82 R 114 
r
 19 DC351 3 83 S 115 
144
s
 20 DC4 52 4 84 T 116 
t
21 NAK 53 5 85 U 117 
u
 22 SYN 54 6 86 V 118 
v
 23 ETB 55 7 87 W 119 
w
 24 CAN 56 8 88 X 120 
x
 25 EM 57 9 89 Y 121 
y
 26 SUB 58 : 90 Z 122 
z
 27 ESC 59 ; 91 [ 123 
{
 28 FS 60 < 92 \ '\\' 124 
|
 29 GS 61 = 93 ] 125 
}
 30 RS 62 > 94 ^ 126 
~
31 US 63 ? 95 _ 127 
DEL
Códigos ASCII extendidos:
145
O COMANDO REPEAT 
Como vimos, o WHILE testa a condição ANTES de executar o laço. Mas, e se 
quiséssemos testar DEPOIS da execução? Ou seja, se quiséssemos fazer algo pelo 
menos uma vez e então testar? 
 REPEAT
 comando1;
 comando2;
 ...
 comandon
 UNTIL condição;
O que esse comando diz? Repita os comandos a seguir até que a condição seja 
verdadeira. Ou seja, primeiro ele executa os comandos comando1, comando2, ..., 
comandon para depois testar a condição. Se a condição for falsa, ele executa o laço 
novamente e testa de novo, e assim por diante. Se a condição for verdadeira, ele sai do 
laço e segui o programa. 
Veja bem a diferença entre REPEAT e WHILE: 
? WHILE: enquanto a condição for verdadeira, executa os comandos; 
? REPEAT: executa os comandos até que a condição seja verdadeira. 
Ou seja, enquanto que o WHILE pára se a condição for falsa, o REPEAT continua se 
ela for falsa, ou seja, pára se ela for verdadeira. 
Outra coisa, notou a ausência de BEGIN e END? No REPEAT não precisa. Não é 
errado por, mas não precisa. Assim, as duas formas a seguir são redundantes: 
 REPEAT REPEAT
 comando1; BEGIN
 comando2; comando1;
 ... comando2;
 comandon ...
 UNTIL condição; comandon
 END
 UNTIL condição
Note também que não preciso por ";" antes do UNTIL. Ou seja: 
? Antes de END e UNTIL não precisa pro ";" 
? Antes de ELSE não pode haver ";" 
Vejamos uma aplicação: lembra do nosso programa anterior com WHILE para achar a 
média? 
 PROGRAM media;
 VAR soma, nota : real;
 cont : integer;
146
 BEGIN
 soma := 0;
 cont := 0;
 nota := 0;
 write('nota: ');
 readln(nota)
 WHILE nota <> -1 DO BEGIN
 soma := soma + nota;
 cont := cont + 1;
write('nota: ');
 readln(nota)
END;
 IF cont>0 THEN writeln('A média é ',soma/cont)
END.
Como escreveríamos isso com REPEAT? 
 PROGRAM media;
 VAR soma, nota : real;
 cont : integer;
 BEGIN
 soma := 0;
 cont := -1;
 nota := 0;
 REPEAT
 soma := soma + nota;
 cont := cont + 1;
 write('nota: ');
readln(nota)
 UNTIL nota = -1;
 IF cont>0 THEN writeln('A média é 
',soma/cont)
 END.
Então, em suma: 
? Se quisermos primeiro testar para depois fazer o laço, usamos WHILE; 
? Se quisermos fazer o laço pelo menos uma vez e então testar, usamos REPEAT. 
Meio nebulosa a diferença não? Não é para menos, REPEAT e WHILE são 
completamente equivalentes, ou seja, você pode escrever um em função do outro. Por 
exemplo, abaixo vemos, à esquerda, um REPEAT escrito com WHILE (ou seja, o 
código escrito com WHILE age como se fosse um REPEAT), e à direita temos um 
WHILE escrito com REPEAT (ou seja, o código escrito com REPEAT age como se 
fosse um WHILE): 
REPEAT com WHILE: WHILE com REPEAT:
 f := true; REPEAT
 WHILE f DO BEGIN IF condição THEN BEGIN
comando1; comando1;
 comando2; comando2;
 ... ...
147
 comandon; comandon
 f := NOT condição END
 END; UNTIL NOT condição;
Quando você usa um ou outro na prática? Vai do gosto do freguês. 
148
O COMANDO WHILE 
Lembra nosso programa de chute? Nós dávamos 10 chances ao usuário e, então 
saíamos. O que acontece se quiséssemos dar infinitas chances? Não poderíamos usar o 
FOR. Iríamos querer algo assim: 
 enquanto o usuário não acertar
 peça novo chute
Como fica isso em Pascal? 
 PROGRAM chute;
 CONST num = 5;
 VAR nao_acertou : boolean;
chute : integer;
 BEGIN
 nao_acertou := true;
WHILE nao_acertou DO
 BEGIN
 write('seu chute: ');
readln(chute);
 IF chute = num THEN BEGIN
writeln('acertou!');
nao_acertou := false
END
 ELSE
 IF chute > num THEN writeln('é >')
ELSE writeln('é <')
 END {while}
END.
Então, em termos gerais: 
 WHILE condição DO comando;
A condição é como no IF, podendo ter AND, OR e NOT 
Como o WHILE funciona? Se condição for verdadeira, ele executa o comando (ou 
grupo de comandos). Aí, ao final, ele testa novamente a condição e, se ela continuar 
verdadeira, executa comando novamente. Faz isso até que condição seja falsa. 
Ou seja, faz exatamente o que diz: "Enquanto condição faça comando". 
Um lembrete: sempre inicialize as variáveis da condição. 
Se a condição for falsa antes do WHILE, ele nem será executado: 
149
 continua := false;
 WHILE continua DO write('nunca será executado');
Com isso vemos que não precisamos mais do coxambre horrível do FOR. Aliás, um 
FOR pode ser feito com WHILE, veja abaixo: 
cont := 1;
FOR cont:=1 TO N DO WHILE cont<=N DO
 comando; BEGIN
 comando;
 cont := cont + 1
 END;
Use sempre WHILE quandovocê precisar sair do laço a qualquer momento, como no 
exemplo do programa onde o usuário adivinhava o número. 
Considere o programa abaixo: 
 n := 1;
 WHILE n <> 10 DO BEGIN
 write(n);
 n := n+2
 END;
Quando esse programa pára? Nunca! Pois n nunca é 10. Ele imprime os ímpares ad 
infinitum. Se quiséssemos imprimir os 5 primeiros ímpares deveríamos fazer: 
 n := 1;
 WHILE n < 10 DO BEGIN
 write(n);
 n := n+2
 END;
Nunca use <> quando < ou > bastam. 
Considere agora esse fragmento: 
 x := 5;
 WHILE x > 0 DO BEGIN
 x := x - 1;
write(10/x)
 END;
Qual o erro deste? O erro é que antes subtraímos, daí escrevemos, para depois testar. 
Assim, quando x=1, faço x:=x-1 => x=0 e divido 10 por 0 => erro! 
Como conserto isso? O modo mais direto seria: 
150
x := 5;
 WHILE x > 0 DO BEGIN
 x := x - 1;
 IF x>0 THEN write(10/x)
END;
Mas isso não parece legal, pois estamos fazendo duas vezes o mesmo teste. Tem como 
melhorar? Tem: 
 x := 4;
 WHILE x > 0 DO BEGIN
 write(10/x);
x := x - 1
 END;
Agora garanto que ao decrementar x, testo se ele é maior que zero. 
Assim, é bom seguir essa receita com laços WHILE: 
 gero ou leio o primeiro valor
 WHILE há outros valores
 processo o valor
 gero ou leio o próximo
Dessa forma garantimos que só valores testados são processados. 
Como foi visto no IF, a condição pode ser qualquer expressão, variável ou valor 
booleano. Assim, o seguinte programa nunca pára: 
 WHILE true DO writeln('não pára!');
pois a condição é sempre verdadeira. Além disso, operações como AND, OR e NOT são 
permitidas. 
Em suma: o laço WHILE testa a condição e, se esta for verdadeira, então executa seu 
corpo (o que está entre BEGIN e END, ou o comando que segui o DO, snão não houverBEGIN e END). Após executar o corpo, ele testa novamente a condição, executando 
novamente o corpo se esta for verdadeira. Assim ele seguie até que a condição se torne 
falsa, quando ele "pula" o corpo e o programa passa ao comando seguinte ao WHILE. 
Como exemplo, façamos um programa que tire a média de n notas do usuário (n 
desconhecido). Se o usuário entrar -1 ele sai do programa: 
 PROGRAM media;
 VAR soma, nota : real;
 cont : integer;
 BEGIN
151
 soma := 0;
 cont := 0;
 nota := 0;
 WHILE nota <> -1 DO BEGIN
write('nota: ');
 readln(nota);
soma := soma + nota;
 cont := cont + 1
 END;
 writeln('A média é ',soma/cont)
 END.
Que erros temos aí? Dois grandes! O primeiro é que, quando o usuário entra com -1, ele 
é somado. Então temos que deixar o read para o final (para deposi da soma): 
 PROGRAM media;
 VAR soma, nota : real;
 cont : integer;
 BEGIN
 soma := 0;
 cont := -1; {se 0 conta um a mais, verifique}
 nota := 0;
 WHILE nota <> -1 DO BEGIN
 soma := soma + nota;
cont := cont + 1;
 write('nota: ');
readln(nota)
 END;
 writeln('A média é ',soma/cont)
 END.
Mas ainda dá para melhorar! Notou que da primeira vez, soma=0, nota=0 e faço soma 
:= soma+nota? Posso evitar essa soma desnecessária assim: 
 PROGRAM media;
 VAR soma, nota : real;
 cont : integer;
 BEGIN
 soma := 0;
 cont := 0;
 nota := 0;
 write('nota: ');
 readln(nota)
 WHILE nota <> -1 DO BEGIN
 soma := soma + nota;
 cont := cont + 1;
write('nota: ');
 readln(nota)
END;
 writeln('A média é ',soma/cont)
 END.
152
Agora sim... o -1 não entra na soma nem faço somas desnecessárias. 
E qual era o segundo erro? E se da primeira vez o usuário puser de cara um -1? Aí 
soma=0, cont=0 e soma/cont=0/0 = erro! Então temos que por um teste no final: 
 PROGRAM media;
 VAR soma, nota : real;
 cont : integer;
 BEGIN
 soma := 0;
 cont := 0;
 nota := 0;
 write('nota: ');
 readln(nota)
 WHILE nota <> -1 DO BEGIN
 soma := soma + nota;
 cont := cont + 1;
write('nota: ');
 readln(nota)
END;
 IF cont>0 THEN writeln('A média é 
',soma/cont)
END.
Pronto! 
153
TIPO BOOLEAN 
Variáveis booleanas são variáveis capazes de conter apenas 1 de 2 valores: verdadeiro 
ou falso. 
Como as condições no IF retornam verdadeiro ou falso são chamadas booleanas. Note 
que, em x > 2, x não é booleano, mas o resultado da expressão é. 
Como defino uma variável booleana? 
VAR v : boolean;
E como abasteço um valor nessa variável? Assim, a forma geral do comando IF é: 
 PROGRAM abastece;
 var b1,b2 : boolean;
a,b,c : integer;
 BEGIN
 a := 2;
 b := 3;
 c := 1;
 b1 := true;
 b2 := false;
b2 := a > b; {aqui b2 é "false", pois a é menor que b}
 b1 := (a>b) AND (b>c); {b1 recebeu false, confira}
b2 := (a>b) OR NOT (b>c);
etc
 END. 
Opa! Quem é esse NOT? É a negação! 
 NOT true = false
 NOT false = true
Vejamos um exemplo: suponha que queremos que b1 seja verdadeira se b2 for falsa e 
vice-versa. Como farei? Um modo horrendo é: 
 IF b2 THEN b1 := false
 ELSE b1 := true;
Mas isso pode, e DEVE, ser substituído por: 
 b1 := NOT b2;
O efeito é o mesmo, confira, e o programa fica menor. 
154
Note também que não fiz: 
IF b2 = true THEN b1 := false
ELSE b1 := true;
Por que? Porque é redundante. Quando o IF acima será executado? Quando o resultado 
de (b2 = true) for verdadeiro, ou seja, true. E, para que isso ocorra, que valor b2 deve 
ter? true. Então b2 = true equivale a simplesmente ler o valor de b2. 
Mas e se quiséssemos que algo fosse executado se uma variável for false? Abaixo você 
vê as duas maneiras, a segunda é preferível: 
 modo 1:
 IF b1=false THEN faz algo;
modo 2:
 IF NOT b1 THEN faz algo
Agora confira e veja que as duas formas agem da mesma maneira: se a condição for 
verdadeira, faz e, para a condição ser verdadeira, ou b1 é false ou NOT b1 é verdadeiro 
=> b1 é false. 
OPERADORES BOOLEANOS 
AND, OR e NOT sao operadores booleanos, porque agem em expressoes ou variaveis 
booleanas. 
Suponha que temos duas variaveis booleanas a e b, a seguir temos uma tabela com seus 
valores e os resultados das operaçoes: 
a b a AND b a OR b NOT a NOT b
True True True True False False
True False False True False True
False True False True True False
False False False False True True
Ou seja: 
AND True False
True True False
False False False
OR True False
True True True
False True False
NOT
True False
False True
Essas tabelas sao chamadas de tabelas verdade. 
155
Lembra do nosso programa de chute? Suponha que, ao final do programa queiramos 
dizer que acabaram-se as chances do usuario, mas queremos dizer isso somente se ele 
errou todas as vezes. Vomo fazemos? Veja abaixo: 
 PROGRAM chute;
 CONST num = 5; {valor a ser adivinhado}
 VAR n : integer; {o chute do usuário}
 c : integer; {contador do for}
 acertou : boolean; {indica se o usuario acertou}
 BEGIN
 writeln('Você tem 10 chances');
 acertou := false;
 FOR c := 1 TO 10 DO
BEGIN
 write('seu chute: ');
 readln(n);
 IF n = valor THEN
 BEGIN
 writeln('acertou"');
 acertou := true;
 c := 10
 END;
 if n > valor then writeln('seu palpite foi maior');
 if n < valor then writeln('seu palpite foi menor')
 END;
 IF NOT acertou THEN writeln('suas chances acabaram');
END.
Por fim, lembre que as únicas operações permitidas em booleanos são AND, OR e 
NOT. +, - etc não funcionam porque não tem lógica, afinal, quanto é true + 1? E true + 
false? 
TIPO REAL 
As mesmas operações permitidas com integer podem ser usadas com real. Vale lembrar 
que "-" pode indicar subtração de dois valores ou indicar que o valor é negativo: 
 x := 2.5 - 1.43;
 x := -3.12;
Agora vamos ver uma aplicação: vamos calcular quanto tempo passa, pela relatividade, 
em uma nave se movendo a uma velocidade v, enquanto que na Terra passaram n horas. 
A fórmula é: 
Tn = TT ¥�1 - v²/c²)
onde Tn é o tempo na nave, TT é o tempo na Terra e c é a velocidade da luz no vácuo. 
156
Mas, peraí! Como calculo o quadrado e a raíz? 
x := sqr(y); x recebe y²
 x := sqrt(y); x recebe 
lembre-se de que x deve ser real. Naturalmente, x := y*y; também funciona. 
Então o programa fica: 
 PROGRAM relat;
 CONST c = 300000; {km/s}
 VAR tt : real; {tempo na terra (s)}
 tn : real; {tempo na nave (s)}
 v : real; {velocidade da nave (km/s)}
BEGIN
 write('vel (km/s): );
 readln(v);
 tt := 60; {1 minuto}
 tn := tt * sqrt(1 - (sqr(v) / sqr(c)));
writeln('t na nave é: ',tn:4:2,' s, t na terra é ',tt:4:2,' s')
 END.
CONVERSÃO DE TIPOS 
Como fazemos para converter entre real e integer? Para isso, pascal tem as seguintes 
regras: 
? Expressões integer são automaticamente convertidas para real. 
? Expressões real devem ser convertidas explicitamente para integer. 
Então, o seguinte vale: 
 VAR a : integer;
 b : real;
 BEGIN
 b := a;
 b := a/2;
 etc
 END.
Mas como convertemos de real para integer? Depende do que você quer que seja feito 
com o número. Podemos: 
157
? arredondar: por exemplo, de 4.5 para 5; de 4.7 para 5; de 4.3 para 4. 
? truncar: de 4.5 para 4; de 4.7 para 4; de 4.3 para 4. 
Ou seja, ou arredondo, ou trunco. No caso do último, só a parte inteira é considerada. 
Se quisermos truncar: 
 x := trunc(4.7); x terá 4
Se quisermos arredondar: 
 x := round(4.7); x terá 5
A forma geral das funções é: 
Trunc(x : real) : longint
 Round(x : real): longint
o que significa que trunc e round recebem um valor real edevolvem um longint. 
Mas, e se o número for negativo? Nada muda: 
 Trunc(-expressão) = -
Trunc(expressão)
 Round(-expressão) = -
Round(expressão)
Naturalmente, qualquer expressão real pode ser usada dentro de trunc ou round. 
Vejamos alguns exemplos: 
Valor Trunc(valor) Round(valor)
5.0 5 5 
4.5 4 5 
4.99999 4 5 
4.49999 4 4 
4.2 4 4 
4.7 4 5 
-5.0 -5 -5 
-4.5 -4 -5 
-4.2 -4 -4 
-4.7 -4 -5
158
O COMANDO IF 
Suponha que queremos um programa onde o usuário adivinha um número que 
definimos. Como fazemos isso? 
1. Pedimos o número ao usuário. 
2. Se ele adivinhou, aviso. 
Como eu faço a segunda parte? Para ele ter adivinhado, o número que o usuário deu 
deve ser igual ao número que definimos. Suponha que este número pré-definido seja 5. 
Então a parte 2 fica: 
1. Pedimos o número n ao usuário. 
2. Se n = 5 então digo que ele 
acertou. 
E como faço isso em Pascal? 
 PROGRAM adivinha;
 CONST valor = 5;
 VAR n : integer; {o chute do 
usuário}
BEGIN
 write('seu chute: ');
 readln(n);
 IF n = 5 THEN write('acertou!')
END.
note que é n = 5 e não n := 5. 
Assim, a forma geral do comando IF é: 
 IF condição THEN comando;
e, da mesma forma que o FOR: 
IF condição THEN
 BEGIN
 comando1;
comando2;
 ...
 comandon
 END;
Esse comando diz que se a condição for verdadeira, então o comando (ou grupo de 
comandos entre BEGIN e END) que vem após o THEN ser'executado. Se não for 
verdadeira, ele não será executado. 
159
CONDIÇÕES 
Mas, afinal, que tipo de condições podemos usar no IF? Qualquer tipo de comparação 
envolvendo constantes, variáveis, valores ou expressões: 
Condição Significado Exemplo
expressão1 = expressão2 igual 5 = 6 é falso 
expressão1 < expressão2 menor 5 < 6 é verdadeiro 
expressão1 <= 
expressão2
menor ou 
igual 
5 <= 6 é 
verdadeiro 
expressão1 > expressão2 maior 5 > 6 é falso 
expressão1 >= 
expressão2
maior ou igual 5 >= 6 é falso 
expressão1 <> 
expressão2
diferente 
5 <> 6 é 
verdadeiro 
Vamos melhorar nosso exemplo de adivinhar números. Agora ele compara os números 
e, se o usuário adivinhou, pára o FOR. Ele dá também dicas ao usuário se o chute é 
maior ou menor e 10 chances, no máximo, para acertar: 
 PROGRAM adivinha;
 CONST valor = 5;
 VAR n : integer; {o chute do usuário}
 c : integer; {contador do for}
BEGIN
 writeln('Você tem 10 chances');
 FOR c := 1 TO 10 DO
 BEGIN
 write('seu chute: ');
 readln(n);
 IF n = valor THEN
 BEGIN
 writeln('acertou"');
 c := 10
 END;
 if n > valor then writeln('seu palpite foi maior');
 if n < valor then writeln('seu palpite foi menor')
 END
 END.
Viu como fizemos para sair do FOR? Enganamos a máquina, fazendo ela achar que esta 
era a iteração de número 10 e, portanto, a última. 
Atenção! E s s e m o d o d e s a i r d o F O R é H O R R E N D O e e x t r e m a m e n t e 
DESADONSELHÁVEL. Além disso, NÃO se pode garantir que o compilador que você 
usa irá fazer isso mesmo. Em Free Pascal isso funciona. Mas, então, por que está sendo 
apresentado? Mais adiante você verá comandos que interrompem o ciclo quando uma 
160
determinada condição for satisfeita. No momento, essa "interrupção" terrível do FOR 
pode servir para mostrar a você como o FOR funciona e qual a importância de seu 
contador, sua variável de controle. Por isso vale lembrar... NUNCA FAÇA ISSO! 
Mas esse programa não está bem escrito. Veremos agora por quê. 
ELSE 
Suponha agora que queremos dizer que o usuário errou ou acertou. Ou seja, queremos 
tomar a seguinte decisão: 
Se o usuário acertou, escrevo 
"acertou!" 
Senão escrevo "errou" 
Como faço isso em Pascal? 
IF n = 5 THEN writeln('acertou!')
ELSE writeln('errou!');
Notou a falta do ";" após o writeln? Antes do ELSE NUNCA bote ";". Se puser, o 
compilador reclamará. 
Então, de um modo geral, o IF fica: 
 IF condição THEN comando1
 ELSE comando2;
e, nesse caso, se a condição for verdadeira, então comando1 é executado. Se não for 
verdadeira, o comando2 é executado. 
Ou seja, se condição for verdadeira, o que vier depois do THEN é executado e o ELSE é 
pulado. Se for falsa, o que vem após o THEN é pulado e o ELSE é executado. 
Da mesma forma que antes, em vez de um comando podemos ter blocos de comandos: 
IF condição THEN
 BEGIN
 comando1;
...
 comandon
 END { --> note a falta do ";" }
ELSE BEGIN
 comandok;
 ...
 comandoj
 END;
Vamos, agora, reescrever nosso programa anterior: 
161
 PROGRAM adivinha;
 CONST valor = 5;
 VAR n : integer; {o chute do usuário}
 c : integer; {contador do for}
BEGIN
 writeln('Você tem 10 chances');
 FOR c := 1 TO 10 DO
 BEGIN
 write('seu chute: ');
 readln(n);
 IF n = valor THEN
 BEGIN
 writeln('acertou"');
 c := 10
 END
 ELSE {n <> valor}
 IF n > valor THEN writeln('seu palpite foi maior')
 ELSE { n < valor }
 writeln('seu palpite foi menor')
END
 END.
Viu como sumimos com uma comparação? Do modo modo como o programa estava, 
quando o usuário tinha acertado, ainda assim a máquina comparava para ver se era > e 
para ver se era <, uma perda de tempo. 
Agora, se for =, a parte do ELSE não é executada. 
Da mesma forma, antes, se era >, ainda assim fazia o teste para <, que daria falso. 
Agora esse teste não é feito. 
Além desses ganhos, ganhamos com a lógica. Por que o terceiro if sumiu? Porque era 
desnecessário, veja: 
? inicialmente, o palpite poderia ser qualquer coisa. 
? se for = acerto, então não faço mais testes 
? senão, já tenho uma informação, é diferente. 
? ao fazer o segundo IF, sei que é diferente, pois o IF está dentro do ELSE do IF 
que testou se era igual. 
? se for maior, então o IF é executado e pula o ELSE 
? senão, tenho duas informações: não é igual nem maior, logo, é menor. Por isso 
não preciso nem testar. 
Mas há um problema com o IF. Há uma ambigüidade que surge quando usamos IFs 
aninhados. Por exemplo: 
 IF condição1 THEN
 IF condição2 THEN
comando1
 ELSE comando2;
162
Quando comando2 será executado? Ou seja, o ELSE é de qual IF? Não deixe a 
edentação errada te enganar! Nesse caso, o computador casa o ELSE sempre com o 
último IF que não esteja impedido. Assim, comando2 será executado se condição1 for 
verdadeira e condição2 for falsa; e comando1 se ambas as condições forem verdadeiras. 
E se fizermos assim: 
 IF condição1 THEN
 BEGIN
 IF condição2 THEN
comando1
 END
 ELSE comando2;
Nesse caso, o ELSE é do primeiro IF, pois isolamos o segundo dentro do corpo do 
primeiro, impedindo o segundo IF. Então comando2 é executado somente se condição1
for falsa. 
No código seguinte: 
IF condição1 THEN
 IF condição2 THEN comando1
ELSE comando2
 ELSE comando3;
comando1 é executado se condição1 e condição2 forem verdadeiras, comando2 se 
condição1 for verdadeira e condição2 for falsa, e comando3 se condição1 for falsa. 
Note como a edentação deixa realmente o código mais legível. 
AND 
Suponha que queremos executar um comando somente quando duas condições, C1 e C2, 
forem verdadeiras. Queremos algo como: 
 se C1 e C2 forem verdadeiras
 então faça comando
Como fazemos isso em Pascal? 
IF (C1) AND (C2) THEN comando;
Note os parênteses em volta das condições. Eles precisam estar aí. 
OR 
163
Suponha agora que queremos executar um comando quando uma de duas condições (ou 
ambas) forem verdadeiras. Então queremos algo assim: 
 se C1 ou C2 forem verdadeiras,
 então faça o comando
Em Pascal isso é: 
 IF (C1) OR (C2) THEN comando;
note novamenteos parênteses. 
164
ANIMAÇÃO BÁSICA 
O que o programa abaixo faz? 
BEGIN
 FOR i:=1 to 20 do write('*');
writeln
 END.
Escreve 20 '*' certo? E como você vê a saída?
 ********************
Como o computador escreveu?
 *
 **
 ***
 ...
 ********************
E por que você não viu isso? Porque foi muito rápido! Agora considere o programa:
FOR c:=1 TO 20 DO 
 BEGIN
 write('*');
atrasa
 END;
 writeln;
se "atrasa" for suficientemente longo, então veremos a animação, que corresponde a 
uma barra de * que cresce da esquerda para a direita. 
Como fazemos o atraso? Uma maneira horrível pode ser:
 PROCEDURE atrasa;
 VAR a,b,c : integer {contadores}
BEGIN
 FOR a:=1 TO 1000 DO
 FOR b:=1 to 10000 DO
 FOR c:=1 TO 10000 DO 
{nada};
END;
Isso vai ficar contando até 10¹². É um atraso. 
165
Mas tem que haver um meio mais inteligente de gerar esse atraso. E tem! Em pascal 
existe o comando delay(t), que gera um atraso de t milissegundos. Para que delay 
funcione, não esqueça de incluir "USES crt;" logo abaixo da cláusula "PROGRAM". 
Então nosso programa pode ser:
 FOR c:=1 TO 20 DO
 BEGIN
 write('*');
delay(500)
 END;
Mas isso ainda é limitado, não? Afinal, a tela não é só uma linha. Ela tem altura e 
largura, e poderíamos querer por um '*' em algum lugar pré-definido dela. Como 
faríamos então? 
Antes de mais nada, temos que considerar a tela como uma grande matriz de n linhas 
por m colunas. Um grande quadriculado. Então a tela é:
0 1 2 ... m
0 
1 
2 
... 
n 
onde n e m dependem do tamanho do monitor. Note que o (0,0) é no canto superior 
esquerdo. 
Como fazemos então para por um '*' na posição (2,3) -> linha 3, coluna 2? Usando 
gotoxy:
 BEGIN
 gotoxy(2,3);
 write('*')
END.
Assim, gotoxy posiciona o cursor na coordenada (x,y) = (2,3) e write escreve la´um '*'. 
Fácil não? Novamente, não esqueça de incluir "USES crt;". 
Agora, como fazermos para fazer com que um '*' ande das coordenadas (2,2) até (20,2), 
ou seja, que ande 18 posições na linha 2? Um algoritmo para isso seria:
 desenho um * na posição pos
 espero
 para pos de 2 a 20 faça:
 apago o * em pos
 desenho um * em pos+1
 espero 
166
E como apago o '*'? Simples, desenho um espaço em branco em cima dele. Ou seja, 
pinto na mesma cor da tela. Então o programa é:
gotoxy(2,2);
 write('*');
 delay(500);
FOR x := 2 TO 19 DO {19 porque a última linha irá escrever no 20}
BEGIN
 gotoxy(x,2);
 write(' ');
 gotoxy(x+1,2);
 write('*');
delay(500)
 END; 
Você vai ver o '*' passar de x:=2 a 20. Peraí. 20? Então por que no FOR tem um 19? 
Porque o último write será posto em x+1 e, se x for 19, esse último '*' irá em x = 20. 
Agora, para finalisar esse pequeno desvio que fizemos, vamos derrubar um ovo. Vamos 
desenhar algo que, ainda que vagamente, lembre um ovo e fazê-lo cair 20 posições a 
partir de uma posição inicial constante. 
Que algoritmo usamos? o mesmo:
 desenho o ovo
 espero
 para y = yinicial até yinicial + 20
 apago o ovo
 desenho o ovo em y+1
 espero
E como vamos desenhar o ovo? Bom, com o que sabemos até agora podemos criar um 
procedimento para desenhar o ovo e um para apaga. E como saberemos onde desenhar? 
É só fazer com que os procedimento leiam a posição inicial do ovo em variáveis 
globais. Lembre-se: há um modo melhor, mais inteligente e mais seguro de fazer isso, 
mas só veremos mais tarde. Então vamos lá:
 PROGRAM queda;
 USES crt;
 CONST xin = 10; {o x inicial}
yin = 2; {o y inicial}
 VAR x,y : integer; {coordenadas}
c : integer; {contador do for}
PROCEDURE desenha_ovo;
 BEGIN
 gotoxy(x+1,y);
 write('*');
 gotoxy(x,y+1);
 write('* *');
gotoxy(x,y+2);
 write('* *');
167
 gotoxy(x+1,y+3);
write('*')
 END;
 PROCEDURE apaga_ovo;
 BEGIN
 gotoxy(x+1,y);
 write(' ');
gotoxy(x,y+1);
 write(' ');
 gotoxy(x,y+2);
write(' ');
 gotoxy(x+1,y+3);
 write(' ')
END;
 BEGIN
 x := xin; {inicializo a coordenada}
 y := yin; {inicializo a coordenada}
 desenha_ovo;
delay(500);
 FOR c := yin TO (yin+20) DO
BEGIN
 apaga_ovo;
 y := y+1; {coordenada onde desenho o próximo ovo, x é o mesmo}
desenha_ovo;
 delay(500)
 END
 END.
O que "desenha_ovo" faz? Desenha um ovo na posição x,y (veja abaixo):
x x+1 x+2
y *
y+1 * *
y+2 * *
y+3 *
E "apaga_ovo"? Desenha o mesmo ovo, só que com espaços em vez de *. O corpo do 
programa faz, então, a animação. 
Obs: Notou a falta de ";" no último write dos procedimentos, no delay do FOR e no 
END do FOR? Isso funciona porque antes de um END o ";" não é necessário. Tudo 
funciona se você colocar, mas não é necessário. 
Pronto. Estamos derrubando o ovo. Mas note uma coisa: a velocidade de queda é 
constante. O tempo entre cada desenhar do ovo é constante, ou seja, se o ovo cai 20 
posições, o fará em tempo 20 × t (tempo do atraso), a uma velocidade de 1 pos/t. Mas, e 
se quisermos incluir uma aceleração? Basta variarmos o atraso a um passo constante. 
Por exemplo:
Passo Atraso
168
1 0.5
2 0.4
3 0.3
4 0.2
O programa leva cada vez menos tempo para percorrer a mesma distância de um passo, 
ou seja, a velocidade está aumentando. Como a redução do tempo se dá em um passo 
constante, a velocidade aumenta em um passo constante também, ou seja, a aceleração é 
constante. 
Então, se quisermos incluir uma gravidade em nossa queda, teríamos que fazer algo 
assim:
 desenha_ovo;
 delay(60 * g); {600 para g = 10}
FOR c := yin TO (yin+20) DO
BEGIN
 apaga_ovo;
 y := y+1; {coordenada onde desenho o próximo ovo, x é o mesmo}
 desenha_ovo;
 delay((60 - c) * g) {reduz o tempo de g em g}
 END
Obs: Lembre-se de que delay aceita somente valores inteiros positivos. 
ENTRADA 
Como fazemos se quisermos que o usuário nos dê uma informação? Por exemplo, se 
quisermos calcular a média de um aluno, como fizemos até hoje? 
Bom, até hoje, modificávamos o programa, abastecendo, para cada aluno, as notas, 
compilando e executando o programa. Bastante besta não? 
O que gostaríamos de fazer é escrever o programa uma só vez e então executá-lo e 
deixar que ele peça as notas. Como fazemos isso? Com os comandos read e readln. 
Considere o programa: 
PROGRAM teste_read;
 VAR n : real;
 BEGIN
write('digite um número: ');
 readln(n);
 writeln('você digitou ',n:3:2)
 END.
 Saída:
169
 digite um número: 5
 você digitou 5.00
E se trocarmos readln por read? 
PROGRAM teste_read;
 VAR n : real;
 BEGIN
write('digite um número: ');
 read(n);
 writeln('você digitou ',n:3:2)
 END.
 Saída:
 digite um número: 5você digitou 5.00
Viu a diferença? 
Então: 
? read lê a entrada e posiciona o cursor após o final desta. 
? readln lê a entrada e dá uma nova linha, ou seja, posiciona o cursor na linha de 
baixo. 
Assim como o writeln, você pode usar "readln;" se quiser apenas uma resposta, mas não 
armazená-la, assim, o seguinte programa: 
PROGRAM p;
 BEGIN
 readln
 END.
não terminará até que "enter" seja pressionado, aí o sistema dá uma nova linha e sai. Se 
usarmos "read;" em vez de "readln;", a nova linha não será dada. Cabe a você decidir 
quando usar cada um. 
Então, basicamente: 
read(n) e readln(n) lêem uma entrada que o usuário digitou e, após ele dar "enter" o 
comando guarda essa entrada em n. Naturalmente, se o tipo de entrada dada for 
diferente do tipo de n, o programa gerará um erro. 
Por exemplo, se n for integer e o usuário digitar "3.5", na horaque o read for ler dará 
erro. Tem como evitar esse erro, mas é assunto para um curso mais avançado. 
Vamos, então, escrever o programa de notas: 
 PROGRAM notas;
170
 VAR p1,p2,p3 : real; {notas das provas}
 m : real; {média das provas}
BEGIN
 write('nota p1: ');
 readln(p1);
 write('nota p2: ');
 readln(p2);
 write('nota p3: ');
 readln(p3);
 m := (2*p1 + 3*p2 + 5*p3) / 10;
writeln('a média é ',m:4:2)
 END.
Nesse caso, queremos somente 3 dados. Mas, e se quisermos usar um número de dados 
que não é conhecido quando escrevemos o programa? Por exemplo, suponha que 
queremos achar a média aritmética simples de n dados, onde n é uma entrada do 
usuário. Considere o programa: 
 PROGRAM notas;
 VAR n : integer; {número de dados}
 num : real; {número digitado}
 media : real; {média dos dados}
 cont : integer; {contador do for}
 soma : real; {soma dos dados}
 BEGIN
 write('Quantos dados serão? ');
 readln(n);
 soma := 0;
 FOR cont := 1 TO n DO
 BEGIN
 write('entre um dado: ');
 readln(num);
 soma := soma + num
 END;
 media := soma / n;
 writeln('a média é ',media:4:2)
 END.
Percebeu o que aconteceu? O usuário disse quantos números ía dar e depois entrou cada 
um dos números. O oprograma, então, somava-os à medida que estes eram dados pelo 
usuário e, no final, apresentava a média. 
Ou seja, o que o programa fez foi calcular 
media = 
(™di) /n
n
onde n e cada di foi dado pelo usuário quando da execução do programa. 
171
CONSTANTES 
Suponha que queremos que uma determinada variável tenha sempre o mesmo valor no 
programa, sem que possamos modificar esse valor. Mas então não queremos uma 
variável, e sim uma constante. 
Como defino uma constante em Pascal? Quase como uma variável: 
 PROGRAM nome;
 CONST cte1 = valor1;
cte2 = valor2;
 VAR v1 : tipo1;
 v2 : tipo2;
 PROCEDURE ...
 BEGIN
 ...
 END.
Assim, por exemplo, se faço CONST l = 3.5;, l terá sempre esse valor no programa, não 
podendo ser modificada, ou seja, se eu fizer l:=2; em algum lugar do programa, um erro 
será dado. 
Mas afinal, por que usar uma constante em vez de por diretamente seu valor no 
programa? Ou seja, por que fazer CONST cte = 10; e não por 10 em todo lugar que 
precisar no programa? Suponha que usamos esse valor 50 vezes no programa. Agora 
suponha que precisamos rodar esse programa mas com um valor diferente. Temos que 
fazer 50 substituições. Se tivéssemos usado a constante, só precisaríamos substituir o 
valor na linha CONST. 
De resto, uma constante pode ser usada como usaríamos um valor qualquer. 
Vamos ver agora um exemplo: 
Fatorial
Vamos calcular o fatorial de um número dado pelo usuário. Como faremos? 
? leio o número, n 
? faço 1 × 2 × 3 × ... × n 
E como fica isso em Pascal? 
 PROGRAM fatorial;
 VAR n : integer; {o número cujo fatorial é calculado}
 c : integer; {contador para o for}
 r : integer; {resultado do fatorial}
 BEGIN
172
 write('número: ');
 readln(n);
 r := 1; {inicializo r}
 {calculo o fatorial de n}
 FOR c := 1 TO n DO r := r * c;
 writeln('resultado: ',r)
 END.
O que esse programa fez, foi n! = n × (n-1)!, onde o (n-1)! era guardado em r a cada 
iteração. De fato, para calcular 5!, calculamos os 5 primeiros fatoriais. 
Mas, e se n = 0? Nesse caso o laço FOR não será executado. E qual o valor de r? 1, 
exatamente 0!.

Mais conteúdos dessa disciplina

Mais conteúdos dessa disciplina