v2 ; var a,b: integer ; begin read (a) ; read (b) ; while (a <> 0) or (b <> 0) do begin writeln (a+b) ; read (a) ; read (b) ; end; end. Figura 5.9: Duas formas para somar pares de nu´meros. Este exemplo e´ extremamente interessante pois permite ver claramente que o co´digo referente aos comandos de leitura e impressa˜o sa˜o os mesmos, apesar da ordem diferente no segundo exemplo. O que difere e´ a estrutura de controle do lac¸o, isto e´, do bloco de comandos que se repete. No quadro da esquerda, o algoritmo precisa contar ate´ 30, por isto existe uma varia´vel cont que faz esta conta. No quadro da direita, o lac¸o e´ controlado por uma expressa˜o booleana um pouco mais sofisticada que a do exemplo anterior, pois faz uso do operador or. A expressa˜o em questa˜o se torna falsa apenas quando ambos os nu´meros lidos forem nulos. Se um dois dois for na˜o nulo, o lac¸o e´ executado. O comando de impressa˜o ficou aparentemente invertido pela simples raza˜o de que o teste depende de uma primeira leitura das varia´veis a e b antes do teste, sena˜o o teste na˜o pode ser feito. Mas, ressaltamos, o nu´cleo do programa e´ exatamente o mesmo, leˆ dois nu´meros e imprime a soma, o que muda e´ o controle do lac¸o. 5.7 Testar se um nu´mero lido e´ positivo Problema: Ler um u´nico nu´mero do teclado e imprimı´-lo apenas se ele for positivo. Parece simples para o ser humano saber se um nu´mero e´ positivo ou na˜o, mas 46 CAPI´TULO 5. CONCEITOS ELEMENTARES para o computador o que esta´ em memo´ria e´ apenas uma sequeˆncia de bits. Logo, para ele decidir se um nu´mero e´ positivo deve usar uma expressa˜o booleana. Mas, como executar o comando de impressa˜o apenas em um caso (do nu´mero ser positivo) e ignorar a impressa˜o caso na˜o seja? Este problema permitira´ introduzir a noc¸a˜o de desvio condicional. Um desvio condicional produz exatamente o efeito desejado, faz um teste e depen- dendo do resultado executa ou na˜o o comando subsequente. A figura 5.10 ilustra a soluc¸a˜o deste problema. No caso, o comando writeln so´ e´ executado se a expressa˜o booleana for verdadeira. Caso o nu´mero lido seja nulo ou negativo o fluxo de execuc¸a˜o do programa “pula” para o comando subsequente, que no caso e´ o fim do programa. program imprime se positivo ; var a,b: integer ; begin read (a) ; i f a > 0 then writeln (a) ; (∗ so executa se a for positivo ∗) end. Figura 5.10: Imprime se for positivo. O comando de desvio condicional admite uma segunda forma, que estabelece um fluxo alternativo ao programa dependendo do teste. Considere o seguinte problema. Problema: Ler um u´nico nu´mero do teclado e imprimı´-lo apenas se ele for positivo. Se na˜o for imprimir a mensagem “nu´mero inva´lido”. A soluc¸a˜o deste problema requer uma variante do comando if, conforme ilustrado na figura 5.11. Apenas um comando de impressa˜o sera´ executado. program imprime se positivo ; var a,b: integer ; begin read (a) ; i f a > 0 then writeln (a) (∗ so executa se a for positivo ∗) else writeln (’numero invalido’) ; (∗ executa se a for nulo ou negativo ∗) end. Figura 5.11: Imprime se for positivo, segunda versa˜o. 5.8. RESUMO 47 5.8 Resumo Neste cap´ıtulo vimos todas as estruturas elementares para qualquer algoritmo (ou programa) presentes em qualquer linguagem de programac¸a˜o. Sa˜o eles: Comandos • Entrada e sa´ıda (read e write, respectivamente); • Atribuic¸a˜o (:=); • Repetic¸a˜o (while/do); • Desvio condicional (if/then, ou if/then/else); Expresso˜es • Aritme´ticas; • Booleanas. Qualquer algoritmo e´ escrito como uma combinac¸a˜o destes comandos manipu- lando dados em memo´ria (varia´veis) da maneira como o algoritmo estabelece. Como sabemos, cada problema tem va´rias soluc¸o˜es poss´ıveis, mas uma vez fixado uma, pode- se escrever o programa na forma como o computador entenda, usando-se apenas as noc¸o˜es apresentadas neste cap´ıtulo. A menos do uso de estruturas de dados sofisticadas, as quais veremos a partir do cap´ıtulo 10, agora ja´ e´ poss´ıvel escrever qualquer algoritmo, e consequentemente, qualquer programa! O que muda de uma linguagem de programac¸a˜o para outra e´ basicamente a grafia dos comandos, as vezes com alguma ligeira modificac¸a˜o na sintaxe e na semaˆntica do comando. Por exemplo, na linguagem C, o comando write e´ grafado printf, na linguagem BASIC e´ grafado print. Cada linguagem tem um comportamento diferente, na˜o e´ apenas o nome que muda. Por exemplo, se imprime e muda de linha ou na˜o, em qual formato escreve, etc. Mas, estes sa˜o os elementos ba´sicos para se programar. No pro´ximo cap´ıtulo veremos como usar estes comandos de maneira inteligente para resolver problemas mais complexos. O leitor pode pular o apeˆndice da pro´xima sec¸a˜o sem preju´ızo da compreensa˜o do restante do texto. 5.9 Apeˆndice Existe mais um comando de controle de fluxo, presente em qualquer linguagem de programac¸a˜o: o comando de desvio incondicional. Segundo o modelo de Von Neumann estudado, isto nada mais e´ do que alterar o controlador de instruc¸o˜es para um enderec¸o arbitra´rio (na verdade controlado) quando pensamos no modelo de baixo n´ıvel. A figura 5.12 ilustra o uso do desvio incondicional para resolver o problema de se imprimir todos os nu´meros de 1 a 30. 48 CAPI´TULO 5. CONCEITOS ELEMENTARES program contar ; label : 10; var i : integer ; begin i := 1; 10:write ( i ) ; i := i + 1; i f i <= 30 then goto 10; end. Figura 5.12: Exemplo do uso do desvio incondicional. Neste exemplo, a varia´vel i e´ inicializada com o valor 1 e em seguida e´ executado o comando que imprime 1 na tela. Em seguida a varia´vel i e´ incrementada e, apo´s verificar que 1 e´ menor ou igual a 30, o fluxo do programa executa o comando de desvio incondicional goto, que faz com que o fluxo de execuc¸a˜o do programa va´ para a linha indicada pelo ro´tulo 10, isto e´, imprime o valor da varia´vel i, incrementa o i e assim por diante. Quando i valer 31 o goto na˜o e´ executado, o que faz com que o end final seja atingido e o programa termina. Em outras palavras, e´ uma outra maneira (mais estranha) de se implementar o mesmo programa da figura 5.7. A observac¸a˜o interessante e´ que, no n´ıvel de ma´quina, o que o compilador faz e´ gerar a partir do programa da figura 5.7, um co´digo de ma´quina implementado usando-se uma noc¸a˜o de desvio incondicional, implementada no reperto´rio reduzido de instruc¸o˜es, mas isto o programador na˜o e´ obrigado a saber agora. O que ele deve saber e´ que o uso de comandos de desvio incondicional na˜o e´ recomendado pois na medida em que os programas va˜o ficando com muitas linhas de co´digo, digamos algumas centenas de linhas ou mais, o que ocorre e´ que o programador tende a se perder e passa a ter muita dificuldade em continuar o desenvolvimento do programa quando o uso do goto e´ feito de qualquer maneira e, em especial, de forma exagerada. Isto tende a tornar o co´digo ileg´ıvel e de dif´ıcil manutenc¸a˜o. Como vimos, as linguagens de alto n´ıvel permitem mecanismos mais elegantes para repetir trechos de co´digo sem necessidade do uso do goto, usando-se o while. Isto e´ baseado no princ´ıpio da programac¸a˜o estruturada, que nasceu com a linguagem ALGOL-60. Esta linguagem, apesar de na˜o ser mais usada, deu origem a` maior parte das linguagens modernas, entre elas o pro´prio Pascal. Este comando esta´ em um apeˆndice pois no´s nunca mais o usaremos. 5.10. EXERCI´CIOS 49 5.10 Exerc´ıcios 1. Leia o mini guia da linguagem Pascal, dispon´ıvel em http://www.inf.ufpr. br/cursos/ci055/pascal.pdf, em especial os cap´ıtulos de 1 a 3, a sec¸a˜o 4.2 e o cap´ıtulo 7. 2. Tente compilar e executar com va´rias entradas os programas Pascal vistos neste cap´ıtulo. 3. Modifique o programa Soma2 para que ele receba um nu´mero inteiro N de en- trada e imprima a seguinte sequeˆncia