You are on page 1of 51

ALGORITMOS COM PASCAL

Prof. Miguel Jonathan – Dept. Ciência da Computação – IM/UFRJ - 2003

CAPíTULO 1

TIPOS E VALORES:

A cada tipo básico da linguagem corresponde um conjunto de valores possíveis. Os tipos


que usaremos e que existem na linguagem Pascal, são inteiro, real, lógicoe caractere.
Valores podem ser armazenados em variáveis na memória da máquina, e podem ser
manipulados na unidade aritmética-lógica.
Tipos de valores disponíveis:
- números inteiros ex: 10 345 -27
- números reais ex: 2.45 2.450 2.4500 1267.54 (os 3 primeiros representam o
mesmo valor)
(e também em notação cientifica: 1.6754 x 103 ou 1.6754E+3 ou 1.6754e3 ou
0.126754E4 )
- valores lógicos (verdadeiro/sim e falso/não)
- caracteres (símbolos) ex: ‘*’ ‘?’ ‘G’ ‘p’ ‘4’

OPERAÇÕES:
Uma operação é realizada com valores, na Unidade Aritmética-Lógica da máquina, e
produz como resultado outro valor, que fica armazenado temporariamente nos registros,
podendo ser usado em operações subseqüentes.
As operações podem ser unárias ou binárias , dependendo se operam sobre um ou dois
valores. Uma operação é formada por um operador e um ou
doisoperandos (operação unária ou binária). Os operadores possíveis dependem do tipo dos
operandos envolvidos.

a) Operações sobre inteiros, com resultado inteiro:


operadores binários: + - * div e mod
+ (soma) ex: 10 + 30 resultado: 40
- (subtração) ex: 30 - 12 resultado: 18
* (multiplicação) ex: 20 * 4 resultado: 80
div (divisão inteira) ex: 30 div 4 resultado: 7
mod (módulo, ou resto da divisão inteira) ex: 30 mod 7 resultado: 2

operador unário: - (produz o negativo do seu operando)


ex: - 7 operador - aplicado sobre o operando 7 produz o resultado –7
-(-7) produz o resultado 7.

b) Operações sobre reais com resultado real:


operadores binários: + - * /
+ (soma) ex: 10.5 + 30.27 resultado: 40.77
- (subtração) ex: 30.2 - 12.8 resultado: 17.4
* (multiplicação) ex: 20.0 * 4.2 resultado: 84.0
/ (divisão real) ex: 30.0 / 4.0 resultado: 7.5

Caso a operação envolva um operando real e um inteiro, o resultado será sempre real:
30 – 2.5 resultado: 27.5
30 / 4.0 resultado: 7.5

O operador / quando usado com 2 operandos inteiros, produz o resultado


real: 30/4 resultado: 7.5

c) Operadores relacionais binários, operando sobre inteiros e reais, com resultado lógico:
> < >= <= <> =
> (maior) ex: 20 > 30 resultado: falso (não)
< (menor) ex: 20 < 30 resultado: verdadeiro (sim)
>= (maior ou igual) ex: 20 >=
30 resultado: falso 20>=20 resultado: verdadeiro
<= (menor ou igual) ex: 20 <= 30 resultado: verdadeiro
<> (diferente) ex: 20 <> 30 resultado: verdadeiro 30.6 <> 10.78 (verdadeiro)
= (igual) ex: 20 = 20 resultado: verdadeiro

Comparação de caracteres:
O operadores relacionais também podem ser usados para comparar dois valores do tipo
caractere. Por exemplo, é correto escrever a operação: ‘d’ > ’b’
Nas linguagens de programação em geral, e em Pascal em particular, essas comparações
devem ser interpretadas de forma especial.
A linguagem permite utilizar 256 caracteres diferentes. Os caracteres são colocados em
ordem, em uma tabela que começa na posição 0 e vai até 255. Essa tabela é hoje em dia
um padrão da indústria, e é conhecida como “tabela ASCII”. A cada posição da tabela
corresponde um caractere. O “valor” de cada caractere é na realidade o numero inteiro
que representa a posição desse caractere na tabela. O caractere em si deve ser visto
apenas como um símbolo, ou um desenho.
A tabela é longa, mas é importante saber alguns detalhes úteis:
- os caracteres das letras maiúsculas estão na tabela em ordem alfabética
- os caracteres das letras minúsculas também.
- os caracteres dos algarismos (‘0’ a ‘9’) seguem a ordem crescente dos números
- as letras acentuadas estão em posições sempre acima de 128
- algumas teclas do teclado correspondem a 2 caracteres seguidos. A tecla ENTER
corresponde ao caractere CR (carriage return, ou retorno de carro), da posição 13,
seguido do caractere LF (line feed, ou alimentação de linha), da posição 10.
O programador Pascal não precisa saber mais detalhes sobre as posições dos caracteres
na tabela para poder programar sem problemas, mas por curiosidade a tabela é mostrada
parcialmente abaixo:

TABELA ASCII (American Standard Code for Information Interchange)


0 .
1 .
2 .
. .
10 LF
. .
13 CR
. .
48 ‘0
49 ‘1’
50 ‘2’
. .
. .
56 ‘8’
57 ‘9’
. .
. .
. .
65 ‘A’
66 ‘B’
67 ‘C’
. .
. .
89 ‘Y’
90 ‘Z’
. .
. .
97 ‘a’
98 ‘b’
. .
. .
121 ‘y’
122 ‘z’
. .
. .
133 ‘à’
. .
. .
160 ‘á’

etc etc

Então, quando fazemos a comparação de dois caracteres usando operadores relacionais, o


que é comparado na realidade são as posições correspondentes na tabela. Como as letras
estão em ordem alfabética crescente na tabela, teremos que: ‘D’ < ‘F’ resulta
em verdadeiro (na realidade estará sendo feita a operação 68< 70)
Da mesma forma, ‘d’ < ‘f’ também resulta em verdadeiro (será feito 100 < 102 ), ou seja,
os operadores < , >, etc, podem ser interpretados como “antes” e “depois” na ordem
alfabética. Mas isso só vale para comparação entre letras maiúsculas ou entre letras
minúsculas. Se compararmos uma maiúscula com outra minúscula, essa interpretação pode
falhar. Por exemplo, ‘D’ < ‘a’ dará verdadeiro (pois 68 < 97), embora a letra ‘D’ esteja
alfabeticamente “depois” da letra ‘a’.
Para evitar isso é comum, em programas que comparam palavras alfabeticamente, primeiro
converter todas as letras para maiúsculas ou para minúsculas, e só depois fazer as
comparações. Mas isso será visto mais adiante.

Outro ponto importante a ressaltar, é que fica difícil comparar letras acentuadas com as
demais, para determinar a ordem alfabética relativa. Vemos acima o exemplo de ‘à’ e do
‘á’, em posições muito distantes das demais letras. Infelizmente o padrão da tabela ASCII
vale apenas para os primeiros 128 caracteres, e as letra acentuadas estão em uma área da
tabela que não é padronizada. Ainda existem em operação muitos ambientes de
programação com valores diferentes entre si para as letras acentuadas. Por esse motivo, o
uso de letras acentuadas em muitas aplicações é desencorajado. Neste curso evitaremos
trabalhar com letras acentuadas.

Também é importante observar que os caracteres que representam os algarismos estão


também em posições contíguas na tabela, e seguem a ordem crescente dos números que
representam. Assim vemos que, por exemplo, ‘7’ > ‘3’ dará verdadeiro (porque 55 > 51).

d) Operadores lógicos operando sobre valores lógicos, com resultado lógico:

Operadores binários:
OU-INCLUSIVO (OU)
E
OU-EXCLUSIVO (XOU)
Operador unário:
NÃO
Significados:
OU : para a OU b ser Verdadeiro, basta um dos operandos, ou ambos, ter o valor
Verdadeiro.
E: para a E b valer Verdadeiro, ambos os operandos devem valer Verdadeiro
XOU: para a XOU b valer Verdadeiro, apenas um dos operandos pode valer
Verdadeiro, o outro deve valer Falso.
NÃO: negação do operando.

A tabela verdade abaixo resume essas operações: (V – verdadeiro, F – falso)

x y x ou y x E y x XOU y não x
F F F F F V
F V V F V V
V F V F V F
V V V V F F

Equivalente em inglês: os operadores lógicos têm nomes consagrados na língua inglesa,


que são usados na grande maioria das linguagens de programação. Usaremos também a
notação em inglês, por ser universal.

OU-INCLUSIVO (OU) INCLUSIVE-OR (OR)

E AND
OU-EXCLUSIVO EXCLUSIVE-OR (XOR)
(XOU)
NÃO NOT

VARIÁVEIS, CONSTANTES, MEMÓRIA e IDENTIFICADORES

Uma variável consiste de um identificador ao qual é associada uma área de memória onde
podem ser armazenados valores de um determinado tipo. Uma variávelsimples corresponde
a apenas um valor. Uma variável composta representa um agrupamento de valores na
memória da máquina.

Por exemplo, o identificador nota pode representar uma área da memória onde é
armazenado um valor real (a nota de um aluno). Então, se a nota do aluno for, digamos, 8.5,
podemos associar o identificador nota com o valor 8.5. Variáveis compostas serão vistas
mais adiante.

Uma constante é um identificador que corresponde a uma área da memória onde fica
armazenado um valor que não deve ser alterado pelo algoritmo. Por exemplo, o
identificador PI pode ser associado a uma área da memória onde será armazenado o valor
3.1416 no inicio de um algoritmo, mas que não deverá ser mais modificado.

Um identificador pode ser formado por letras, algarismos e o caractere sublinhado (‘_’) em
qualquer quantidade, desde que não iniciado por um algarismo. Em geral procura-se formar
uma palavra que lembre mnemonicamente o significado do valor correspondente no
problema que está sendo resolvido pelo algoritmo.
Por exemplo, o identificador salário pode ser associado a um valor real que representa o
salário de alguém, e o identificador achou pode ser associado a um valor lógico que indica
se a busca por um determinado valor numérico em uma lista foi bem sucedida ou não.

EXPRESSÕES:
Uma expressão é uma fórmula contendo valores, operandos, identificadores de variáveis ou
constantes, e outros símbolos permitidos, e que pode ser calculada de modo a ser reduzida a
um valor final. No cálculo de uma expressão os identificadores são substituídos pelos
valores correspondentes que estão na memória no momento em que a expressão é
calculada.
As operações que fazem parte de uma expressão são executadas da esquerda para a direita,
respeitando as regras de precedência.
Regras de Precedência:
maior precedência: - unário, NÃO
* / div mod E
+ - (binário) OU OU-EXCLUSIVO
menor precedência > < >= <= <> =

Além disso, se houver parênteses na expressão, terão prioridade de execução as operações


que estiverem nos níveis mais internos de parênteses.

Exemplo de expressão: PI + 3 * x – 2.5


onde PI tem o valor 3.1416 e x tem o valor 10, no momento em que a expressão será
calculada na Unidade Aritmética Lógica da máquina.
Para reduzir essa expressão a um valor, os identificadores são inicialmente substituídos
pelos valores correspondentes na memória. A seguir, as operações são executadas da
esquerda para a direita. Como o operador * tem precedência sobre o operador +, a
operação 3 * x será feita primeiro. Como + e – têm a mesma precedência, a operação de
soma será feita a seguir, e finalmente a subtração. Os valores intermediários resultantes de
cada operação são usados como operandos das operações seguintes.
O gráfico abaixo indica os passos que levam à redução da expressão ao seu valor final:

PI + 3 * x – 3.1
3.1416 + 3 * 10 – 3.1 (subst. dos valores dos identificadores)
3.1416 + 30 – 3.1 (* tem precedência sobre +)
33.1416 – 3.1 ( + e – tem a mesma precedência, então a operação mais à esquerda
é feita primeiro)
30.0416 (valor final da expressão)

Uso de parênteses permite violar as regras de precedência:


PI + 3 *( x – 3.1)
3.1416 + 3 * (10 – 3.1 )
3.1416 + 3 * 6.9
3.1416 + 20.70
23.8416 (valor final da expressão)

OBS: usar parênteses em excesso não é erro: (3+4) ou ((3+4)) tem o mesmo valor que
3+4

Neste próximo exemplo, a expressão se reduz a um valor lógico. Note que não são
necessários parênteses porque a precedência dos operadores relacionais é menor que a dos
operadores aritméticos:
PI + 3*x > x – 2
3.1416 + 3 * 10 > 10 –2
3.1416 + 30 > 10-2
33.1416 > 10 – 2
33.1416 > 8 ( - tem precedência sobre >)
verdadeiro (valor final da expressão)

Expressões bem e mal formadas:


Uma expressão precisa estar bem formada sintaticamente para poder ser calculada. Por
exemplo, a expressão abaixo não pode ser calculada, pois exige operações impossíveis:

10 > 20 OU 100 = 40 (expressão mal-formada )

Como o operador OU tem precedência sobre o operador >, a operação 20 OU 100 deveria
ser feita primeiro. Mas não é possível fazer essa operação, porque o operador OU só se
aplica a operandos lógicos. Existe nessa fórmula um erro de sintaxe (forma gramatical
errada). Para corrigir o erro, introduzimos parênteses para forçar que a operação relacional
seja feita antes:

(10 > 20) OU (100 = 40)


falso OU falso
falso

Nota: essa observação é válida para a linguagem Pascal. Na linguagem C, por exemplo, os
operadores lógicos têm menor precedência que os operadores relacionais. Por isso, em C, a
expressão acima sem parênteses estaria correta.

Expressões Triviais:
Uma única constante literal, ou um único identificador de variável, constitui uma expressão
trivial, mas é uma expressão legitima:
Por exemplo:
3 é uma expressão trivial, seu valor é 3.
Se x tem o valor 3, a expressão: x é trivial, com valor 3.

Expressões envolvendo funções:


Assim como na Matemática, uma expressão pode conter também o uso de funções com
argumentos que são também expressões. Funções serão vistas mais adiante, mas para
ilustrar a expressão abaixo usa a função sqrt( ) (de square root – raiz quadrada):
____
x + 3 * sqrt(y-2) equivalente em Matemática a x + 3 √ y-2

CAPíTULO 2
INSTRUÇÕES OU COMANDOS

As instruções ou comandos são fórmulas que permitem realizar alterações na memória,


agir sobre os dispositivos de entrada ou saída, ou controlar o fluxo do programa.

A seguir estão relacionados os comandos mais importantes que usaremos na construção de


algoritmos de computador, e que são equivalentes aos comandos da Linguagem Pascal:

COMANDO DE ATRIBUIÇÃO: :=

Definição: < identificador de variavel > := <expressão>


Significado: a expressão do lado direito do símbolo := é calculada e reduzida a um valor.
Esse valor será, em seguida, transferido para a variável da memória designada pelo
identificador do lado esquerdo.

Exemplo: supondo que x vale 3 no momento em que o comando abaixo for realizado,
então:
y := 2 * x + 10
faz a expressão ser calculada e reduzida ao valor 16, e em seguida, esse valor é transferido
para a variável y que passa então a ter também o valor 16. O valor anterior que y tinha é
perdido.

Uma atribuição usa muitas vezes uma expressão trivial do lado direito, como em:
y := 10 (a expressão da direita vale 10, e esse valor é transferido para a variável y)

OBS: jamais confunda o operador de atribuição := com a idéia de igualdade. O


significado não é que a variável da esquerda é igual ao valor da expressão da direita, mas
que a variável da esquerda ficará igual ao valor calculado da expressão.

COMANDO DE LEITURA DE DADOS (ENTRADA) ler (<variável>)

Esta é a outra forma pela qual se pode alterar o valor de uma variável na memória.

Significado: um valor existente no dispositivo de entrada de dados (normalmente a


memória do teclado da máquina) será lido pela máquina e armazenado na variável da
memória cujo nome aparece no comando.
Por exemplo:
Seja uma variável x definida como do tipo real. Supondo que o comando:
ler (x) seja executado.
Então, se o usuário digitar 56.132 no teclado (terminando por teclar a tecla ENTER), o
comando acima fará com que a variável x na memória receba o valor 56.132, sendo que o
valor anterior dessa variável será perdido.

Como funciona o comando ler( ):


O entendimento correto de como funciona o comando de leitura de dados é essencial para
que o programador iniciante não se depare com erros aparentemente inexplicáveis.
O comando mais usual é para ler dados que serão digitados no teclado da máquina. É
possível também ler dados de outras mídias, como de um disco ou de uma fita magnética,
mas esses casos serão vistos mais tarde.

Primeiramente é importante saber que os dados digitados pelo teclado são lidos pela
máquina como uma linha de texto. Após digitar os dados, é necessário apertar a tecla
ENTER para sinalizar que terminamos a linha. Nesse momento, os caracteres digitados
serão colocados em uma memória intermediaria, conhecida popularmente como o buffer do
teclado. O caractere correspondente à tecla ENTER também irá para o buffer.

Pelo fato de ser uma linha de texto, os dados digitados formam uma seqüência de valores
de caracteres terminando com o valor do caractere ENTER. Se, por exemplo, for digitado o
número –3.25 seguido de ENTER, então o buffer conterá os 5 caracteres do número (o
caractere ‘-‘, seguido do caractere ‘3’, seguido do caractere ‘.’, etc.), e após eles o caractere
da tecla ENTER. É muito importante se ter essa noção de que o que digitamos não são
“números”, mas sim uma seqüência de caracteres.

Números reais podem ser digitados em formato convencional (como 567.8), ou em notação
cientifica (ex: 5.678E2 ou 0.567e+02 ou outra forma equivalente). Caracteres são digitados
sem as aspas simples. (ex. A)

Quando o comando ler(<variável>) é executado, a máquina tenta construir um valor do


tipo declarado da variável com os caracteres que já estão no bufferdo teclado. Somente se
não houver nada no buffer é que a máquina pára e aguarda que o buffer seja preenchido
com uma nova linha de caracteres. Se os caracteres que estiverem no buffer não formarem
um valor do tipo esperado, haverá um erro de execução e o programa terminará
imediatamente com uma mensagem de erro. Diz-se que o programa abortou a execução.

Suponha que o comando ler(x) foi executado, e x é do tipo inteiro. Se digitarmos mais de
um número na mesma linha, então o primeiro número será copiado para o valor de x, e os
demais caracteres permanecerão no buffer esperando serem lidos pelos próximos comandos
de leitura.

Por exemplo, suponha a seqüência de comandos seguinte, onde x e z são variáveis inteiras,
e y é uma variável real:

ler(x)
ler(y)
ler(z)
ler(x)

Inicialmente, como o buffer está vazio, a máquina pára e espera que uma linha de
caracteres seja digitada, finalizando com ENTER. Suponha que o usuário digite:

34 -567.45 98 <ENTER>
(A quantidade de espaços entre os números é irrelevante, devendo ser pelo menos 1. Não é
permitido separar os números por virgulas ou outros caracteres A notação <ENTER>
acima significa pressionar a tecla ENTER.)

Essa linha de texto irá para o buffer do teclado.


A seguir, o primeiro comando ler(x) lerá os caracteres ‘3’ e ‘4’, parando ao encontrar o
primeiro espaço em branco. A rotina construirá o número inteiro 34, e este número será
armazenado em x.

Terminado o comando ler(x), o próximo comando será executado, que é ler(y).


A máquina verifica que ainda existem caracteres não lidos no buffer do teclado, e começa a
ler após o último caractere lido (após o ‘4’). Os espaços adicionais são pulados, até
encontrar o hífen (‘-‘). Um hífen pode ser parte de um número nessa posição (sinal de
menos), por isso é aceito, e a máquina vai lendo os caracteres ‘5’,’6’, ‘7’ e encontra o
ponto. Como o tipo de y é real, é permitido haver um ponto decimal (mais de um ponto
seria erro), e por isso a máquina continua lendo os caracteres ‘4’ e ‘5’ até encontrar um
espaço. Nesse momento a máquina conclui que terminaram os caracteres de y, e inicia uma
rotina que vai construir um número real com esses caracteres. O numero é então
armazenado na variável y na forma de mantissa e expoente (equivalente a –5.6745 x 102.
(Na realidade é um pouco diferente porque a máquina trabalha na base 2, e não na base 10,
mas o principio é o mesmo).

Terminado o comando ler(y), o próximo comando é executado, que é ler(z).


A máquina verifica que ainda existem caracteres não lidos no buffer, pula os espaços não
lidos, e encontra o caractere ‘9’. Como z é inteiro, ela aceita o caractere, lê o ‘8’, e encontra
um espaço. Constrói então o número inteiro 98, que é armazenado na variável z da
memória.

O próximo comando, ler(x), é executado. A máquina encontra alguns espaços seguidos do


caractere ENTER no buffer, mas nenhum outro caractere. Conclui que o buffer está vazio, e
nesse momento pára aguardando que o usuário digite outra linha.
(OBS: não é possível digitarmos varias linhas de uma vez. Ao final de cada linha, a
máquina re-assume o controle e trabalha com os dados da linha digitada. Só depois que o
buffer voltar a ficar vazio é que a máquina pára e aceita outra digitação de linha.)

O usuário então digita, digamos:


456.0 seguido de ENTER.

A máquina vai procurar construir um inteiro com esses caracteres. Vai lendo o ‘4’, depois o
‘5’ , depois o ‘6’, até deparar com o ponto. Nesse ponto o programa abortará a execução,
pois um inteiro não pode conter ponto decimal.

Cuidados a tomar com a leitura de variáveis tipo caractere:


É preciso muito cuidado para se ler variáveis do tipo caractere. O motivo é que qualquer
espaço em branco, ou o próprio caractere ENTER, que estiverem no buffer do teclado no
momento da execução do comando ler( ), pode causar com que o caractere errado seja
transferido para a variável.

Um erro clássico é tentar ler um número seguido de um caractere.


Suponha que queremos ler o valor de n (inteiro) e depois os valores
de letra1 e letra2 (ambos caracteres) com os comandos:
ler(n)
ler (letra1)
ler (letra2)

Então digitamos a linha:


25 A B<ENTER>

esperando que n receba o valor 25, letra1 receba o valor ‘A’, e letra2 receba o valor ‘B’. O
resultado porém será inesperado. Na realidade, n receberá o valor 25, letra1 receberá o
caractere que é o espaço que segue o ‘5’, e letra2 receberá o caractere ‘A’. Os demais
caracteres depois do A permanecerão no buffer e poderão ser lidos por outros comandos de
leitura que seguirem.

Como então é possível ler um caractere depois de um número? Já vimos que a forma:
25AB
não é possível, porque deve sempre existir pelo menos um “valor branco” (espaço,
tabulação ou o caractere ENTER) após cada numero.

Mesmo que quiséssemos fazer a entrada em 2 linhas, como abaixo:


25<ENTER>
AB<ENTER>
isso não adiantaria, porque o ENTER final da primeira linha corresponde a 2 caracteres
(CR seguido de LF), o que fará com que letra1 receba o caractere CR (valor 13)
e letra2 receba o caractere LF (valor 10). Aliás a máquina por isso mesmo nem chegaria a
pedir a segunda linha.

COMANDO PARA LER UMA NOVA LINHA


Para resolver esse problema, existe um comando que “esvazia o buffer do teclado”. Esse
comando é novaLinha. O efeito desse comando é ignorar todos os caracteres não lidos que
ainda existam no buffer do teclado, de modo a forçar que uma nova linha seja lida pela
máquina.

Agora podemos fazer:


ler(n)
novaLinha
ler(letra1)
ler(letra2)

e digitar:
25<ENTER>
AB<ENTER>
O comando ler(n) lerá o número 25 para a variável n, os 2 caracteres do <ENTER> serão
ignorados por conta do comando novaLinha, e a máquina lerá os caracteres da segunda
linha. Agora a letra A será associada à variável letra1, e a letra B (valor 66) será associada
à variável letra2, corretamente. Observe que os caracteres A e B são digitados em
seqüência, sem nenhum espaço entre eles. Caso existisse um espaço entre eles, a
variável letra2 receberia o valor do espaço.

Na linguagem Pascal, os comandos correspondentes são:


ler(<variável>) é read (<variável>)
novaLinha é readln

COMANDO DE ESCREVER (SAÍDA) escrever (<expressão>)

O comando escrever( ) recebe uma expressão como argumento. O efeito desse comando é
normalmente de escrever o resultado da expressão no dispositivo padrão de saída, que em
geral é o monitor de vídeo.

É importante notar que, ao contrário do comando de leitura, o argumento é uma expressão,


e não uma variável.
Mas, lembrando sempre que uma variável é também uma expressão trivial, esse comando
também pode receber uma variável como argumento.

Por exemplo, supondo que no momento da sua execução, as variáveis x e y valem,


respectivamente, 10 e 20, então o comando:
escrever (x*3 + x*y)
faz com que a expressão seja calculada na Unidade Aritmética Lógica, sendo reduzida ao
valor 230, e a seguir esse numero será escrito no monitor de saída.

OBS: Os valores serão escritos na tela na posição onde estiver o cursor. É preciso atenção
para levar em conta onde o cursor estará quando o comandoescrever() for realizado.

Expressões com uma seqüência de caracteres:

Uma seqüência de caracteres, delimitada por um par de aspas simples, é uma expressão
válida em Pascal e pode ser usada nos comandos de escrita. Elas serão escritas literalmente
no campo correspondente. Como as demais expressões, um formato pode ser adicionado
para especificar o tamanho ocupado na linha de saída. Caso um formato não seja
especificado, o tamanho usado será o menor possível.

Por exemplo, supondo que uma variável inteira n tenha o valor 30, o comando abaixo
imprime duas expressões, a literal 'n+5 = ' seguida do valor calculado de n+5.
escrever ('n+5 = ', n+5)
fará com que seja escrita na tela a frase: n+5 = 35

Comandos de escrita na linguagem Pascal:


Os comandos abaixo escrevem na unidade padrão de saída, que é normalmente a tela do
monitor de vídeo. Comandos semelhantes para escrever no disco serão vistos mais adiante.

write (<expressão>)
equivale ao que foi descrito acima para escrever(<expressão>)

write (<expressão-1>, <expressão-2>,...., <expressão-n>) onde n >= 1


equivale à seqüência de n comandos:
write (<expressão-1>);
write (<expressão-2>);
......
write (<expressão-n>)

writeln
O cursor avança para o inicio da próxima linha na tela de saída. Equivale a escrever o
caractere <ENTER> ou novalinha.

writeln (<lista de expressões>)


Equivale à seqüência de comandos:
write(<lista de expressões>);
writeln
Nota: o ponto-e-vírgula é necessário para separar 2 comandos na linguagem Pascal.

FORMATOS DE SAÍDA

O processo de escrita na saída é inverso ao processo de leitura. Os valores que estão na


Unidade Aritmética Lógica estão em um formato interno da maquina, mas podem ser
escritos de vários formatos diferentes. Por exemplo, o numero 2.567e2 pode ser impresso
como 256.7, como 256.7000, etc. A linguagem permite escolher dois aspectos do formato
de impressão:
a) quantos caracteres no total terá o formato impresso do valor, incluindo o sinal (+ ou -) e
o ponto decimal.
b) qual a precisão (numero de casa decimais) com que o valor será impresso (só para
valores reais).

Os números reais serão impressos na notação cientifica se o formato não indicar o número
de casas decimais.

Para indicar o formato de impressão, a expressão deve ser seguida do tamanho em


caracteres com que o seu valor será escrito, seguido (no caso de reais) do número de casas
decimais, ambos precedidos por um dois-pontos (: ) , como em escrever(x+y:10:3)

Note que o comando escrever( ) não acrescenta nenhum espaço após escrever cada valor de
expressão. Isso deve ser providenciado pelo programador. Por exemplo, se imprimir os
valores de x e y (inteiros) e z (real), valendo 153, 10245 e -32.767, respectivamente, o
comando:
escrever (x,y,z) escreverá na tela algo como:
15310245-3.27670000000000000E+001 o que pode ser muito desagradável.

Para ter uma saída mais legível, devemos levar em conta a necessidade dos espaços entre os
valores, e colocar um formato adequado para cada valor, com casas decimais para os
números reais. O comando:
escrever(x:5, y:6, z:9:2) escreverá na tela o seguinte (note o arredondamento de z):
153 10245 -32.77

Os exemplos abaixo ilustram os vários casos, onde as variáveis x (inteiro), y (real) ,


e letra (caractere) são respectivamente a -10, 25.68 e A. Note que os números serão
arredondados automaticamente para se ajustarem ao número de casas decimais definido no
formato. Em particular, um real com zero casas decimais será impresso como o inteiro mais
próximo. Números reais serão impressos sempre em notação cientifica caso não seja
especificado no formato a quantidade de casas decimais desejada. Números reais sem
tamanho definido, serão impressos em um tamanho padrão definido pelo compilador usado.
Números inteiros sem tamanho definido ocupam o menor tamanho necessário para escrevê-
los.

Nos exemplos abaixo, as colunas de texto foram numeradas para melhor visualização:

colunas da tela--- 1 2 3 4 5 6 7 8 9 10 11 12 13
>
escrever(x:4) - 1 0
escrever(y:9:1) 2 5 . 7
escrever(y/2:12) 1 . 2 8 4 0 0 E + 0 1
escrever(y/2:8:3) 1 2 . 8 4 0
escrever(y/2+1:10:0) 1 4
escrever(letra) A
escrever(letra:5) A
Nota: O formato de impressão em notação cientifica pode variar ligeiramente entre várias implementações.

OBSERVAÇÕES ADICIONAIS:
Valores lógicos são impressos da seguinte forma (em Pascal):
verdadeiro --- > TRUE
falso --- > FALSE
O número de colunas usadas pode também ser controlado com o formato.

CAPíTULO 3

Estrutura de um programa em Pascal

Um texto contendo um programa na linguagem Pascal deve obedecer a regras


de sintaxe (forma) bem específicas, para que o compilador possa reconhecer
as suas diversas partes, e convertê-lo (traduzir) para uma seqüência
equivalente de comandos em linguagem de máquina.

Nas definições abaixo, as palavras e símbolos que não estão entre os sinais de
< e > são considerados como elementos da linguagem Pascal e devem ser
escritos literalmente. As frases entre os sinais < e > são explicações em
português do que deve entrar no lugar delas. Dizemos que essas frases estão
escritas na meta-linguagem (a linguagem que usamos para definir uma outra
linguagem).

program <identificador>;

<declarações de constantes>

<declarações de variáveis>

<declarações de funções e procedimentos>

<bloco>

Funções e procedimentos serão vistos em um capitulo mais à frente.

Note a primeira palavra deve ser program e que o último caractere deve ser
um ponto-final, após o <bloco>.

Na estrutura acima, definimos:


<declarações de constantes> = const <lista de definições de constantes>
Exemplo:

const pi=3.1415; n = 30;


Note que o sinal de igualdade é usado, e que tipos não são declarados. O
compilador deduz os tipos pelo formato dos valores usados nas declarações. O
ponto-e-vírgula deve terminar cada declaração de constante.

<declarações de variáveis> = var <lista de definições de variáveis>

Exemplo:
var
x,y:integer;

w,z:real;

letra1:char;

terminou: boolean;

Observações:

Tanto faz escrever as declarações em uma ou em várias linhas.

O tipo de cada variável deve ser indicado após o sinal de dois-pontos.

Várias variáveis de um mesmo tipo podem ser declaradas juntas, separadas


por virgulas.

O tipo boolean é o equivalente em Pascal a um valor lógico.

O tipo char indica que a variável contém o valor de um caractere.

O bloco de comandos:

O programa em si está contido no <bloco> que é definido como:

<bloco> = begin <lista de comandos> end

<lista de comandos> = <comando-1>; <comando-2>; .....; <comando-


n> onde n>=0

Note que, pela definição acima, um programa pode ter zero comandos, e ainda
ser um programa “bem formado”, embora não sirva para nada.

Exemplo de um programa:

program exemplo;

const

n1= 5;

n2= 3;

var
x,y:integer;

comp: boolean;

begin

writeln('Digite um multiplo de ',n1, ' e outro multiplo de ', n2, ': ');

read(x,y);

comp:= x > y;

writeln(x, ' > ', y, ' = ', comp);

readln; readln;

end.

No programa acima, o bloco de comandos que é executado começa logo após


o begin.

O bloco contém 6 comandos. Os dois últimos estão escritos na mesma linha,


mas apenas por conveniência. Cada comando deve ser separado do seguinte
por um ponto-e-vírgula.

Após o ultimo comando de um bloco o ponto-e-vírgula é opcional.

No exemplo acima, n1 e n2 poderiam também ter sido declaradas como


variáveis inteiras, em vez de constantes. Nesse caso, seus valores deveriam
entrar como comandos de atribuição, dentro do bloco, como abaixo. O efeito
seria exatamente o mesmo.

O exemplo mostra o uso de comentário delimitado por (* e *) . Comentários


podem também ser delimitados por { e } .

program exemplo2;

(******************************************************************

Este exemplo evita usar constantes.

Mas mostra o uso de comentários.

*******************************************************************)

var

n1,n2,x,y:integer;

comp: boolean;
begin

n1:=5;

n2:=3;

writeln('Digite um multiplo de ',n1, ' e outro multiplo de ', n2, ': ');

read(x,y);

comp:= x > y;

writeln(x, ' > ', y, ' = ', comp);

readln; readln;

end.

Comandos de controle do fluxo de instruções:

COMANDOS DE DESVIO CONDICIONAL

a) se <expressão lógica> então <comando-verdade>

b) se <expressão lógica> então <comando-verdade> senão


<comando-falso>

No primeiro caso, o valor da expressão lógica é calculado, e caso seja


Verdade (True) o <comando-verdade> é executado, caso seja Falso nada é
feito.

No segundo caso, caso o valor da expressão lógica for Falso, o <comando-


verdade> não é executado, mas o <comando-falso> é executado.

Exemplo:

Seja o comando:
se (x mod 2 = 0) e (x < y) então escrever (x div 2) senão escrever (x+y)

Supondo que os valores de x e y sejam respectivamente 10 e 15 no momento


da execução do comando acima, então teremos:

Cálculo da expressão lógica:

(x mod 2= 0) e (x <y)

(10 mod 2 = 0) e (10 < 15)

(0 = 0) e Verdade

Verdade e Verdade

Verdade

Como o valor calculado foi Verdade, o comando após a palavra-


chave então será executado, e será impresso o valor de x div 2, ou seja, 10
div 2 que é 5.

Mas se os valores de x e y forem 11 e 15, o valor da expressão será outro:

(x mod 2= 0) e (x <y)

(11 mod 2 = 0) e (11 < 15)

(1 = 0) e Verdade

Falso e Verdade

Falso

E nesse caso o comando após a palavra-chave senão será executado, sendo


escrito na tela o valor de x+y, ou seja 11+15 que é 26.

Na linguagem Pascal, esses comandos são escritos assim:


a) if <expressão lógica> then <comando-verdade>

b) if <expressão lógica> then <comando-verdade> else <comando-


falso>

c) Comando case:

O comando case é um comando que permite selecionar um ou mais comandos


para serem executados conforme o valor de uma expressão escalar (ou seja, o
valor deve ser simples, não pode ser, por exemplo, uma string). Somente os
tipos inteiro, caractere, lógico, e tipos enumerados (não vistos ainda) podem
ser usados.

Neste comando o valor da expressão é comparado com os valores dos casos


previstos de execução. No máximo um caso pode ser verdadeiro.

Os valores dos casos podem ser:

- um valor de uma constante escalar.

- uma lista de valores escalares, separados por vírgulas.

- uma faixa de valores da forma <valor-1> .. <valor-2>, significando o


conjunto de valores contidos no intervalo de <valor-1> a <valor-2>.

- uma combinação de faixas de valores e listas de valores, separados por


virgulas.

Alem disso os valores não podem ser repetidos, ou seja, um valor só pode
aparecer em apenas um dos casos.

Sintaxe:
case <expressão> of

Lista Constantes Escalares-1: Comando-1;

Lista Constantes Escalares-2: Comando -2;

...

Lista Constantes Escalares-k: Comando-k;

else

Comando;

...

Comando;

end

OBS: A parte do else pode não existir. Nesse caso, nada ocorrerá se nenhum dos casos for verificado.

Exemplo:

No exemplo abaixo, a expressão é uma variável c , do tipo caractere. O primeiro caso é uma lista
com duas faixas de valores, e inclui todas as letras maiúsculas entre A e Z, e todas as letras
minúsculas entre a e z. O segundo caso inclui os dígitos de 0 a 9. O terceiro caso inclui uma lista
com 4 valores , que são os caracteres usados para as operações aritméticas. Caso a expressão c não
tenha nenhum desses valores, os dois comandos após o else serão executados.

program exemplo;
var c: char;
begin
write('Entre com um caractere: ');
readln(c);
case c of
'A'..'Z','a'..'z': writeln('Caractere lido e'' letra.');
'0'..'9': begin
writeln('Caractere lido e'' um digito ');
writeln('entre 0 e 9');
end;
'+','-','*','/': writeln('Caractere lido e'' um operador matematico.');
else writeln('O caractere lido nao e'' letra, nem digito,');
writeln('nem operador matematico.');
end;
end.
Para melhor compreender o exemplo acima, segue abaixo o programa
equivalente usando comandos if..then...else equivalentes:

program exemplo_if;

var c: char;

begin

write('Entre com um caractere: ');

readln(c);

if (c>='A') and (c <= 'Z') or (c>= 'a') and (c <= 'z')

then writeln('Caractere lido e'' letra.')

else if (c>='0') and (c<= '9')

then begin

writeln('Caractere lido e'' um digito ');

writeln('entre 0 e 9');

end

else if (c='+') or (c='-') or (c='*') or (c= '/')

then writeln('Caractere lido e'' um operador matematico.')

else begin

writeln('O caractere lido nao e'' letra, nem digito,');

writeln('nem operador matematico.');

end;

end.

Note bem que:

Todo comando case pode ser transformado em um comando if...then ...else


equivalente, mas o reverso não é verdade.

O comando case deve ser usado onde um comando if equivalente só teria


expressões lógicas do tipo:
<expressão> = <constante-escalar>

e sempre usando a mesma expressão.

Caso a expressão não corresponda a nenhum dos casos, então o efeito do


comando case é nulo.

EXERCÍCIOS DE FIXAÇÃO:

1) Escrever um programa em Pascal que solicita do usuário os coeficientes a,


b e c da equação de segundo grau:

ax2 + bx + c = 0

e imprime uma das seguintes respostas na tela:

a) Existem duas raízes reais com valores <valor 1> e <valor 2>

b) Existe apenas uma raiz real, com valor <valor único>

c) Não existem valores reais.

O programa deve calcular inicialmente o determinante b2 – 4*a*c. Caso


seja positivo, calcula os valores (–b + sqrt(b*b-4*a*c))/(2*a) e (-b-
sqrt(b*b-4*a*c))/(2*a) e imprime a primeira resposta. Caso seja nulo,
calcula o valor –b /(2*a) e imprime a segunda resposta. E caso seja
negativo, imprime a terceira resposta.

2) Escrever um programa em Pascal que calcula o Imposto de Renda anual


de um contribuinte pessoa física. O usuário deve digitar os seguintes
valores reais:

a) o rendimento bruto tributável recebido no ano;

b) o total de deduções a que tem direito;


c) o valor de Imposto de Renda na fonte, já pago durante o ano.

Como resposta, o programa deve escrever uma das frases abaixo:

a) Imposto a pagar: <valor em reais e centavos>

b) Imposto a receber por devolução: <valor em reais e centavos>

O valor do cálculo do Imposto usa a tabela progressiva divulgada pelo


Governo, que neste ano é a seguinte:

Base de cálculo anual em Alíquota (%) Parcela a deduzir do imposto em


R$ R$

Até 12.696,00 - -

De 12.696,01 até 15,0 1.904,40


25.380,00

Acima de 25.380,00 27,5 5.076,90

A Base de cálculo acima é obtida subtraindo o total das deduções do rendimento bruto tributável
recebido no ano. O imposto é calculado em partes, um valor para cada faixa de rendimentos.

CAPíTULO 4

Repetição em programas Pascal

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 blocobegin ....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 umaordem 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.
CAPíTULO 5

Variáveis Compostas Homogêneas - Vetores e Matrizes

Um vetor (array em inglês) é um agregado de variáveis do mesmo tipo


(homogêneas). O exemplo abaixo mostra a representação gráfica de um vetor
de 6 inteiros chamado v:

1 2 3 4 5 6

Cada “casa” , ou “elemento”, do vetor é uma variável independente. No exemplo acima,


cada elemento pode conter um valor inteiro, e as posições foram ordenadas de 1 até 6. Os
elementos de um vetor são identificados pelo nome do vetor associado ao número de ordem
da sua posição relativa no vetor: v[1], v[2], v[3], v[4], v[5] e v[6].

Assim, no caso acima, a variável v[2] tem o valor 67.


Podemos alterar esse valor exatamente como fazemos com qualquer variável:
v[2] := 100;
readln(v[2]);

etc.

Para declarar esse vetor em um programa Pascal, é usada a forma abaixo:


var
v: array[1..6] of integer;

A forma geral é:
var <identificador do vetor>: array [<intervalo das posições>] of <tipo dos valores do vetor>

Cada variável do conjunto é representada por:


<identificador do vetor>[<expressão cujo valor é a posição da variável> ]
onde a expressão deve ser do tipo declarado.

Por exemplo, a variável na posição 3 do vetor pode ser representada por:


v[3] v[10-7] v[5*5-2*11] v[x-4], supondo que x tenha o valor 7, etc.
Uso do comando for com vetores

A manipulação de vetores é grandemente facilitada pelo uso dos comandos de repetição,


especialmente o for. Por exemplo, para zerar (colocar o valor 0) todas as posições do
vetor v definido acima, seria necessário escrever 6 comandos:
v[1]:= 0;
v[2]:= 0;
v[3]:= 0;
v[4]:= 0;
v[5]:= 0;
v[6]:= 0;

A mesma operação pode ser feita com apenas um comando de repetição for, usando uma
variável de controle para representar as posições do vetor:
for i:= 1 to 6 do v[i]:=0;
É fácil imaginar o que isso representa de simplificação para a manipulação de vetores
grandes.

Da mesma forma, para ler do teclado todos os valores do vetor v, seriam também
necessários 6 comandos:
read (v[1]);
read (v[2]);
read (v[3]);
read (v[4]);
read (v[5]);
read (v[6]);

Todos esses comandos podem ser substituídos por um único comando for:
for i:= 1 to 6 do read(v[i]);

O que se pode e o que não se pode fazer com vetores, na linguagem Pascal:
Nota: essas regras não se aplicam ao tipo string que é um caso especial de vetor de
caracteres com regras própria, e que será visto mais adiante.

Não é possível:
a) Não se pode ler todo um vetor diretamente com um comando read. Não se pode
escrever: read(v);
É necessário ler casa a casa, diretamente, ou com um laço de repetição como for no
exemplo acima.
b) Não se pode escrever todos os elementos de um vetor com um único comando write.
Não é permitido escrever: write(v). Também nesse caso cada elemento deve ser tratado
como uma variável independente, por exemplo:
for i:= 1 to 6 do write(v[i]:3);
c) Não é possível copiar os valores dos elementos de um vetor para outro com um único
comando de atribuição. Ou seja, dados dois vetores v e w, ambos do mesmo tamanho e
do mesmo tipo, não é permitido fazer: w:= v; . Também aqui é necessário trabalhar
elemento a elemento, e o comando for mais uma vez é indicado:
for i:= 1 to 6 do w[i]:= v[i];
c) Não existe comandos ou funções que dão o tamanho (número de elementos) de um vetor.
d) Não é permitido tentar acessar uma posição fora do intervalo de posições definido para o
vetor. A tentativa causará um erro em tempo de execução e o programa abortará. No caso
do vetor v acima, por exemplo, não é permitido escrever: v[8]:= 20, read(v[8]) ou
write (v[8]) porque a faixa de valores das posições vai de 1 a 6 apenas.

O que é permitido:
a) A faixa de valores das posições não precisa começar em 1. Qualquer intervalo de valores
pode ser usado na definição de um vetor. Por exemplo, podemos definir um vetor assim:
var v:array[15..20] of real;
Nesse caso o vetor v terá apenas os elementos: v[15], v[16], v[17], v[18], v[19] e v[20]
b) As posições não precisam ser necessariamente números inteiros. Podem ser qualquer
tipo ordinal, ou seja, que possa ser definido por uma seqüência ordenadade valores. Por
exemplo, os caracteres em Pascal formam uma seqüência ordenada na tabela de
caracteres, e podem portanto serem marcadores de posição em um vetor.
Podemos definir um vetor assim:
var letras: array['a'..'z'] of integer;
Nesse caso os elementos do vetor
são: letras['a'], letras['b'], ….., letras['z']
Um uso possível para esse vetor poderia ser que cada posição poderia guardar a
quantidade de vezes que a letra dessa posição aparece em uma determinada frase.

Exemplos de uso:

Ordenação de números:
Fazer um programa para ler n valores inteiros quaisquer, n <50, onde o valor de n deve ser
previamente fornecido pelo usuário.
Em seguida, o programa deve escrever na tela os valores em ordem numérica crescente.
A solução utiliza um algoritmo de ordenação .
O algoritmo abaixo é conhecido como ordenação por seleção. Os números são colocados
em um vetor definido com 50 posições. Inicialmente, procura-se a posição no vetor
(posMenor) onde está o menor número. Se essa posição for diferente da posição 1, então
troca-se os valores das casas 1 e posMenor. Isso garante que o menor elemento agora está
na posição 1. A seguir, repete-se o processo a partir da posição 2. Ou seja, procura-se a
posição do menor elemento da posição 2 em diante, que será posMenor. Se o valor de
posMenor for diferente de 2, troca-se os valores das casas 2 e posMenor. O processo é
repetido a partir da posição 3, depois 4, etc, até n-1. Nesse ponto o vetor estará com os
valores ordenados. Basta então escrever na tela os valores das posições 1 a n e teremos os
números em ordem crescente.
program ordenasel;
const nmax=50;
var
v: array[1..nmax] of integer;
i,j,n,posMenor,temp: integer;
begin
writeln('Digite um inteiro menor ou igual a ' ,nmax, ' : ');
readln(n);
writeln('Digite ',n,' inteiros separados por espacos');
for i:=1 to n do read(v[i]);
for i:=1 to n-1 do begin
posMenor:=i;
for j:=i+1 to n do
if v[j] < v[posMenor] then posMenor := j;
if i <> posMenor then begin
temp := v[i];
v[i] := v[posMenor];
v[posMenor] := temp;
end;
end;
writeln;
for i:=1 to n do write(v[i]:4);
end.

O tipo STRING

A linguagem Pascal original não possuía o tipo string. Hoje em dia, todas as versões
modernas de Pascal estendido possuem esse tipo (Turbo Pascal, Free Pascal, etc).

O tipo string é um caso especial de vetor de caracteres criado especialmente para tratar
com texto: palavras, frases, etc, onde a seqüência de caracteres deve ser tratada como uma
única entidade. A palavra string significa uma cadeia de caracteres. Cada posição de uma
string contém apenas um caractere.

A definição de uma variável é: var frase: string;

Não há necessidade de se definir um tamanho máximo, embora seja possível:


var nome: string[15];

Se não for definido um tamanho máximo, a string poderá expandir-se ou encolher-se


automaticamente para acomodar a quantidade de caracteres necessária.

As regras para vetores em geral não se aplicam às strings. Em particular, é permitido paara
strings:
a) ler uma string inteira com um único comando read ou readln: readln(frase);
b) escrever uma string inteira com um único comando write ou writeln: writeln(frase);
c) atribuir uma string diretamente: frase2:= frase;
d) escrever o valor literal de uma string entre aspas simples e usar em comandos de
atribuição ou de escrita: frase:= ‘rio de janeiro’; write(‘rio de janeiro’);
e) Caracteres individuais e strings podem ser usados de forma idêntica:
frase:= ‘a’; faz a string frase ser uma string com apenas o caractere ‘a’.
f) O uso da função length() que dá o tamanho (número de caracteres) de uma string.
g) O uso do operador de concatenação +, que permite unir duas strings produzindo uma
string que é a concatenação das duas: ‘ab’ + ‘cd’ produz a string ‘abcd’. O mesmo
pode ser obtido com a função concat(). Também aqui pode-se misturar strings com
caracteres de qualquer maneira: ‘a’ + ‘b’ dá a string ‘ab’, etc. O operador e a função
podem ser usados para concatenar varias strings e/ou caracteres:
Ex: frase := frase1 + frase2 + ‘!’;
frase := concat(frase1, frase2, ‘!’);
h) É possível comparar duas strings diretamente, usando os operadores relacionais
=, <>, >, <, >=, e <=, onde a comparação é feita pela ordem dos elementos na
tabela de caracteres, o que garante a ordem alfabética para strings contendo apenas
letras maiúsculas ou apenas minúsculas:
‘cde’ < ‘fgh’ dará true e ‘AB’ = ‘CD’ dará false
i) A posição zero de uma string contém sempre um número inteiro que é o tamanho da
string. Esse valor pode ser obtido usando a função ord(). Por exemplo, para imprimir o
tamanho da string frase, pode-se escrever: write ( ord(frase[0]); Na realidade a função
length() obtém o seu valor consultando a posição 0 da string.

Com esses conhecimentos, podemos adaptar muito facilmente o algoritmo de ordenação


por seleção, descrito acima para vetores de números, para ordenar um vetor de nomes em
ordem alfabética, assumindo que estão todos escritos em letras da mesma caixa (maiúsculas
ou minúsculas). Note que isso só foi possível por causa das regras especiais para strings, e
que é possível também se criar um vetor de strings:

program ordenanomes;
(**********************************************************************
algoritmo de selacao para ordenar nomes em ordem alfabética.
**********************************************************************)
const nmax=50;
var
v: array[1..nmax] of string;
i,j,n,posMenor: integer;
temp:string;
begin
writeln('Digite um inteiro menor ou igual a ' ,nmax, ' : ');
readln(n);
writeln('Digite ',n,' strings, uma em cada linha);
for i:=1 to n do readln(v[i]);
for i:=1 to n-1 do begin
posMenor:=i;
for j:=i+1 to n do
if v[j] < v[posMenor] then posMenor := j;
if i <> posMenor then begin
temp := v[i];
v[i] := v[posMenor];
v[posMenor] := temp;
end;
end;
writeln;
for i:=1 to n do writeln(v[i]);
end.
MATRIZES – vetores com mais de 1 dimensão:

Os elementos de um vetor guardam uma relação de posicionamento entre si apenas em uma


dimensão. Essas variáveis estão dispostas como que em uma linha, e cada elemento é
identificado pela sua posição relativa na linha:

2 30 17 35 7
0
1 2 3 4 5 (posições na linha)

Quando há mais de uma dimensão, damos o nome de matriz a esse arranjo de variáveis. O
caso mais comum é a matriz de 2 dimensões. Os elementos ficam dispostos em um plano,
composto por várias linhas do mesmo tamanho, como abaixo:

colunas 
1 40 34 50 27 linhas
2 ↓
25 4 18 80
3 0 3 65 11
1 2 3 4

Na matriz de inteiros acima, existem 3 linhas, cada linha com 4 colunas, ou 3x4 (três por
quatro). Essa matriz pode ser declarada assim:
var mat: array[1..3, 1..4] of integer;
Após o nome da matriz, são colocados entre colchetes os intervalos em que ficam os
números das linhas, e os números das colunas, nessa ordem. Note que também aqui os
elementos da matriz devem ser todos do mesmo tipo.
Cada elemento da matriz é identificado pela notação: mat[i,j], onde i é o número da
linha, e j o número da coluna, onde se encontra o elemento. Na figura acima, temos então
que mat[1,1] tem o valor 40.
O comando for... do é muito usado para processar os valores de matrizes.
Exemplos:

a) Para zerar todos os elementos de uma matriz m, com 3 linhas e 4 colunas, declarada
como:
var
m: array[1..3, 1..4] of integer;

basta fazer:
for i:= 1 to 3 do
for j:= 1 to 4 do m[i,j] := 0;

Nota: é usual usar-se a variável i para representar as linhas de uma matriz, a variável j para
representar as colunas.

b) Para ler do teclado valores para preencher a matriz acima (12 valores):
for i:= 1 to 3 do
for j:= 1 to 4 do read(m[i,j] );

Nota: O usuário poderá digitar todos os 12 números em uma só linha (separados por
espaços), ou um número por linha, ou, melhor, 4 números por linha, de forma a visualizar
melhor a matriz.

CAPíTULO 6

Sub-programas em Pascal: Funções e Procedimentos

Conceituação:
Sub-programas são partes de um programa que podem ser consideradas como tarefas
relativamente independentes das demais. Por isso, podem ser programadas de forma
separada, recebem um nome, e depois podem usadas várias vezes dentro do programa
bastando serem “chamadas” pelo nome.
Há duas categorias clássicas de sub-programas: funções e procedimentos.

Funções:
Uma função é um sub-programa que realiza uma tarefa de calcular e produzir como
resultado um valor, o qual será usado por outras partes do programa:
Ex: o programa abaixo usa a função pré-definida sqrt(n), que calcula a raiz quadrada de um
real n, e dá como resultado um valor real:
Exemplo 6-1:

program ex6_1;
var L1,L2,H: real;
begin
L1:= 3.0;
L2:= 4.0;
H:= sqrt(L1*L1+L2*L2);
writeln('A hipotenusa do triangulo retangulo de lados ', L1:3:1, ' e
',
L2:3:1, ' e'' ' ,H:3:1);
end.

No exemplo acima, a função sqrt já vem pré-definida na linguagem Pascal, e pode ser
utilizada diretamente. Note o seguinte:
a) a função tem um argumento real n, ou seja, para usá-la é preciso fornecer um valor real
entre parênteses. A definição de uso é sqrt(n) onde n deve ser um valor real.
b) esse argumento pode ser qualquer expressão real, no exemplo foi L1*L1+L2*L2.
c) a função realiza uma tarefa, através de um algoritmo próprio, para calcular a raiz
quadrada. Essa tarefa constitui o sub-programa, que nesse caso já está armazenado no
computador em forma compilada.
d) quando o programa for executar o comando: H:= sqrt(L1*L1+L2*L2);
vai ocorrer o seguinte:
- primeiro, a expressão do argumento será calculada, para obter o seu valor. No
caso, será calculado o valor 3.0*3.0 + 4.0*4.0 que dá 25.0.
- em seguida o programa entrará em um estado de suspensão da sua execução, e o
controle da execução passará para o primeiro comando do sub-programa sqrt.
- antes de iniciar o sub-programa, o valor calculado do argumento, no caso 25.0,
será passado como valor inicial de uma variável especial do sub-programa que
representa o argumento da função. Essa variável é chamada de parâmetro de valor e
a operação é chamada de passagem de parâmetro.
- o sub-programa executará seus comandos, e a raiz quadrada do argumento será
calculada, obtendo o valo 5.0, nesse caso.
- ao terminar, o sub-programa repassará o valor obtido de volta para o programa. Isso
é feito substituindo a aplicação da função, sqrt(L1*L1+L2*L2),pelo resultado
obtido.
- nesse ponto o controle da execução voltará para o programa no ponto em que havia
interrompido, e o programa executará o comando: H:= 5.0;continuando a
execução normalmente a partir desse ponto.

Funções definidas no próprio programa:


No exemplo acima, foi usada uma função pré-definida na linguagem Pascal. Mas a
linguagem permite que qualquer função possa ser definida no próprio programa.
O programador deve escrever a definição da função na área de declarações do
programa. Essa é a área antes do trecho begin ....end. do programa.
No exemplo abaixo, o programa declara, e depois usa, uma função para calcular o fatorial
de um inteiro. A função está destacada em azul. Note que a variável x faz parte das
declarações do programa, e não da função. A função tem sua própria área de declarações de
variáveis.
Exemplo 6-2:

program ex6_2;
var
x:integer;
function fat(n:integer): longint;
var
i: integer;
f: longint;
begin
f:=1;
for i:= 2 to n do f:= f*i;
fat:= f;
end; {fim da declaracao da funcao}

begin {inicio do programa}


writeln('Digite varios numeros para saber o fatorial');
writeln('Termine com -1');
read(x);
while x > 0 do begin
writeln ('fatorial de ', x, ' = ', fat(x) );
read(x);
end;
end.

Ao executar o programa, o seguinte diálogo poderá ocorrer: (dados do usuário em


itálico):
Digite varios numeros para saber o fatorial.
Termine com –1:
4
Fatorial de 4 = 24
5
Fatorial de 5 = 120
6
Fatorial de 6 = 720
-1 (aqui o programa termina)

As seguintes observações são importantes para um bom entendimento de funções e do


programa acima:

a) A declaração da função fica na área de declarações, junto com as declarações de


variáveis e constantes:
function fat(n:integer): longint;
var
i: integer;
f: longint;
begin
f:=1;
for i:= 2 to n do f:= f*i;
fat:= f;
end; {fim da declaracao da funcao}
b) O formato da declaração da função é bastante parecido com o de um programa,
apenas no cabeçalho a palavra program é substituída pela palavrafunction. A
declaração da função tem sua própria área de declarações e sua área de comandos.
Mas termina com end; e não com end.
c) Além disso, no cabeçalho da função são declarados os seus argumentos, agrupados
por tipo, seguidos do tipo do resultado que produz. A forma sintática do cabeçalho
é:
function <nome da função> (<lista de argumentos>:<tipo>; <lista de argumentos>: tipo; etc):<tipo do resultado>
No caso do fatorial, há apenas um parâmetro inteiro (chamado n) e o resultado será
do tipo longint, porque os fatoriais crescem muito rapidamente:
function fat(n:integer): longint;
d) No corpo da função (parte executável, começando após o primeiro begin)
o nome da função deve receber por atribuição pelo menos uma vez o valor do
resultado:
fat:= f;
É dessa forma que o resultado calculado será repassado de volta ao programa, onde
irá substituir a aplicação da função. Note que, apesar de receber um valor por
atribuição, o nome da função não é uma variável. Caso o nome da função receba
mais de um valor durante a execução da função, o valor que finalmente será
repassado para o programa será o último valor atribuído ao nome da função antes
dela terminar sua execução.
e) Outro ponto importante a registrar é que os identificadores definidos na função só
têm significado dentro da função, e não para fora dela. Chama-se a isso o escopo
dos identificadores. No exemplo acima, as variáveis n, i e f não são “vistas” pelo
programa que usa a função, e são chamadas variáveis locais da função. A
variável n é especial, chamada de parâmetro formal de valor. É ela que receberá o
valor do argumento a ser usado no inicio da execução da função. A partir daí, os
parâmetros de valor se comportam como qualquer outra variável local.

Voltando então para a execução do Exemplo 6-2, vemos que o laço de repetição fará com
que a função fat seja chamada várias vezes, cada vez com um argumento diferente. A cada
vez, o programa será interrompido, o controle será passado para a função, um resultado será
obtido e repassado de volta ao programa, substituindo a aplicação da função.

Tipos dos argumentos e do resultado de funções:


Em uma linguagem de programação como Pascal, as funções podem ter argumentos de
tipos diferentes. Argumentos podem ser de tipos escalares simples, como integer, longint,
real, char e boolean, e podem ser também de tipos estruturados, como vetores, strings,
matrizes e registros (records), esse último tipo ainda por ser estudado.
Por outro lado, o resultado da função tem maiores limitações: o tipo do resultado de uma
função só pode ser um tipo escalar simples, com a exceção do tipo string, que também pode
ser um resultado. Portanto, vetores comuns não podem ser resultado de funções, Veremos
mais adiante que, para contornar essa limitação, podemos usar procedimentos para obter
resultados de sub-programas que sejam tipos estruturados. Mas, para isso, teremos que
usar parâmetros de referência, outro assunto que será visto mais adiante.
Os exemplos a seguir mostram várias funções com tipos diferentes de argumentos e de
resultados.
Exemplo 6-3:
Neste exemplo, a função maiuscula(c) é usada para obter a letra maiúscula correspondente
ao caractere c, se este for uma letra minúscula, caso contrário o valor retornado é o próprio
caractere original:

program ex6_3;
var
frase:string;
i: integer;
function maiuscula(c:char):char;
{essa funcao converte letras minusculas em maiusculas}
begin
case c of
'a'..'z': maiuscula:= chr(ord('A') + ord(c)-ord('a'));
else maiuscula:= c;
end;
end;
begin
writeln('Digite uma frase. Ela sera'' re-escrita em letras maiusculas: ');
readln (frase);
for i:=1 to length(frase) do frase[i] := maiuscula(frase[i]);
writeln(frase);
end.

Note que a função foi aplicada a um argumento do tipo char, e que o valor resultante
também é do tipo char. Para alterar as letras da string frase, foi necessário usar um laço de
repetição para aplicar a função sucessivamente a cada caractere da frase.
No próximo exemplo, a função será aplicada a toda a frase de uma vez (o argumento é do
tipo string) e o resultado também será do tipo string, isto é, a função retorna a frase inteira
alterada:

program ex6_4;
var
frase:string;
i: integer;
function maiusc_str(s:string):string;
{essa funcao retorna uma string com todas as letras maiusculas}
var i: integer;
begin
for i:= 1 to length(s) do
case s[i] of
'a'..'z': s[i]:= chr(ord('A') + ord(s[i])-ord('a'));
end;
maiusc_str:= s;
end;
begin
writeln('Digite uma frase. Ela sera'' re-escrita em letras maiusculas:
');
readln (frase);
writeln(maiusc_str(frase));
end.

Uma observação importante: a função não altera a string frase. Ela retorna outra string, com
as letras alteradas, que substituirá a expressão maiusc_str(frase).É essa string retornada
que será impressa. O valor original da string frase não foi alterado.

No exemplo seguinte, a função cripto(c,n) onde c é um caractere, e n é um inteiro, positivo,


tem o seguinte valor:
- se c for uma letra (maiúscula ou minúscula), cripto(c,n) retorna a letra n posições
adiante no alfabeto, considerado circular (depois do ‘z’ vem o ‘a’, depois do ‘Z’ vem o
‘A’). Ex: cripto(‘Z’, 3) retorna ‘C’
- se c for um dígito, cripto(c,n) retorna o dígito n posições adiante, também circular
(depois do ‘9’ vem o ‘0’)
Ex: cripto(‘3’, 11) retorna ‘4’.
- para qualquer outro caractere, a função retorna o próprio caractere sem alteração.

Esse exemplo é mais complexo, e é interessante para ressaltar a importância


de se separar as tarefas em sub-programas separados. Dessa forma, o
programa que usa a função fica muito mais compreensível, e também a função
pode ser testada e aperfeiçoada independentemente dos programas que a
usarão. O programa que usa a função é bem simples, e toda a complexidade
da criptografia fica encapsulada na definição da função.

Exemplo 6-5:
program ex6_5;
var
frase: string;
i,n: integer;

function cripto(c: char; n: integer): char;


var pos,d:integer;
begin
n:= n mod 26; {reduz logo o n }
pos:= ord(c) + n; {posicao na tabela de caracteres n casas adiante de c}
case c of
'a'..'z': begin
d:= pos -ord('z'); {d e' quanto pos passou de z}
if d<=0 then cripto:= chr(pos)
else cripto:= chr(ord('a') + d-1 )
end;
'A'..'Z': begin
d:= pos -ord('Z'); {d e' quanto pos passou de Z}
if d<=0 then cripto:= chr(pos)
else cripto:= chr(ord('A') + d-1 )
end;
'0'..'9': begin
d:= pos -ord('9'); {d e' quanto pos passou de 9}
if d<=0 then cripto:= chr(pos)
else cripto:= chr(ord('0') + d-1 )
end;
else cripto:= c; {se for outro caractere, nao altera}
end;
end;
begin
writeln('Digite uma frase: ');
readln(frase);
writeln('Escolha o valor de n para a criptografia: ');
readln(n);
for i:=1 to length(frase) do write(cripto(frase[i], n));
readln;
end.

Procedimentos

Procedimentos representam outra categoria de sub-programas em Pascal. As diferenças


entre procedimentos e funções são:
a) um procedimento é um sub-programa que realiza uma tarefa, mas não retorna um valor
de resultado, como as funções.
b) o uso do procedimento é semelhante a um comando, e tem o mesmo valor sintático,
isto é, onde na linguagem se espera um comando, pode ser colocada uma chamada de
procedimento.
O exemplo abaixo ilustra a declaração e o uso de um procedimento de nome msg, que faz a
tarefa de escrever uma mensagem (uma string) em um ponto determinado da tela:
Ele utiliza um procedimento pré-definido em Pascal, gotoxy(x,y), que posiciona o cursor no
ponto correspondente à interseção da linha y com a coluna x:

Exemplo 6-6:

program ex6_6;
uses crt; {necessario para usar gotoxy e clrscr}
var linhamedia,colunamedia: integer;
m:string;
procedure msg(frase:string; x,y: integer);
begin
gotoxy(x,y);
write(frase);
end;
begin
clrscr;
msg('esta frase na linha 1 coluna 1', 1, 1);
msg('esta frase na linha 3 coluna 2', 2, 3);
msg('esta frase na linha 5 coluna 3', 3, 5);
m:= 'meio da tela';
linhamedia:=12;
colunamedia:=40;
msg(m,colunamedia-length(m) div 2,linhamedia);
end.

O procedimento msg tem 3 parâmetros formais de valor: frase, x e y. Ele é chamado 4


vezes pelo programa. Note que cada chamada tem a forma de um comando. A cada
chamada, o valor de cada parâmetro é inicializado com o valor correspondente do
argumento usado. Da mesma forma que para as funções, cada argumento usado na chamada
de um procedimento pode ser qualquer expressão que tenha valor do tipo esperado.
Existem vários comandos que usamos normalmente na linguagem Pascal que são na
realidade procedimentos pré-definidos. Os casos mais comuns são os procedimentos de
leitura e escrita: read, readln, write, e writeln, são procedimentos bastante complexos, que
têm a faculdade adicional de aceitar um numero variável de argumentos. Outros comandos,
como clrscr, gotoxy, etc também são procedimentos.

Parâmetros de Referência
Até agora todos os parâmetros usados nos exemplos de funções e procedimentos
foram parâmetros de valor. Um parâmetro de valor é uma variável local do sub-programa,
que tem a propriedade de receber um valor inicial passado durante a chamada. Fora disso,
comporta-se como uma variável local normal, como as demais definidas na seção var.
As variáveis locais de um sub-programa existem em um espaço de memória próprio, que só
é acessível ao sub-programa. Por esse motivo, os parâmetros de valor não podem ser
”vistos” pelo programa externo ao sub-programa. Apenas o resultado do cálculo da função
pode retornar ao programa.
Os parâmetros de referência, ou parâmetros variáveis, permitem que valores calculados no
sub-programa possam ser repassados ao programa, de forma diferente do mecanismo de
retorno de função.
O mecanismo usado no parâmetro de referência é o seguinte:
a) na definição do procedimento, os parâmetros de referência devem ser precedidos do
prefixo var.
b) Na chamada do procedimento, os argumentos usados no lugar de parâmetros de
referência devem ser obrigatoriamente nomes de variáveis do programa, e não
expressões.
c) Quando o procedimento é chamado, o parâmetro de referencia recebe, não mais um
valor, mas uma referência para a variável correspondente do programa. Na prática, isso
significa que o parâmetro do sub-programa, e a variável correspondente do programa,
passam a ser a mesma variável, como se fossem sinônimos. O efeito é que tudo que
acontece com um parâmetro de referência do sub-programa vai se refletir
imediatamente na variável correspondente do programa. Ou seja, quando o sub-
programa termina, e devolve o controle de execução ao programa, as variáveis passadas
por referência para o sub-programa podem ter sido alteradas.

O exemplo a seguir define dois procedimentos, que são usados no programa.


O primeiro procedimento chama-se altera_variavel, e tem dois parâmetros: o parâmetro
de referência x e o parâmetro de valor n. O efeito desse procedimento é fazer com que
uma variável do programa tenha o valor somado a n pelo procedimento. A variável que
deverá ser alterada será passada por referência. Já a quantidade a ser somada, será
passada por valor.
O segundo procedimento elimina os n primeiros caracteres de uma string do programa. A
string a ser alterada é passada por referência. A quantidade de caracteres a serem
eliminados é passada por valor:
Exemplo 6-7:
program ex6_7;
uses crt;
var a,b,c: integer;
nome: string;
procedure altera_variavel(var x:integer; n:integer);
{a e' parametro de referencia, n e' parametro de valor}
begin
x:= x+n;
end;
procedure reduz_string (var frase:string; n:integer);
{esse procedimento elimina os n primeiros caracteres da frase}
var i:integer;
s:string;
begin
s:=''; {s e' inicializada com uma string vazia, ou nula}
for i:= n+1 to length(frase) do s:=s+frase[i]; {operador + de
concatenacao}
frase:=s; {o conteudo de frase no programa sera’ alterado}
end;
begin {aqui inicia a execucao do programa}
clrscr;
a:=10;
b:=20;
c:=30;
writeln(a:4,b:4,c:4);
altera_variavel(a, 5); {a variavel a tera' seu valor alterado para a+5}
altera_variavel(b, 7); {a variavel b tera' seu valor alterado para b+7}
altera_variavel(c, 15); {a variavel c tera' seu valor alterado para
c+15}
writeln(a:4,b:4,c:4);
nome:= 'Antonio Claudio da Sliva';
writeln('nome antes : ', nome);
reduz_string(nome,8); {deve eliminar os 8 caracteres antes de Claudio}
writeln('nome depois: ', nome);
readln;
end.

O próximo exemplo mostra um programa que usa vários procedimentos e funções.


Um processo de criptografia de frases de até 100 caracteres, com código
(chave) igual a k<=10, consiste em colocar os caracteres da frase em uma
matriz, usando apenas as primeiras k colunas. No exemplo abaixo, com k=8,
são usadas as 8 primeiras colunas de uma matriz 10x10 para criptografar a
frase:

UNIVERSIDADE FEDERAL DO RIO DE JANEIRO

O número de linhas necessárias para conter todos os caracteres da frase é


dado pela expressão:

no. de linhas = menor inteiro maior ou igual a tamanho da frase/k

Para k=8, e como a frase acima tem 37 caracteres, o número necessário de


linhas é: 37/8= 4,6 => 5.

Inicialmente, os caracteres da string são


U N I V E R S I colocados na matriz linha a linha, ocupando as k
DA D E F E D primeiras colunas apenas:

E R A L D O 1 2 3
4 5 6 7 8 9 10
R I O D E J
1
A N E I R O
2
3
4
5
6
7
8
9
10

A codificação é completada reescrevendo a matriz em forma de string, desta vez escrevendo os caracteres
segundo as colunas, a partir da coluna 1, apenas para as linhas usadas.
Completando o exemplo acima, a frase codificada fica da forma seguinte:

UDERANARINIDAOEVEL IE DRRFDEOSEO ID J

O interessante é que o mesmo processo pode ser usado tanto para codificar
como para decodificar. Para decodificar, toma-se a frase codificada, desta vez
com chave (no. de colunas) igual ao número de linhas usado na codificação
original, obtendo a matriz transversa abaixo:

1 2 3 4 5 6 7 8 9 10

U D E R A 1

NA R I N 2
3
I D A O E 4
V E L I 5
6
E D R 7
8
R F D E O 9
10
S E O

I D J
Basta usar o processo de codificação para obter a
frase original, lendo coluna a coluna.

O número mínimo de linhas necessárias para


codificar uma frase com ncar caracteres, e chave k,
é dada pela expressão: round(ncar/k + 0.4)

A solução abaixo usa 2 procedimentos e 2 funções.

Os procedimentos le_frase e le_chave são usados para solicitar do usuário a


frase a ser codificada, e a chave a ser usada. Ambos usam parâmetros de
referência varpara passar os valores lidos para o programa.

A função linhas_necessarias(f, k) calcula e retorna o menor número de linhas


necessárias para codificar a frase f com a chave k.
A função codifica(frase,k) é que faz o trabalho de codificar a string frase com a
chave k, e retorna a string codificada. A função utiliza o procedimento
limpa_matriz, para inicializar os elementos da matriz com espaços em branco.
Note que o procedimento é interno à função, e que a matriz é acessada como
variável global ao procedimento, não sendo necessário passar parâmetro.

A função usa uma matriz 10x10, podendo acomodar frases de até 100
caracteres.

O programa propriamente dito consiste apenas de chamadas dos


procedimentos. Todo o trabalho real é feito nos sub-programas, o programa
apenas coordena a chamada dos mesmos para realizar uma tarefa completa.

program codifica_matr;
{Este programa codifica textos usando o metodo da matriz transposta}
var
frase: string;
chave:integer;

procedure le_frase (var frase:string);


begin
writeln('Digite a frase a ser codificada ate'' 100 caracteres:' );
readln(frase);
end;

procedure le_chave(var chave:integer);


var i: integer;
begin
writeln('Digite a chave de codificacao < 10: '); readln(chave);
end;

function linhas_necessarias(f:string; k: integer):integer;


{retorna o menor numero de linhas necessarias para codificar a string f
com a chave k}
begin
linhas_necessarias:= round(length(f)/k +0.4);
end;

function codifica (frase:string; k: integer):string;


var
m: array[1..10,1..10] of char;
i,j,n,lin,col,linhas, colunas:integer;
s: string;
procedure limpa_matriz;
var i,j:integer;
begin
for i:= 1 to 10 do
for j:= 1 to 10 do m[i,j]:= ' ';
end; {limpa_matriz}
begin
limpa_matriz;
colunas:= k;
linhas:= linhas_necessarias(frase,k);
for i:= 1 to length(frase) do begin
lin:= (i- 1) div colunas+1;
col:= i mod colunas; if col=0 then col:=colunas;
m[lin,col]:= frase[i];
end;
s:='';
for j:=1 to colunas do
for i:= 1 to linhas do s:=s+m[i,j];
codifica:=s;
end; {codifica}
begin
le_frase(frase);
le_chave(chave);
frase:=codifica(frase,chave);
writeln('Frase codificada com a chave ', chave,': ', frase);
chave := linhas_necessarias(frase, chave);
frase:= codifica(frase,chave);
writeln('Decodificando com a chave ', chave, ': ', frase);
readln;
end.

You might also like