Métodos de Programação I 2. 20 Ana Maria de Almeida 2.2.8 ESTRUTURAS DE CONTROLO Estruturas de controlo são instruções especiais em Pascal que permitem controlar o fluxo de sequência de instruções, alterando a ordem sequencial explícita. Essas alterações podem ser devidas a escolhas de blocos de instruções devido à ocorrência de determinadas condições, ou porque é necessário repetir instruções de construção iterativa (construção passo a passo) de um determinado valor. Assim, podemos considerar as esruturas de controlo agrupadas segundo o diagrama seguinte. Sequência Condicional Selecção Estruturas de Base Alternativa Repetição Enquanto Até que Com contador Procedimento Subprograma Função • SELECÇÃO Selecção Condicional - a instrução if-then-else if expressão lógica then instrução else instrução Esta instrução permite fazer uma escolha de instruções a executar consoante o valor da expressão lógica é verdadeiro ou falso. Assim, caso a avaliação da expressão a seguir ao if seja verdadeiro, executa-se a instrução correspondente ao then. Caso contrário, executa-se a instrução presente no else. De acordo com o diagrama de sintaxe, há ainda a hipótese de nem sequer se escrever o else e, neste caso, se a expressão lógica fôr falsa, passa-se imediatamente à instrução seguinte. Por exemplo, x := 5; y:= 8; if x = y then write( x ); write(‘Eis!’); EFEITO: Eis! ou ainda, x := -81; if x >= 0 then raiz := sqrt( x ) else raiz := sqrt( -x ); EFEITO: raiz ← 9 (raiz toma o valor de raiz quadrada de -x) Métodos de Programação I 2. 21 Ana Maria de Almeida Vamos agora apresentar um exemplo típico do uso da alternativa num programa que lê 3 números inteiros positivos, verifica se podem constituir lados de um triângulo e, em caso afirmativo, indica o tipo de triângulo: Especificações: • Dados: 3 valores inteiros positivos • Resultados: classificação de triângulo ou impossibilidade em formar um triângulo Dados 3 valores naturais, para estes poderem constituir as medidas dos lados de um triângulo, cada lado deve ser menor que a soma dos lados opostos. No caso de esta condição ser verdadeira, um triângulo diz-se: “equilátero” se tiver os lados todos iguais; “isósceles”, caso tenha, apenas, dois lados iguais; “escaleno” se os lados forem todos de medidas diferentes. Assim, um programa em Pascal para responder a esta questão poderá ser o seguinte: program triangulo (input, output); var aa, bb, cc : 1 .. maxint; begin read( aa, bb, cc); if ( aa < bb + cc ) and ( bb < aa + cc ) and ( cc < aa + bb ) then if ( aa = bb ) or ( aa = cc ) or ( bb = cc ) then if ( aa = bb ) and ( bb = cc ) then writeln(‘Equilatero‘) else writeln(‘Isosceles‘) else writeln(‘Escaleno‘) else writeln(‘Nao pode ser triangulo‘); writeln; end. Figura 2.5: programa para caracterizar um triângulo. Repare como a identação é importante, permitindo-nos saber imediatamente, a que instrução if corresponde cada then e cada else. É também importante fazer notar que, entre os if, then e else não pode existir ; (ponto e vírgula). Caso seja necessária mais do que uma instrução no then ou no else, e portanto o uso obrigatório de pontos e vírgulas, deve-se usar o delimitador de blocos begin-end, obviamente, sem ponto e virgula a seguir ao end (a menos de um else seguido de outra instrução qualquer3). A Selecção Múltipla ou de Alternativa - instrução case case expressão of constante , : instrução end ; ; não pode ser do tipo real No caso de necessitarmos de escolha múltipla, ter uma instrução de escolha binária (if) torna-se demasiado enfadonho de usar. Esta nova instrução dá-nos a possibilidade de apreciar vários casos e decidir para todos eles ou para mais do que uma escolha. 3 Repare no último else do exemplo da figura 2.5 Métodos de Programação I 2. 22 Ana Maria de Almeida Suponha-se, por exemplo, que, numa portagem de auto-estrada, existe o seguinte módulo num programa: type tipoveiculo = (bicicleta, motociclo, motorizada, automovel, autocomreb, camioneta, autocarro, camiao, reboque); var veiculo : tipoveiculo; Se chegar um veículo qualquer à portagem, o programa, dependendo de onde chega e em função do seu tipo, tem de decidir qual a portagem que vai pagar: case veiculo of bicicleta, motociclo autocomreb, camioneta autocarro, camiao reboque end; : : : : writeln(‘2,3 euros’ ); writeln(‘2,8 euros’ ); writeln(‘3 euros’ ); writeln(‘3,2 euros’ ) Um exemplo mais completo é o do programa abaixo que, dada uma data, calcula a data do dia seguinte: Especificações: • Dados: data no formato dia mês ano • Resultados: data do dia seguinte ao dado. È óbvio que a primeira coisa a fazer é delimitar um domínio para os séculos abrangidos pelo programa. Seja ele, Domínio =1900 .. 2100 Comecemos por descrever o algoritmo a implementar no programa: o o o ler dia , mês, ano ; escrever “Dia seguinte a dia/mês/ano :” ; determinar o número de dias desse mês: caso mês? mês = 1,3,5,7,8,10,12 mês = 4,6,9,11 ultimodia ← 31 mês =2 ultimo ← 30 (bissexto?) ano mod 4 = 0 e ano ≠ 1900,2100 ultimo ← 28 o actualizar dia, mês, e ano para seguintes: se dia = ultimo senão dia ← 1 se mes = 12 mes ← 1 ano ← ano + 1 o escrever dia/mês/ano. senão mes ← mes + 1 dia ← dia +1 senão ultimo ← 29 Métodos de Programação I 2. 23 Ana Maria de Almeida program dia_seguinte (input, output); var dia : 1 .. 31 ; mes : 1 .. 12 ; ano : 1900 .. 2100 ; ultimo : 28 .. 31 ; begin (* leitura e escrita da data dada *) read( dia, mes, ano); write(‘ Dia seguinte a ‘, dia :2, ‘/’, mes:2, ‘/’, ano:4, ‘:’:3); (* determinação do numero de dias do mes *) case mes of 1,3,5,7,8,10,12 : ultimo := 31; 4,6,9,11 : ultimo := 30; 2 : if (ano mod 4 = 0) and (ano <> 1900) and (ano <> 2100) then ultimo := 29 else ultimo := 28 end; if ( dia = ultimo ) then begin necessitamos usar dia := 1; várias intruções if ( mes = 12 ) then begin dia := 1; ano := ano + 1 end else mes := mes + 1 end else dia := dia + 1; writeln(dia:2, ‘/’, mes:2, ‘/’, ano:4); writeln; end. Figura 2.6: programa para calcular data do dia deguinte REPETIÇÃO - CICLOS Ciclo “Enquanto” : instrução while - do while expressão lógica do instrução UMA INSTRUÇÃO (SIMPLES OU COMPOSTA) Esta estrutura permite repetir uma instrução simples, ou um bloco de instruções delimitado por begin-end (instrução composta). Essa repetição é efectuada enquanto a expressão lógica se mantiver verdadeira: while TRUE do INSTRUÇÂO; Temos, portanto, duas partes principais nesta estrutura: o teste lógico, efectuado antes de qualquer outra coisa - cabeça do ciclo - e a segunda parte que consiste na instrução (ou bloco de instruções) - corpo do ciclo - que só é executada se o teste fôr verdadeiro. Isto significa que, se na primeira vez que a expressão fôr testada, fôr avaliada para falso, o ciclo nunca é efectuado (há um salto sequencial directo para a primeira instrução após o ciclo). Métodos de Programação I 2. 24 Ana Maria de Almeida Um ciclo é normalmente utilizado para calcular valores através de fórmulas iterativas - fórmulas que usam valores anteriores para calcular novos valores. Um exemplo típico é o do cálculo de potências como, por exemplo, 21 = 2, 22 = 21x2 = 4, 23 = 22x2 = 8, …, 2i = 2i-1x2, …, onde cada novo valor é obtido multiplicando por 2 o valor anterior. Vamos então construir um programa para imprimir uma tabela de potências sucessivas de 2, desde que inferiores a 1000: contador i ← 1 potencia ← inicializações 2 enquanto potencia < 1000 cabeça do ciclo ( teste lógico ) escrever i, potencia i ← i+1 potencia ← potencia * 2 fórmulas iterativas corpo do ciclo Neste caso vamos usar duas fórmulas iterativas: uma para calcular a potência i em curso - que varia desde 1 até ao limite (2i < 1000) - e outra para o cálculo do valor concreto - multiplicação - da potência. Nestes casos e em qualquer outro: toda a fórmula iterativa tem de ser inicializada antes do ciclo. A implementação deste algoritmo em Pascal é, portanto, a seguinte: instrução composta program tabela (output); var i, potencia : 0 .. 1000; begin i := 1; potencia := 2; while potencia < 1000 do begin writeln( i, potencia); i := i +1; potencia := potencia * 2 end end. Figura 2.7: programa para imprimir potências de 2 menores que 1000 Ciclo “Até que” : instrução repeat - until repeat instrução until expressão lógica ; UMA OU MAIS INSTRUÇÕES Métodos de Programação I 2. 25 Ana Maria de Almeida As principais diferenças entre esta estrutura e a anterior residem nos dois pontos seguintes: ● Contrariamente ao que acontecia na repetição anterior, esta estrutura permite repetir, ou uma instrução simples, ou uma série sequencial de instruções, e essa repetição é efectuada até que a expressão lógica se torne verdadeira: repeat instruções; until TRUE ● O teste lógico do repeat (a cabeça deste ciclo) é no final do ciclo o que significa que o ciclo é sempre executado pelo menos uma vez. Passamos a apresentar alguns exemplos: 1. Calcular a soma de vários números inteiros, dados um em cada linha, sendo o final dado por uma linha que só contém zero: Descrição do algoritmo: soma ← 0 fórmula iterativa ler numero, mudar de linha soma ← soma + numero até que numero = 0 inicialização corpo do ciclo teste do ciclo escrever soma Implementação: program somar (input, output); varnumero, soma : integer; begin soma := 0; repeat readln( numero ); soma := soma + numero; until numero = 0; writeln( soma : 10 ); end. Figura 2.8: programa para somar inteiros 2. Ler um número inteiro e verificar se é uma capicua: 2451542 é uma capicua (é igual ao seu “inverso”) Métodos de Programação I 2. 26 Ana Maria de Almeida Descrição do algoritmo: ler número n ← número inverso ← 0 cópia para “destruir” digito ← n mod 10 inverso ← inverso*10 + digito n ← n div 10 até que numero = 0 número = inverso é capicua senão não é Implementação: program capicua (input, output); vardigito : 0 .. 9; numero, n, inverso : 0 .. maxint; begin read( numero ); n := numero; inverso := 0; repeat digito := n mod 10; inverso := inverso * 10 + digito; n := n div 10 until n = 0; (* a cópia do número foi destruida *) if numero = inverso then writeln( numero, ‘ Capicua’ ) else writeln ( numero, ‘ Não e capicua ‘) end. Figura 2.9: programa para encontar capicuas Exercícios: 1. Identifique a fórmula recursiva que está envolvida no algoritmo acima e qual é a sua inicialização. 2. Faça a simulação manual do programa para uma capicua e para outro número diferente do seu inverso. 3. Modifique o programa para usar um while-do em vez do repeat-until (Note que números de um só algarismo também são capicuas).