ALGORITMOS
COM PASCAL
Prof. Miguel Jonathan – Dept. Ciência da Computação – IM/UFRJ – 2003 –
versão 1.0
Desvio incondicional
- o comando goto
A grande maioria dos programas de computador precisa repetir muitas vezes um mesmo comando, ou grupo de comandos, para realizar a sua tarefa.
Na fase inicial da programação, quando ainda não haviam programas muito grandes, as linguagens de programação dispunham apenas do comando goto (literalmente significando “vá para”) para forçar a repetição de comandos. A ele dá-se o nome de desvio incondicional.
Apesar do seu uso não ser mais recomendado hoje em dia, a compreensão do funcionamento do comando goto ajuda bastante a entender o funcionamento dos modernos comandos de repetição que serão vistos mais adiante.
O comando goto é
usado junto com um ponto de retorno chamado de rótulo (label em
inglês). Qualquer comando Pascal pode ser precedido por um rótulo seguido de :
e o comando goto pode ser usado para forçar um retorno do programa para
qualquer um dos rótulos definidos. Rótulos são declarados na seção de
declarações do programa, precedidos da palavra-chave label. Um rótulo pode ser qualquer identificador,
ou um inteiro entre 0 e 9999. A sintaxe do comando é: goto <nome do rótulo>
Os exemplos abaixo ajudam a entender o mecanismo.
Seja obter a soma dos inteiros de 1 até um valor n qualquer maior que 1:
Exemplo 4.1 :
01:program testgoto;
02:var x,soma,n:integer;
03:label 1;
04:begin
05:soma:=0;
06:x:=1;
07:write('Ate'' que numero deseja
somar os inteiros? ');
08:readln(n);
09:1: soma:=soma+x;
10:x:= x+1;
11:if x <= n then
goto 1;
12:writeln('A soma de 1 a ', n, ' e''
igual a ', soma);
13:end.
No programa acima, as linhas estão numeradas para melhor compreensão das explicações. A seqüência de comandos acima fará com que o programa fique repetindo os comandos das linhas 9, 10 e 11 enquanto o valor de x não ultrapassar o valor de n. Outra maneira de dizer a mesma coisa, é dizer que essas linhas serão repetidas até que o valor de x ultrapasse o valor de n. Os comandos entre um rótulo e o comando goto para esse rótulo recebem o nome de laço de repetição.
O programa seguinte mostra um exemplo mais complexo. Desejamos imprimir a seqüência de inteiros da forma:
122333444455555 etc.
para inteiros variando de 1 até um valor máximo n.
Note que a seqüência tem um laço dentro de outro laço. O laço mais “externo” faz com que os números da seqüência variem de 1 até n, e o laço mais “interno” faz com que, para cada numero k, entre 1 e n, este seja repetido k vezes.
Exemplo 4.2 :
01:program
tesgoto2;
02:var
x,k,n:integer;
03:label
1,2;
04:begin
05:write('Valor
maximo da sequencia(< 20): ');
06:readln(n);
07:k:=0;
08:1: k:= k+1;
09:
x:=1; {x conta quantas vezes k sera' escrito}
10:
2: write(k);
11:
if x<k then
12:
begin
13:
x:= x+1;
14:
goto 2;
15:
end;
16:if k<n then goto 1;
17:end.
No programa acima, os comandos das linhas 08 a 16 formam o laço mais externo, e os comandos das linhas 10 a 15 formam o laço mais interno.
O comando while
O comando while permite eliminar completamente a necessidade de comandos goto explícitos, sem impedir que se possa construir laços de repetição em programas. Com isso, evita-se o uso indiscriminado do comando goto , e ao mesmo tempo o programa ganha mais estrutura. A técnica que evita o comando goto, e utiliza apenas o comando while e equivalentes para laços de repetição, é chamada de programação estruturad
Forma sintática: while <expressão lógica> do <comando-a-repetir>
Tradução literal: enquanto <expressão lógica> faça <comando>
Significado:
“A expressão lógica é calculada. Se o seu valor for True, o comando é executado,
e em seguida a expressão volta a ser calculada. Enquanto o valor da expressão
for True, o processo se repete: o comando é executado, e a expressão volta a
ser calculada. Caso o valor da expressão seja False, o comando não é executado,
e o controle passa para a próxima instrução após o while”.
O comando: while
<expressão lógica> do
<comando-a-repetir>
é equivalente ao trecho seguinte:
1: if
<expressão lógica> then begin <comando-a-repetir>; goto 1
end;
Note que, se a expressao lógica for falsa
logo na primeira vez que for calculada, o <comando-a-repetir> não será
executado nem uma vez. Obviamente, o <comando-a-repetir> deve conter
elementos que façam com que a expressão lógica se torne falsa após um número
finito de voltas, caso contrário o laço de repetição nunca terminará. Esse tipo
de erro chama-se de laço infinito, e quando ocorre diz-se, no jargão
popular de computação, que o programa entrou em “loop”. (“Loop” é a
palavra inglesa para laço, e pronuncia-se lup). A única forma de sair
desse erro é forçar o fim do programa. No ambiente Turbo Pascal isso é feito
pressionando a tecla Control (CTRL), e BREAK, simultaneamente.
Exemplo super simples: O programa abaixo imprime:
12345
Exemplo 4.3:
program
ex4_3;
var
i: integer;
begin
i:=0;
while i < 5 do
begin
i:= i+1;
write(i)
end;
end.
Esse programa equivale ao programa abaixo, que usa goto:
Exemplo 4.4:
program
ex4_4;
var
i: integer;
label
1;
begin
i:=0;
1: if i < 5 then
begin
i:= i+1;
write(i);
goto 1;
end;
end.
A seguir mostramos como ficam os exemplos 4.1 e 4.2 acima, quando o comando goto é substituído pelo comando while:
Exemplo 4.5:
program
ex4_5;
var
x,soma,n:integer;
begin
soma:=0;
x:=1;
write('Ate''
que numero deseja somar os inteiros? ');
readln(n);
while
x <= n do
begin
soma:=soma+x;
x:= x+1;
end;
writeln('A
soma de 1 a ', n, ' e'' igual a ', soma);
end.
Exemplo
4.6:
program
ex4_6;
(******************************************
Este programa imprime a seqüência
122333444455555... nnnn, de 1 a n.
Utiliza dois laços de repetição while,
um dentro do outro.
******************************************)
var
x,k,n:integer;
begin
write('Valor
maximo da sequencia(< 20): ');
readln(n);
k:=0;
while
k<n do
begin
k:= k+1;
write(k);
x:=1; {x conta quantas vezes k sera' escrito}
while x<k do
begin
write(k);
x:= x+1;
end; {fim do while interno}
end;
{fim do while externo}
end.
A linguagem Pascal ainda dispõe de dois outros comandos para construir laços de repetição:
O comando repeat
Forma sintática: repeat <seqüência de comandos a repetir> until <expressão lógica>
Tradução literal: repita
<seqüência de comandos a repetir> até <expressão lógica>
Significado:
“A seqüência de comandos é executada. A seguir, a expressão lógica é calculada. Se o seu valor for False, a seqüência de comandos volta a ser executada e, em seguida, a expressão é novamente calculada. O processo se repete até que valor da expressão se torne True. Nesse momento, o comando repeat termina, e o controle passa para o próximo comando do programa.”
A diferença principal de significado entre o comando while e o comando repeat é que, no comando repeat, a seqüência de comandos a repetir é executada sempre pelo menos uma vez, enquanto que no comando while o comando a repetir pode não ser nunca executado.
Há outras diferenças mais sutis, somente na forma:
a) No comando while o que é repetido é “um comando”, enquanto que no comando repeat o que é repetido é “uma seqüência de comandos”.
A diferença é apenas na forma de escrever (sintática): se você quiser repetir uma seqüência de comandos com while, basta colocá-las dentro de um bloco begin ....end, e com o comando repeat, não é necessário envolver a seqüência em um bloco. O motivo é que as palavras repeat e until já são suficientes para indicar ao compilador o inicio e o fim dos comandos a repetir.
b) No comando while, o teste para saber se o comando terminou é verificar se a expressão lógica se torna false. No comando repeat, o teste para saber se o comando terminou é quando a expressão se torna true (verdadeira). O motivo é que o significado do comando while é : enquanto a expressão for verdadeira, faça algo, e o do comando repeat é faça algo até que a expressão se torne verdadeira.
O exemplo abaixo mostra como fica o programa do exemplo 4.3 quando o while é substituído por um repeat:
Exemplo 4.7:
program
ex4_7;
(************************
uso de repeat..until
************************)
var
i: integer;
begin
i:=0;
repeat
i:= i+1;
write(i)
until i>=5
end.
Note as diferenças em relação ao Exemplo 4.3:
- a expressão lógica i>=5 é o oposto da expressão anteior i<5
- não foi necessário envolver os comandos a repetir em um bloco begin-end.
O comando for
O comado for é uma forma abreviada de se escrever o comando while, para alguns casos particulares mais freqüentes. A descrição abaixo se refere ao caso em que a variável de controle é inteira, mas esse comando pode ser usado com qualquer variável de controle que seja ordinal, ou seja, cujos elementos possuam uma ordem determinada, como é o caso dos caracteres e outros tipos enumerados ainda não vistos.
Formas sintáticas:
for
<variável de controle> := <expressão inicial inteira> to <expressão final inteira> do
<comando a repetir>
Significado:
“a expressão inicial é calculada e a
expressão final é calculada (ambas inteiras) com os valores na memória no
momento em que o comando for inicia. A variável de controle recebe o
valor inicial. Se esse valor for menor ou igual que o valor final, então
o comando a repetir é executado, a variável de controle é incrementada
de 1 unidade, e o novo valor da variável é comparado com o valor final.
Enquanto o valor da variável de controle for menor ou igual ao valor final, o
comando a repetir será novamente executado, e a variável novamente
incrementada. O comando termina quando o valor da variável de controle ficar maior
que o valor final.”
IMPORTANTE: a expressão inicial e final são calculadas apenas uma vez, no inicio da execução do comando for. Mesmo que valores de variáveis que façam parte da expressão final forem alterados pelo comando a repetir, isso não altera o valor final que será usado nos testes de comparação.
A segunda forma sintática, ligeiramente diferente, é a seguinte:
for <variável de controle> := <expressão inicial inteira> downto <expressão final inteira> do <comando a repetir>
Significado:
“a expressão inicial é calculada e a
expressão final é calculada (ambas inteiras) com os valores na memória no
momento em que o comando for inicia. A variável de controle recebe o
valor inicial. Se esse valor for maior ou igual que o valor final, então
o comando a repetir é executado, a variável de controle é decrementada
de 1 unidade, e o novo valor da variável é comparado com o valor final.
Enquanto o valor da variável de controle for maior ou igual ao valor final, o
comando a repetir será novamente executado, e a variável novamente
decrementada. O comando termina quando o valor da variável de controle ficar menor
que o valor final.”
A diferença é que a variável de controle é incrementada no primeiro caso, e decrementada no segundo caso.
Exemplo 4.8:
Programa para escrever a seqüência:
123....n para um n inteiro
qualquer.
program
ex4_8;
(**************************
uso de for incrementando
a variável de controle
**************************)
var
i,n: integer;
begin
write ('Digite um valor de n inteiro: ');
readln(n);
for i:= 1 to n do write(i);
end.
Compare com o programa 4.3 ou 4.7. Não é necessário incrementar a
variavel i explicitamente, pois isso é feito automaticamente pelo comando for.
E também não é preciso fazer o teste se i
ainda é menor que n, pois isso também é feito automaticamente. Com isso
o programa fica simplificado. A forma ideal de “ler” o programa acima é: “para
i variando de 1
até 5, imprima o valor de i”.
O exemplo seguinte escreve a seqüência invertida, na forma: n n-1 .... 4321, para um n inteiro qualquer:
Exemplo
4.9:
program
ex4_9;
(**************************
uso de for decrementando
a variável de controle
**************************)
var
i,n: integer;
begin
write ('Digite um valor de n inteiro: ');
readln(n);
for i:= n downto 1 do write(i);
end.
O próximo exemplo imprime em uma única tela todos os caracteres da tabela.
Nota: em Pascal existem duas funções especiais pré-definidas, que servem para fazer a associação entre os caracteres e suas posições na tabela de caracteres. São elas:
ord (c) onde c é uma expressão que representa um caractere. A função retorna um inteiro entre 0 e 255, que é a posição (ou número de ordem) do caractere na tabela. Ex: ord (‘A’) é 65.
chr(n) onde n é uma expressão inteira com valor entre 0 e 255. A função retorna o caractere que fica na posição n da tabela. Por ex: chr(65) é ‘A’.
Seja agora escrever um programa para listar todos os 256 elementos da tabela em uma única tela de saída. A tela tem 24 linhas, com 80 caracteres em cada linha.
Podemos ver toda a tabela em uma única tela se tivermos 11 colunas, com 24 caracteres em cada uma (11 x 24 = 264). Para as 11 colunas caberem em uma linha, cada coluna deve ter 7 caracteres. A saída terá a aparência seguinte (apenas alguns caracteres são mostrados aqui, os demais estão representados por um -):
coluna
j®
0
1 2 3
4 5 6 7 8 9 10
linha
i
¯
0 - 24 - 48 0 72 H
96 - 120 x 144 -
168 - 192 - 216 -
240 -
1 - 25 -
49 1 73 I 97 a
121 y 145 - 169 -
193 - 217 - 241 -
2 - 26 -
50 2 74 J 98 b
122 z 146 - 170 -
194 - 218 - 242 -
..........................................................................
..........................................................................
23 -
47 - 71 G 95 -
119 w 143 - 167 -
191 - 215 - 239 -
O programa deve ter um laço de repetição para escrever as 24 linhas e, para cada linha, outro laço para escrever as 11 colunas.
Vamos usar a variável i para numerar as linhas de 0 a 23, e a variável j para numerar as colunas, de 0 a 10. Uma análise do quadro acima mostra que a posição do caractere k está na linha i e coluna j que satisfazem a relação: k = j* 24 + i .
O programa deve levar ainda em consideração que alguns caracteres não representam símbolos a serem escritos. Eles são usados como sinais de controle para o dispositivo de saída (monitor de vídeo ou impressora) e portanto não convém que se tente imprimi-los. No lugar deles, colocamos duas letras que indicam a sua função. São eles:
8 backspace, faz o cursor voltar uma posição para a esquerda (BS)
10 line feed, faz o cursor descer para a linha seguinte. É representado por LF
13 carriage return, ou retorno do carro, faz o cursor voltar para a posição inicial da linha (CR)
O caractere da posição 0 também não tem representação impressa, ele é o caractere nulo, na tabela representado por NUL. O caractere 7 também não tem representação impressa, e tem o nome de BEL.
O programa abaixo cria então a tabela desejada. Note que em cada coluna, o valor de k é escrito com 3 posições, seguido do caractere chr(k), ocupando 2 posições, e seguido de mais 2 espaços para completar as 7 posições da coluna. Para os caracteres especiais que não tem representação impressa, a expressão chr(k) é substituída por uma palavra adequada, ou por espaços:
program
tabela;
uses
crt;
var
i,j,k: integer;
begin
clrscr;
for i:= 0 to 23 do begin
for j:= 0 to 10 do begin
k:= j* 24 + i;
if k<=255 then begin
write(k:3);
case k of
0: write(' NUL');
7: write(' BEL');
8:
write(' BS ');
10: write(' LF ');
13: write (' CR ');
else write(chr(k):2, ' ');
end; {case}
end; {if}
end; {for interno}
writeln;
end; {for externo}
end.