Buscar

Algoritmo e programao

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 172 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 172 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 172 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

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...............................................................................................................................162
OR ..................................................................................................................................162ANIMAÇÃ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 maiusculas e 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 escreverna 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 desenheum 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óriaapontada 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ço q 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 quequeremos 
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 fila comum. 
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;
 {eliminop}
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 arquivo que 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,

Outros materiais