Prévia do material em texto
I PROGRAMAÇÃO BÁSICA COM VISUALG TEORIA E PRÁTICA Mário Leite Antonio Carlos Nicolodi II DEDICATÓRIAS Dedico este livro às minhas quatro queridas, e inesquecíveis, professoras do Curso Primário do “Grupo Escolar Emílio Soares”, da cidade de Tombos (MG), no período de 1956-1959, que me ensinaram a ler e escrever, para formar a base da minha Educação! Olga de Oliveira Osken (in memorian) Consuelo Idalina Ramos (in memorian) Maria Passos Borba (in memoriam) Terezinha Rezende Linhares Mário Leite Dedico esta obra à minha esposa Márcia e à minha filha Bianca que me deram seu apoio incondicional. Antônio Carlos Nicolodi III CITAÇÃO O computador só faz aquilo que você o manda fazer; e não, necessariamente, aquilo que você quer ele faça! IV AGRADECIMENTOS Agradeço primeiramente a Deus que me deu força e persistência para escrever mais este livro, depois de um bom tempo de muita pesquisa, dedicação e muitas revisões. Agradeço a todos os meus colegas professores e professoras da Universidade de Uberaba (UNIUBE) pela força e incentivo que sempre me deram em todas as minhas obras. Agradeço ao professor Antonio Carlos Nicolodi pelos preciosos esclarecimentos e atualizações da ferramenta Visualg, além desta sua preciosa parceria. Agradeço ao Clube dos Autores, pela oportunidade desta publicação. Mário Leite Agradeço primeiramente aos meus pais por me dar a vida, à minha esposa Márcia e à minha filha Bianca, por me ajudarem nos momentos mais difíceis e nos de grandes alegrias; agradeço também aos meus professores. Agradeço muito ao meu grande amigo e parceiro Mário Leite por me dar esta oportunidade de poder participar com ele desta obra, que deverá ajudar muita gente no futuro. Mas, principalmente, agradeço à Deus por me dar saúde e o conhecimento que pretendo compartilhar com todos. Antonio Carlos Nicolodi V SOBRE OS AUTORES Mário Leite é natural de Tombos (MG); estudou física durante dois anos no Instituto de Física da UFRJ; foi aluno de Iniciação Científica do Centro Brasileiro de Pesquisas Físicas (CBPF: Divisão de Física Nuclear) e do CNPq, no Rio de Janeiro. É graduado e pós-graduado em engenharia pela Pontifícia Universidade Católica do Rio de Janeiro (PUC/RJ), onde foi professor auxiliar de ensino e pesquisa do Departamento de Ciências dos Materiais e Metalurgia. É especialista em Análise de Sistemas pelo Centro Universitário de Maringá (UniCesumar/PR) e mestre em Engenharia de Produção pela Universidade Federal de Santa Catarina (UFSC). Trabalhou durante quatro anos na Indústria e Comércio de Minérios (ICOMI), no estado do Amapá, como engenheiro de pesquisas, desenvolvendo aplicações para o setor de produção. Foi chefe do Setor de Informações Gerenciais da Mineração Caraíba S.A (BA) durante nove anos, ministrando cursos de técnicas de programação para os engenheiros da empresa, e desenvolvendo aplicações para os setores de produção e manutenção. Nesta empresa participou do projeto de mecânica das rochas para implantação do sistema de escavação da mina subterrânea, na adaptação do software de elementos finitos para microcomputadores. É professor de linguagem de programação, análise de sistemas e tecnologia da informação em cursos de processamento de dados, sistemas de informação e administração de empresas. Também é autor de vários livros nas áreas de linguagens e técnicas de programação e ferramenta de ambiente numérico. Atualmente é professor da Universidade de Uberaba (UNIUBE) nas áreas de ferramentas computacionais e linguagens de programação. VI Antonio Carlos Nicolodi é natural de Blumenau (SC); estudou eletrônica no Centro Educacional Profissionalizante Herman Hering (CEDUPHH), estudou Mecanografia e processamentos de dados na ETEVI-Furb de Blumenau e Técnica em Informática para a Internet no Instituto Federal Santa Catarina (IFSC). É graduado em Gestão em Tecnologia da Informação e em Administração de Empresas pela Uniasselvi-Fameblu, com pós- graduado em Educação à Distância (EaD - Gestão e Tutoria) e Governança em T.I. Trabalhou como programador na empresa Apoio Informática (Blumenau), foi gerente de CPD na Escola de Contabilidade aonde desenvolveu um sistema de integrado de contabilidade. Foi sócio proprietário da empresa Domínio Informática e programador chefe, onde desenvolveu vários sistemas ERP para a comunidade do Vale do Itajaí; foi professor no Colégio Doutor Blumenau na disciplina de programação Cobol para os cursos de (Processamento de dados, Administração de empresas e Contabilidade). É professor de informática nas prefeituras de Gaspar e Ilhota, professor de lógica de programação no CEDUPHH (Blumenau); professor de arquitetura de computadores, lógica de programação de cursos de informática, jogos de computadores, entre outros, na Uniasselvi-Fameblu (Blumenau). Criador de vários métodos de ensino de lógica de programação, entre eles o método conhecido como portugol (algoritmos escritos em Português nos anos 1980- 83 também conhecido como português estruturado), usado por vários professores/alunos e escritores (autores em suas obras literárias técnicas). É um dos desenvolvedores do software conhecido como Visualg até a versão 2.5 e o criador da versão 3.0 em 2014, que é o interpretador oficial de algoritmos escritos em portugol. Atualmente é professor, lecionando no horário noturno, e durante o dia é funcionário público na prefeitura de Ilhota (SC) na área administrativa. VII PREFÁCIO Eis-me aqui tecendo o prefácio do livro destes ilustres profissionais - o engenheiro e programador Mário Leite, e o professor Antônio Carlos Nicolodi, administrador, programador que há décadas tem se dedicado a área da tecnologia da informação sendo um dos idealizadores do Visualg. É com agrado e satisfação que recebi o convite, por três motivos: primeiro, porque apesar de eu ser administradora, o mundo da programação sempre me fascinou; em segundo, por saber que ambos autores estão preocupados em facilitar o aprendizado em programação, ao apresentarem inúmeros exemplos de programas que exploram as denominadas Estruturas de Controle, e em terceiro porque encontraram uma nova forma de ensinar a programar, o que torna o aprendizado mais leve e eficaz. Atuo na gestão de cursos que apresentam em algum momento do currículo a disciplina de programação e tenho observado a barreira que o próprio aluno coloca quando participa da primeira aula de programação, por ser uma disciplina vista como “hard”. Sempre me perguntei o porquê da resistência em aprender programação. Eu encontrei a resposta junto a estes dois autores, quando demonstram que para ensinar programação é preciso deixar para trás métodos tradicionais ainda muito presentes nas Instituições de Ensino Superior (IES). É preciso encontrar um novo sentido de ensinar programação mais dinâmico e interessante apontaram Mário e Antônio. À vista disso, uma das características mais notáveis no trabalho desenvolvido por esses autores é a preocupação de tornar evidente “o COMO FAZER”. A obra composta trabalha, basicamente, com exemplos, esquemas e exercícios dentro do ambiente do Visualg, o que proporciona rápido aprendizado na programação com esta ferramenta. Além disto, os exercícios propostos (e resolvidos ao VIII final do livro) é um fator decisivo para a complementação da formação do programador, sanando as dúvidas ao longo do curso. Tenho a convicção de que esta obra proporcionará a você adentrar no universo da programação com uma visão muito mais clara de que o COMO FAZER em Visualg pode significar tudo! Boa leitura! #Vamos aprender com prazer! Andreia Mileski Zuliani Santos Professorae Gestora de cursos EaD – Maringá-PR. IX NOTA DOS AUTORES Este livro tem como objetivo principal ensinar os programadores a utilizar o Visualg de maneira correta para tirar o melhor proveito no aprendizado de Lógica de Programação com esta ferramenta, nos diversos segmentos da Educação . É um guia que orienta os usuários, tanto nos seus recursos e nas suas funcionalidades básicas, quanto na própria linguagem da ferramenta. Mostra uma maneira melhor e mais didática de como criar, interpretar, editar e testar os algoritmos escritos em português estruturado, sem a necessidade de utilizar qualquer linguagem real, ajustando às suas necessidades. Este livro mostra que este software, além ser prático e objetivo para testar algoritmos, também possui todas as funcionalidades de um bom editor de textos no padrão do Windows®, para criar programas bastante funcionais dentro de um ambiente de desenvolvimento integrado muito fácil de operar e com recursos que podem ser equiparados a outros IDEs mais sofisticados. A obra apresenta o software como sendo uma verdadeira ferramenta no auxílio aos seus usuários, tanto para iniciantes quanto para os mais avançados na área de programação, auxiliando e mostrando várias formas de escrever e testar os seus algoritmos, nos mais variados tipos de problemas resolvidos por computador. Mostra a história da ferramenta, os seus novos recursos, as novas funcionalidades e também os novos comandos e funções da linguagem, além de muitos esquemas explicativos e exercícios prontos e propostos para melhorar a eficiência do aprendizado na criação de programas de computador. Agosto de 2020 X ORGANIZAÇÃO DO LIVRO Capítulo 1 - Lógica de Programação Neste capítulo o livro focaliza a “lógica de programação” iniciando com os conceitos básicos sobre instruções, e em seguida introduz o conceito de “algoritmo” de maneira bem clara e intuitiva e com exemplos básicos de programas simples. Explica como o algoritmo define a própria solução do problema; portanto um assunto fundamental na programação. Mostra a sequência básica de solução dos problemas através da programação: algoritmo-pseudocódigo-código. Discute a importância de se criar a lógica da programação. antes da codificação, frisando que codificar (criar o código-fonte na linguagem de programação) é apenas uma questão de saber a sintaxe da linguagem; mas, não é programar, pois o fundamental é achar a solução mais eficiente e mais eficaz para o problema; isto é, o fundamental é o “Como Fazer”. No final do capítulo são propostos onze exercícios para o usuário exercitar o aprendizado. Capítulo 2 - O Visualg Neste capítulo o software Visualg é apresentado com sua história, seus recursos, seu funcionamento e sua linguagem baseada no portugol. Mostra como esta ferramenta substitui, com vantagens, os antigos “Testes de Mesa”, permitindo ao programador a checagem imediata do algoritmo da solução do problema e o aperfeiçoamento dessa solução. Explica seus comandos e funções, além de apresentar a estrutura básica dos algoritmos escritos no seu editor. Este capítulo mostra os recursos dessa ferramenta, com esquemas e exemplos bem esclarecedores: como editar e executar um programa, como verificar e corrigir os XI possíveis tipos de erros, No final são sugeridos onze exercícios para praticar. Capítulo 3 - Tipos de Dados no Visualg Neste capítulo são apresentados os tipos de dados suportados pelo Visualg, e como declarar elementos num programa. Também são mostrados os operadores e operações permitidos pela ferramenta, com exemplos bem esclarecedores de utilização dos tipos básicos de dados na programação. Ao final do capítulo são propostos doze exercícios para o leitor verificar seu aprendizado. Capítulo 4 - Estruturas de Controle Visualg Neste capítulo são apresentadas as estruturas de controle no Visualg, com as regras e os conceitos aplicados aos operadores lógicos e relacionais. Este capítulo trata dos chamados “comandos compostos”, que permitem desviar o fluxo do programa, como também repetir blocos de instruções. São apresentadas as estruturas de desvios condicionais, desvio selecionado e estruturas de repetição (loops). Explica a importância dessas estruturas, pois, em programas reais a execução das instruções nem sempre são sequenciais. Também enfatiza a importância das indentações nos programas para melhorar a legibilidade e detecção de erros. Doze exercícios são propostos para verificação do aprendizado. Capítulo 5 - Trabalhando com Vetores Este capítulo inicia o estudo dos arrays, apresentando as variáveis compostas que definem estruturas homogêneas, através de vetores. Esses elementos são abordados neste capítulo sob uma ótica bem didática, objetiva e fácil de entender; com esquemas, figuras e exemplos esclarecedores. O assunto é tratado de maneira a aumentar o nível de compreensão do leitor e baixar o nível de dúvidas que muitas vezes aparecem em materiais de XII programação. Com um formato bem didático nos programas, o assunto é explicado nos exemplos de modo bem contundente e sem sofisticações São estudadas aplicações práticas com vetores, além de operações, pesquisas e ordenações. Onze exercícios são propostos para verificar o aprendizado. Capítulo 6 - Trabalhando com Matrizes Este capítulo apresenta as variáveis compostas que definem estruturas homogêneas, através de matrizes. Complementando o assunto “arrays”, este capítulo trata desses elementos, como uma generalização dos vetores, de maneira bem fácil de entender: começando bem tranquilo e aumentando o grau de complexidade bem devagar. Declaração, inicialização, leitura e impressão dos elementos de uma matriz são tratados de maneira bem simples, e enfatizando as características dos arrays. Operações com matrizes e cálculos de determinantes também são assuntos bem discutidos e estudados neste capítulo de maneira bem didática e prática. São propostos onze exercícios para o usuário trabalhar seu aprendizado. Capítulo 7 - Trabalhando com Registros Neste capítulo é apresentado o conceito de registro para dados heterogêneos, ao contrário dos vetores e matrizes que só trabalham com dados homogêneos. Este oitavo capítulo complementa os estudos sobre os tipos de estruturas de dados, como uma extensão dos arrays. O objetivo é mostrar como criar uma estrutura heterogênea em contraste com as estruturas homogêneas representadas pelos arrays. É explicado como criar estruturas - tal como uma tabela num banco de dados - para conter dados de tipos diferentes para uma mesma entidade. Para testar o aprendizado, sete exercícios são propostos ao final do capítulo. XIII Capítulo 8 - Modularização Este capítulo aborda um tema importantíssimo para uma boa programação: a “modularização de um programa”. O objetivo é mostrar que esta técnica é fundamental para que o programa tenha uma melhor legibilidade, além de ter sua manutenção bastante facilitada. Explica como criar as sub-rotinas (procedimentos e funções) nos programas, e como a rotina principal as chama e as executa. Explica com bastante clareza as diferenças entre procedimento e função, quanto ao modo de chamar, executar e sobre o resultado. Também discute os tipos de passagem de parâmetros: “por valor” e “por referência” através de esquemas práticos. Doze exercícios são propostos ao final deste capítulo para o usuário praticar. Anexo - Soluções dos Exercícios Propostos Neste anexo são apresentadas as soluções de todos os exercícios propostos ao longo dos nove capítulos estudados. Bibliografia e Referências Bibliográficas XIV SUMÁRIO Capítulo 1 - Lógica de Programação .............................. 1 1.1 - Introdução ao Capítulo................................................... 1 1.2 - Conceitos básicos de Lógicade Programação .............. 1 1.3 - Algoritmo e Pseudocódigo ............................................ 5 1.3.1 - Algoritmo ......................................................... 5 1.3.2 - Pseudocódigo .................................................... 8 1.4 - Comando e Funções Internos de Pseudocódigo .......... 10 1.5 - Etapas da Solução de um Problema ............................. 11 1.6 - Variáveis e Constantes ................................................. 14 1.6.1 - Identificação de Variáveis .............................. 17 1.6.2 - Escopo de Variáveis ........................................ 20 1.7 - Constantes .................................................................... 21 1.8 - Programação x Codificação ......................................... 22 1.9 - Exercícios Propostos .................................................... 26 Capítulo 2 - O Visualg ................................................... 29 2.1 - Introdução ao Capítulo ................................................ 29 2.2 - Básico sobre Aprendizagem em Programação ............ 29 2.3 - Histórico do Visualg .................................................... 31 2.4 - O Visualg no auxílio à Programação ........................... 34 2.4.1 - A Tela Principal do Visualg ............................. 35 2.4.2 - Características Básicas da Ferramenta .......... 37 2.5 - Pseudocódigo x Visualg ............................................... 39 2.6 - Funcionalidades Práticas do Visualg ........................... 43 2.7 - Itens do Menu Principal .............................................. 44 2.7.1 - Opção “Arquivo” ............................................ 44 2.7.2 - Opção “Editar” ............................................... 48 2.7.3 - Opção “Run” ................................................... 51 2.7.4 - Opção “Exportar” ........................................... 53 2.7.5 - Opção “Manutenção” ...................................... 53 XV 2.7.6 - Opção “Help” ................................................. 59 2.8 - Áreas Funcionais do Visualg ..................................... 64 2.8.1 - Área do Programa ........................................... 65 2.8.2 - Área das Variáveis de Memória ...................... 66 2.8.3 - Área de Visualização dos Resultados ............. 72 2.9 - Funcionalidade dos Botões da Barra de Ícones .......... 73 2.10 - A “Barra de Status” ................................................... 79 2.11 - Palavras Reservadas .................................................. 79 2.12 - Funções, Comandos Internos e Palavras Chaves ....... 81 2.13 - Recursos de Cálculos Numéricos .............................. 84 2.14 - Manipulação de Caracteres ........................................ 85 2.15 - Operações de Entrada e Saída .................................... 88 2.16 - Arredondando Valores de Saída ................................ 93 2.17 - Mensagens de Erros ao Rodar o Programa ............... 95 2.17.1 - Erro de Sintaxe ............................................. 95 2.17.2 - Erro de Computação ................................... 101 2.17.3 - Erro de Lógica (bug) .................................. 103 2.17.4 - Erro de Incompatibilidade de Tipos ........... 105 2.17.5 - Erro de Instrução fora de área .................... 107 2.17.6 - Erro de Falta de Terminadores ................... 112 2.18 - Medindo o Tempo de Processamento .................... 117 2.19 - Depurando Programas ............................................ 118 2.20 - Comentários ............................................................ 120 2.21 - Exercícios Propostos ............................................... 123 Capítulo 3 - Tipos de Dados no Visualg ................... 127 3.1 - Introdução ao Capítulo............................................... 127 3.2 - Tipos Primitivos de Dados ......................................... 127 3.3 - Tipos Complexos ....................................................... 130 3.4 - Os Tipos de Dados Considerados no Visualg ............ 130 3.5 - Declaração de Variáveis no Visualg ........................ 131 3.6 - Operadores e Operações ............................................ 137 3.7 - Exercícios Propostos ................................................. 147 XVI Capítulo 4 - Estruturas de Controle Visualg ............. 151 4.1 - Introdução ao Capítulo ............................................. 151 4.2 - Estruturas de Controle ............................................. 152 4.2.1 - Estruturas de Decisão .................................. 154 4.2.1.1 - Estrutura de Decisão Simples ......... 154 4.2.1.2 - Estrutura de Decisão Composta ...... 158 4.2.2 - Estrutura de Decisão Selecionada ............... 163 4.2.3 - Estruturas de Repetição (loops) ................... 167 4.2.3.1 - Loop Lógico com Teste no Início ... 168 4.2.3.2 - Loop Lógico com Teste no Final .... 175 4.2.3.3 - Loop Numérico ............................... 179 4.3 - Aninhamento de Decisões usando Se's ...................... 184 4.4 - Indentações ................................................................ 185 4.5 - Exercícios Propostos .................................................. 187 Capítulo 5 - Trabalhando com Vetores ...................... 193 5.1 - Introdução ao Capítulo ............................................. 193 5.2 - Conceitos básicos ...................................................... 193 5.3 - Operações Elementares com Vetores ....................... 196 5.4 - Declaração de Vetores no Visualg ............................. 198 5.5 - Atribuição Direta ..................................................... 199 5.6 - Atribuição por Leituras Individualizadas .................. 200 5.7 - Atribuição por Leituras Através de Loop .................. 202 5.8 - Operações Matemáticas Simples com Vetores ......... 206 5.8.1 - Soma de Vetores ........................................... 206 5.8.2 - Subtração de Vetores .................................... 208 5.9 - Aplicações de Vetores .............................................. 211 5.9.1 - Ordenação .................................................... 211 5.9.2 - Pesquisas ...................................................... 215 5.9.2.1 - Pesquisa Sequencial ...................... 216 5.9.2.2 - Pesquisa Binária ............................ 219 5.9.3 - Verificando Maior e Menor elemento ........ 222 5.9.4 - Soma e Média dos elementos ...................... 224 XVII 5.9.5 - Invertendo a Ordem dos elementos ............ 227 5.9.6 - Verificando Característica de elemento ....... 229 5.9.6.1 - Verificando elemento Múltiplo......229 5.9.6.2 - Verificando elemento Divisor ...... 231 5.9.6.3 - Verificando Paridade e Posição . . 233 5.9.7 - Incluindo/Excluindo/Alterando elemento ..235 5.9.7.1- Incluindo um novo elemento ........ 235 5.9.7.2 - Excluindo um elemento .............. 238 5.9.7.3 - Alterando o valor do elemento ..... 240 5.10 - Erros na utilização de Vetores ................................. 245 5.11 - Exercícios Propostos ................................................ 247 Capítulo 6 - Trabalhando com Matrizes .................... 253 6.1 - Introdução ao Capítulo .............................................. 253 6.2 - Conceitos Básicos .....................................................253 6.3 - Declaração de Matrizes no Visualg .......................... 256 6.4 - Leitura e Escrita de uma Matriz ................................ 258 6.5 - Operações com Matrizes ........................................... 261 6.5.1 - Adição de Matrizes ...................................... 261 6.5.2 - Subtração de Matrizes .................................. 265 6.5.3 - Multiplicação de Matriz por Escalar ............ 268 6.5.4 - Multiplicação de Matriz por Vetor .............. 271 6.5.5 - Multiplicação de Matriz por Matriz ............. 273 6.6 - Determinantes de Matrizes ....................................... 278 6.6.1 - Determinante de Matrizes de Ordem 2 ......... 278 6.6.2 - Determinante de Matrizes de Ordem 3 ........ 280 6.6.3 - Determinante de Matrizes de Ordem > 3 ..... 282 6.7 - Matriz Transposta ..................................................... 286 6.8 - Matriz Identidade ...................................................... 288 6.9 - Elementos das Diagonais de uma Matriz ................... 290 6.10 - Exercícios Propostos ................................................ 298 XVIII Capítulo 7 - Trabalhando com Registros ................... 303 7.1 - Introdução ao Capítulo .............................................. 303 7.2 - Conceitos Básicos ..................................................... 303 7.3 - Manipulação de Registros ......................................... 305 7.4 - Conjunto de Registros ............................................... 309 7.5 - Leitura de um Conjunto de Registros ........................ 311 7.6 - Pesquisa em Conjunto de Registros .......................... 318 7.7 - Exercícios Propostos ................................................. 326 Capítulo 8 - Modularização ......................................... 327 8.1 - Introdução ao Capítulo .............................................. 327 8.2 - Conceitos Básicos ..................................................... 328 8.3 - Dividir para Unificar ................................................. 329 8.4 - Programação Modular ............................................... 329 8.5 - Sub-rotinas ................................................................ 333 8.5.1 - Procedimentos ............................................... 334 8.5.2 - Funções ......................................................... 336 8.6 - Parâmetros ................................................................ 342 8.6.1 - Passagem de Parâmetros ............................... 344 8.6.1.1 - Passagem Por Valor ........................ 349 8.6.1.2 - Passagem Por referência ................. 350 8.7 - Programas com Sub-rotinas ...................................... 354 8.8 - Acesso a Arquivos .................................................... 369 8.9 - Exercícios Propostos ................................................. 373 Anexo - Solução dos Exercícios Propostos ................. 379 Capítulo 1 ........................................................................... 379 Capítulo 2 ........................................................................... 383 Capítulo 3 ........................................................................... 388 Capítulo 4 ........................................................................... 395 Capítulo 5 ........................................................................... 405 Capítulo 6 ........................................................................... 415 XIX Capítulo 7 ........................................................................... 424 Capítulo 8 ........................................................................... 428 Bibliografia e Referências Bibliográficas ................... 437 1 Capítulo 1 - Lógica de Programação 1.1 - Introdução ao Capítulo O processo de criação de um programa passa, necessariamente, pela análise do problema a ser resolvido, e em seguida sua solução deve ser criada com uma sistemática que possa resolver o problema. Essa sistemática é baseada numa lógica que deve implementar uma solução. E, embora uma linguagem de programação seja importante para automatizar a solução do problema, o programa tem que ser elaborado, antes, de modo que essa solução seja a melhor possível. Ao final, a tradução do código-fonte numa linguagem de programação deve ser “introduzida” no computador para dar a informação desejado ao usuário. A etapa que antecede a criação do código-fonte em linguagem de programação, é o que implementa a solução; por isto, é importante frisar que codificar (criar o código-fonte na linguagem de programação) é apenas uma questão de saber a sintaxe da linguagem; mas, isto não cria a solução do problema, pois o fundamental é achar a solução mais eficiente e mais eficaz, 1.2 - Conceitos Básicos de Lógica de Programação Lógica de Programação pode ser definida como uma “técnica de desenvolver sequências de ações para atingir um objetivo bem determinado”. Essas sequências são adaptadas para uma linguagem de computador a fim de produzir o programa. Atualmente toda as comunicações dos usuários com os computadores são feitas através de bytes, que trazem no seu contexto as ordens para que o computador resolva o problema 2 apresentado pelo usuário, na forma de um programa. Na prática, o problema é analisado, estudado e manipulado por um outro personagem no ambiente da computação: o programador. O programador é quem cria e escreve as ordens que serão dadas ao computador para que apresente uma solução para o problema. A figura 1.1 mostra um esquema de como fica a interação: usuário- programador-computador. Usuário Programador Nível computacional Figura 1.1 - Trazendo o problema para o nível computacional O usuário apresenta o problema ao programador, que o refina e traduz para o computador executar as ordens embutidas nesses refinamentos. E para que essas ordens sejam executadas corretamente, elas devem ser escritas como texto, e numa sequência lógica, tal que a solução apresentada pelo computador seja correta e satisfaça o usuário. Essas ordens são traduzidas (codificadas) num texto chamado de código-fonte. Existem várias definições para “Lógica”, além daquela mencionada no início deste item, mas, de um modo geral, é possível resumir essas definições em uma só: “Logica é a forma ordenada do pensamento”. Do ponto de vista prático, pode-se dizer que lógica de programação é a forma ordenada de escrever Problema ??? 3 as ações para resolver um problema. Para os programadores, é muito importante saber distinguir três definições: • Linguagem de programação é um conjunto de regras que definem como os comandos e funções devem se comportar dentro dos programas de computador. • Programas são as ordens dadas ao computador para que execute as tarefas exigidas no processamento, a partir de um conjunto de comandos e funções, seguindo uma sequência estabelecida. • Algoritmo é o conjunto de instruções na forma de texto descritivo, usando um método de montagem conforme a lógica, para resolver o problema, Os métodos de ensino de disciplinas de “Lógica de Programação” têm nomes variados, mas com o mesmo propósito, como: • Técnicas de Programação. • Algoritmos. • Lógica de Programação. Essas disciplinas apresentam em sua ementa vários métodos de ensino da lógica; entre os quais podem ser destacados: 1) Método do Algoritmo Descritivo: que literalmente descreve passo a passo cada etapa de um processo da solução do problema. 2) Métododos Diagramas Gráficos (fluxograma e diagramas de blocos): onde, por meio de desenhos gráficos é descrito o fluxo do processo, mostrando como funciona o raciocínio lógico e as estruturas de controle. 3) Método da Pseudolinguagem (ou Pseudocódigo), que pode ser apresentado através de uma pseudolinguagem de programação, como o portugol (português estruturado). 4 O portugol (que é a junção de Português+algol) é uma pseudolinguagem de programação; ou seja, é um método para ensinar lógica de programação, muito importante para os iniciantes no assunto “programação de computadores”. Ele permite ao aluno entender o que cada comando (ordem) significa, antes mesmo de saber como será o programa real; por isto é um método muito poderoso. Um algoritmo não é um programa, mas ele exprime a lógica do processo para solucionar o problema; o aluno deve construir um algoritmo antes de codificar em linguagem de programação real. Todas as linguagens de programação têm seus códigos-fonte escritos em Inglês; isto por que esse idioma é o que mais se adapta ao ambiente computacional, devido ao seu poder de compactação dos termos. ENTRETANTO, é preciso distinguir BEM o termo “programação” do termo “codificação”!!! “Programação é o ato intelectual de escrever a solução do programa em função do algoritmo (solução descritiva do problema), e que pode ser aprimorada com uma solução mais formal (pseudocódigo).” “Codificação é o ato técnico de converter a solução escrita pseudocódigo em texto (o chamado código-fonte), baseado na sintaxe da linguagem escolhida”. Embora, na prática possa ser dito “programar em Java”, na verdade, o correto seria: “codificar em Java”, pois a programação para resolver o problema é feita através da seguinte sequência: 1. Análise do problema; 2. Criação do algoritmo para resolver o problema, em nível informal; 3. Criação do pseudocódigo para formalizar a solução em nível mais técnico; 4. Codificação do programa. 5 É esta a sequência - em uma explicação bem simples - que deve ser executada para resolver um problema num ambiente computacional. 1.3 - Algoritmo e Pseudocódigo Embora muitos autores tratem os dois termos como sendo a mesma coisa, existe uma diferença que pode ser bem marcante entre algoritmo e pseudocódigo. 1.3.1 - Algoritmo Existem muitas definições para “algoritmo”; uma delas é dada da seguinte forma: “Algoritmo é uma sequência de passos factíveis de execução, com início e fim, que quando executados produzem a solução de um problema”, Leite (2006, p. 54). Um exemplo clássico de algoritmo é o famoso problema “Trocar uma lâmpada”, resumido nos seguintes passos na descrição a seguir... Início 1 - Pegue uma lâmpada nova. 2 - Teste a lâmpada. 3 - Se lâmpada passar no teste Passo 4; Senão Passo 1 4 - Pegue uma escada. 5 - Posicione a escada no local correto. 6 - Suba os degraus da escada. 7 - Retire a lâmpada queimada. 8 - Coloque a nova lâmpada. 9 - Desça a escada. 11 - Descarte adequadamente a lâmpada queimada. Fim 6 Embora os termos Início e Fim não sejam obrigatórios, é importante colocá-los para frisar que um algoritmo sempre deve ter um início e um fim bem determinados, como citado por Leite (2006, p. 54). Pelo esquema da solução do problema “Trocar uma lâmpada”, pode ser observado que as ações dadas a cada passo sempre devem estar colocadas em verbos no modo Imperativo Afirmativo: Pegue, Teste, Suba, etc, para dar sentido de ordenar, exigir! Então, pelo que foi visto, pode-se afirmar que: “Algoritmo é uma descrição textual e informal da solução do problema”. Em outras palavras, o algoritmo é a própria solução do problema; se o algoritmo estiver correto, o problema está resolvido. Simples, assim! ❖ Exemplo 1.1 - Fazer um algoritmo para verificar se um número A é divisível por um número B. Início 1 - Leia o número A. 2 - Leia o número B. 3 - Se B diferente de 0, Então divida A por B e siga em frente, Senão vá ao Passo 5. 4 - Mostre o resultado. 5 - Pare. Fim 7 A solução do Exemplo 1.1 já apresenta uma ação que é muito comum (fundamental) na lógica de programação: Leia. Ela ordena ao processador a “pegar” o valor digitado pelo usuário e armazená-lo na memória RAM, definindo o que se chama de entrada de dados através de leitura. A ação (comando) Se define uma ordem condicional, analisando uma situação que pode ter um dos dois valores lógicos possíveis: Verdadeiro ou Falso. Então, se o número B for um número diferente de 0 (a Matemática não define divisão por 0), a operação será efetuada e o resultado mostrado, no passo 4;. Senão (caso contrário), se B for igual a zero, o passo 4 não será executado e o fluxo do algoritmo será desviado para o passo 5 (último passo do algoritmo), encerrando a solução. Nota: As ações (comandos) Se, Então e Senão são empregados em “situações” em que haja necessidade de se tomar uma decisão; são termos que definem comandos condicionais dentro num algoritmo. Estes serão vistas com mais detalhes no Capítulo 4. ❖ Exemplo 1.2 - Criar um algoritmo para verificar se um determinado número é par ou ímpar. 8 Início 1 - Leia o número. 2 - Divida o número por 2. 3 - Se o resto da divisão for 0, Então siga em frente, Senão vá para o Passo 6. 4 - Escreva “O número é par”. 5 - Vá para o passo 7. 6 - Escreva “O número é ímpar” 7 - Pare Fim 1.3.2 - Pseudocódigo O pseudocódigo é o algoritmo escrito numa forma mais formal, mais técnica, utilizando as ordens convertidas em comandos mais rigorosos. Deste modo, as ações passam a ter um carácter mais computacional, o que torna a solução do problema menos descritiva e mais compacta. O esquema abaixo mostra o layout de um pseudocódigo, que aqui será adotado: Programa "nome-do-programa" Declare <lista de variáveis do tipo 1> Declare <lista de variáveis do tipo 2> ... Início Aqui são escritas as instruções do algoritmo Instrução1 Instrução2 Instrução3 ... FimPrograma 9 Observe como ficam as soluções dos dois exemplos anteriores em pseudocódigo. Programa "Divide" Declare A, B, C: real Início Leia(A) Leia(B) Se(B<>0) Então C <- A/b FimSe EscrevaLn(C) FimPrograma Note que as soluções em pseudocódigo ficaram bem mais compactas, e com as ordens dadas de maneira mais técnica. Por exemplo, o comando FimSe para indicar a finalização de uma decisão, e Escreva para mostrar o resultado. Programa "VerificaNumero" Declare A, R: inteiro Início Leia(A) R <- Resto(A/2) //resto da divisão de A por 2 Se(R=0) Então Escreva("O número é par") Senão Escreva("O número é impar") FimSe FimPrograma 10 1.4 - Comandos e Funções Internos de Pseudocódigo Nos programas escritos em pseudocódigo, às vezes, é necessário empregar comandos e/ou funções para agilizar o processo, como, por exemplo, “pegar a parte inteira de uma divisão entre dois números”. Se fosse utilizar uma descrição formal, isto seria muito complicado e ficaria mais ou menos assim: ... Leia(N1) Leia(N2) Se(N2<>0) Então X <- Pega parte inteira da divisão de N1 por N2 Escreva(X) FimSe ... Observe que a linha de código onde o resultado da divisão é atribuído à variável X ficou muito estranha; parecendo uma linha de algoritmo e não de pseudocódigo. A linha de instrução em pseudocódigo ficaria assim: X <- Int(N1/N2), muito mais racional. Por isto, existem algumas ordens (comandos e funções) internas, utilizadas para melhorar a legibilidade do programa. A tabela 1.1 mostra alguns comandos e funções que são utilizados nos pseudocódigos. Ordem Tipo O que Faz Declare v1, v2, v3 Comando Cria variáveisde memória. Escreva(x) Comando Exibe o conteúdo da variável x na tela e fica na mesma linha. EscrevaLn(x) Comando Exibe o conteúdo da variável x na tela e salta para nova linha. EscrevaLn("") Comando Apenas salta uma linha. 11 Leia(x) Comando Lê o conteúdo da variável x para a memória. Pare(n) Comando Suspende o processamento por n milissegundos. LimpaTela Comando Limpa a tela do monitor de vídeo. Abandone Comando Sai do loop incondicionalmente. Int(A/B) Função Retorna a parte inteira da divisão de A por B. Resto(A/ B) Função Retorna o resto inteiro da divisão de A por B. RaizQ(x) Função Retorna raiz quadrada de um número x não negativo. Abs(x) Função Retorna o valor positivo de um número x. Tamanho("s") Função Retorna o número de caracteres de uma string "s". Tabela 1.1 - Alguns Comandos e Funções utilizados em pseudocódigos 1.5 - Etapas da solução de um Problema Nas situações reais a solução de um problema pode ser mais complexa, exigindo técnicas de análise de sistemas e alguma complexidade. Mas, de qualquer forma, a sequência básica para resolver um problema através de um programa de computador, pode ser resumida no esquema da figura 1.2. Problema Algoritmo Pseudocódigo Código Figura 1.2 - Esquema básico da criação de um programa 12 ❖ Exemplo 1.3 - Ler dois números, fazer a troca de valores entre eles, e depois mostrar esses dois números com seus valores trocados. Algoritmo: Início 1 - Leia o primeiro número 2 - Leia o segundo número 3 - Troque os valores entre os dois números 4 - Mostre os dois números com seus novos valores Fim Pseudocódigo: Programa "Trocas" //Lê dois números, faz a troca entre eles. //Autor: Mário Leite //----------------------------------------------------- Declare A, B, X: inteiro Início Escreva("Digite o primeiro número A: ") Leia(A) Escreva("Digite o segundo número B: ") Leia(B) X A //preserva o valor do primeiro número A B //faz o primeiro número igual ao segundo B X //faz o segundo número receber o preservado EscrevaLn("") //salta linha EscrevaLn("Valor final de A: ", A) EscrevaLn("Valor final de B: ", B) FimPrograma 13 Observe que, embora o algoritmo não mencione esse detalhe, no pseudocódigo a lógica mandou preservar o valor do primeiro número para, só no final, colocá-lo no segundo número; caso isto não fosse feito, os dois ficariam com um mesmo valor e a troca não seria efetivamente conseguida. MAS... como saber se os resultados estão corretos, ANTES DA CODIFICAÇÃO!!?? Para testar a correção de um programa são utilizados os chamados “Testadores de Algoritmos”, ou “Interpretadores de Algoritmos”. E um desses, talvez o mais famoso e mais popular é o Visualg (Visualizador de Algoritmos) que será visto no próximo capítulo. Essa ferramenta - uma pseudolinguagem de programação - é muito importante para os iniciantes no assunto, pois permite testar o programa, antes mesmo de codificá-lo numa linguagem real e mais potente; pois o que interessa é verificar se o algoritmo está correto. E, embora o Visualg não seja uma linguagem formal de programação, ele é muito importante no aprendizado de “Lógica de Programação”, pois permite ao programador ter uma visão mais clara da solução já em nível de pseudocódigo. Esta ferramenta pode ser classificada como “um interpretador de algoritmos”, que facilita em muito o aprendizado, com um editor onde é escrito o pseudocódigo do programa, em portugol, e é distribuída pela Internet, gratuitamente. Mas, qual é, então, a diferença entre Visualg e o Basic, por exemplo?! A diferença básica está nos termos empregados para uma mesma instrução; por exemplo, para exibir o valor da variável X no monitor de vídeo: em Visualg é Escreva(X) e no Basic é Print(X); em Visualg utiliza-se o idioma Português adaptado, e nas outras linguagens é sempre no idioma Inglês. De tudo que foi visto até agora, pode ser concluído que só depois de passar pelo estudo do algoritmo/pseudocódigo e um interpretador de algoritmos é que se deve adotar uma primeira 14 linguagem de programação real, que poderá ser o Pascal, com qualquer um dos compiladores oferecidos no mercado; entre eles o Pascal Zim! que é distribuído gratuitamente na Internet. Portanto, codificar um programa numa linguagem real SEM ANTES passar pela sua lógica da solução, não é uma boa atitude de programação. 1.6 - Variáveis e Constantes Nos exemplos anteriores de programas em pseudocódigo, foram empregadas muitas linhas de códigos com instruções em que uma letra (ou conjunto de letras e números) foi colocado à esquerda do símbolo como por exemplo, no programa “Trocas”, Aux A A B B Aux Aux, A1 e B são as “VARIÁVEIS” utilizadas para manipulação/armazenamento dos dados que a lógica do programa exigiu para resolver o problema proposto. Mas... o que são variáveis; para que servem?! A memória RAM de um computador pode ser comparada a um armário com várias gavetas, onde cada gaveta representa um local de armazenamento. Cada local desses é um endereço de memória, com uma identificação própria denominada endereço real e que só a CPU pode” acessá-lo diretamente. Então, como o programador não conhece o endereço real, ele tem que acessá-lo simbolicamente através do conceito de “variável de memória”. De acordo com Leite (2006) “Variáveis de memória, ou simplesmente variáveis, são endereços simbólicos da memória principal definidos pelo programador, onde são armazenados temporariamente valores para serem processados, ou resultado de algum processamento”. Quer dizer: variável pode ser 15 considerada uma unidade de armazenamento em nível de programação; e é importante saber que esses locais” são voláteis; os valores ali alocados podem ser alterados e/ou descartados depois de certo tempo, dependendo das circunstâncias. Por isto, o resultado de um processamento, que originalmente estava em uma variável, deve ser salvo de forma definitiva em uma mídia: fita, disco, pen drive etc; senão o valor será perdido definitivamente. ❖ Exemplo 1.4 - Criar um programa para obter o salário líquido de um funcionário a partir de seu salário bruto, após descontar a contribuição para o INSS: O Algoritmo poderia ser assim: 1 - Entre com o valor do Salário Bruto 2 - Entre com o valor do percentual de desconto 3 - Calcule o Desconto: DC = SB*(PD/100) 4 - Calcule o Salário Líquido: SL = SB - DC 5 - Mostre o resultado armazenado em SL Note que cinco passos foram usados para calcular o salário líquido de apenas um empregado. Na verdade, uma empresa - mesmo sendo uma microempresa - não possui apenas um empregado; assim o processamento deve ser usado para todos eles. Deste modo, a cada processamento os valores de SB, PD, DC e SL se alteram; e se não forem salvos o valor de cada SL em locais permanentes, ao final do processamento de todos os funcionários da empresa só restará o valor do salário líquido do último empregado. Os termos SB e PD são variáveis utilizadas para armazenar os dados de entrada; DC é uma variável que armazena o valor calculado para o desconto, e SL uma variável onde é guardado o resultado do salário líquido de um funcionário; 16 mas todos eles são locais simbólicos da memória principal. A figura 1.3 apresenta um esquema desta situação. Nota: SB, PD, DC e SL são os nomes das variáveis empregadas no problema apresentado no Exemplo 1.4. Entretanto, conforme será explicado mais adiante, esses nomes deveriam ser mais explícitos para traduzir melhor o que cada um deles significa no contexto. São como “caixas” rotuladas para guardar algo que o programador deseja. variável SL variável PD 3600 104000 400 variável DC variável SB Figura 1.3 - Armazenamento de valores em variáveis de memória 17 Além do endereço e valor, uma variável também necessita ter um tipo de dado que qualifique o valor armazenado (tipos de dados serão vistos no Capítulo 3); em resumo: uma variável deve ser definida em função das seguintes características: • Identificador ==> endereço (nome simbólico na memória). • Valor ==> quantidade armazenada no momento. • Tipo de Dado ==> qualidade do valor armazenado. • Escopo ==> visibilidade (abrangência) dentro do programa. Programa "ControleSalario" //Controla o salário de um empregado //Autor: Mário Leite ----------------------------------------------------- Declare SB, SL, PD, DC: real Início Escreva("Digite o valor do salário bruto: ") Leia(SB) Escreva("Digite o percentual do desconto: ") Leia(PD) DC <- SB*(PD/100) SL <- SB - DC EscrevaLn("Salário líquido: ", SL) FimPrograma 1.6.1 - Identificação de Variáveis Nas literaturas sobre programação, dependendo até da linguagem, são sugeridas algumas regras para criar identificadores de uma variável; entretanto, a regra mais importante é esta: “o 18 identificador de uma variável deve traduzir o significado do que ela armazena”. Um exemplo seria o de identificar uma variável que armazenasse o valor da devolução do imposto de renda do ano de 2020. Neste caso poder-se-ia optar por qualquer um dos nomes a seguir: • IR • DevIR • DevIR20 • Devolucao_do_Imposto_de_Renda_de_2020 Qual destes identificadores você utilizaria? O primeiro parece muito curto; o segundo parece mais prático que o primeiro, pois sugere uma devolução com o emprego do prefixo Dev. O terceiro é mais explícito, pois indica que a devolução é do ano de 2020. E o quarto identificador, também poderia ser utilizado? Sim poderia; mas não deveria, pois apesar de ser o mais explícito de todos é muito longo! Então, entre as quatro opções apresentadas o identificador que mais se aproxima do ideal seria o terceiro: DevIR20, pois além de traduzir bem o que é armazenado na memória não é muito curto e nem demasiadamente longo. De qualquer forma, a escolha do nome (identificador) de uma variável vai depender muito do bom senso do programador; não existe uma regra rígida para isto, apenas que ele explique o que vai ser armazenado naquele endereço, porém sem exageros; mas, existem algumas regras básicas: 1. Deve começar sempre com uma letra (A-Z, a-z) ou com underline (_). 2. Não pode ser utilizado caractere especial ou pontuação (? > < @ &*, . # ; -). 3. Não pode haver espaços em branco entre os caracteres. 4. O tamanho deve ser de no máximo 255 caracteres[5]. 19 5. Não podem ser utilizadas letras acentuadas (á ó ê ã,) e nem o cedilha (ç). 6. Não pode utilizar palavras reservadas de linguagens de programação[6] ou de pseudocódigo. 7. Devem ser evitadas variáveis com identificadores contendo as letras “I”, e “O” pois, podem ser confundidas com os dígitos 1 e 0, respecivamente. Nota: Embora existam linguagens de programação que tratam de modo sensível os identificadores de variáveis (por exemplo, no C DevIr20 é diferente de DeveIR20) em pseudocódigo não existe case sensitive em relação a nome de variáveis. Portanto aqui DevIr20, DEVIR20, devIR20, Devir20, devir20, DeViR20, etc, são uma mesma variável. Identificador O que poderia significar DevIR20 Devolução do Imposto de Renda de 2020. TotAluFem Total de alunos do sexo feminino. TotGeral Total geral. Soma Soma de alguns valores num programa. Fat Fatorial de um número. Nota1Alu Primeira nota de um aluno. Nota1Qui Primeira nota em Química. NomeCli Nome de cliente. Num Um número lido. EndCli Endereço de cliente. ArqCli Arquivo de clientes. TotVendas Total de vendas. TotVendDez Total de vendas em Dezembro. TotVend20 Total de vendas em 2020. Tabela 1.2 - Exemplos de identificadores válidos 20 Identificador O que deveria significar Por que não é válido 20DevIR Devolução do Imposto de Renda de 2020. Começa com dígito Tot AluFem Total de alunos do sexo feminino. Tem espaço entre as letras t e A. Tot&Geral Total geral. Tem caractere especial (&). Valor$ Valor monetário. Tem caractere especial ($). PreçoUnit Preço unitário de um produto Possui ç no identificador. 1aNotaAlu Primeira nota. Possui letra sobrescrita. maçã Nome de fruta. Possui letra acentuada e cedilha. Next Próximo Comando da linguagem VB. Read Ler Comando da linguagem Pascal Resto Resto de uma divisão Função em pseudocódigo. Var Valor de uma variável Palavra reservada de linguagem. int Inteiro Tipo de dado da linguagem C. EndereçoCli Endereço de um cliente. Possui ç no identificador. Tabela 1.3 - Exemplos de identificadores inválidos 1.6.2 - Escopos de Variáveis Além do identificador, do tipo de dado e do valor contido as variáveis possuem também escopo, que quer dizer “visibilidade” ou “abrangência” dentro de um programa. O escopo define em que partes do programa uma variável poderá ser acessada ou referenciada. Existem dois tipos de escopos: local e global. Variáveis locais só podem ser acessadas dentro da rotina que as definiram, ao passo que as globais podem ser acessadas em qualquer parte do programa. Para programas compostos de módulos, ou subprogramas, cada subprograma desses poderá ter 21 suas próprias variáveis locais que poderão ser acessadas somente dentro de cada um deles (este assunto será visto no Capítulo 8). 1.7 - Constantes O valor de PI - razão entre o comprimento de uma circunferência e seu diâmetro - é, normalmente, usado como 3.14 (com apenas duas casas decimais). Entretanto, acredite: o PI já foi calculado com oito quatrilhões de casas decimais! Esta constante é mostrada abaixo com cinquenta decimais... 3.14159265358979323846264338327950288419716939937511 De qualquer forma, as constantes também representam, simbolicamente, endereços da memória RAM; entretanto, ao contrário de uma variável, o valor armazenado em uma constante não pode ser alterado durante o processamento. Isto quer dizer que ao declarar uma constante deve-se definir imediatamente seu valor, o qual permanecerá inalterável durante todo o processamento do programa. Quanto às outras características (identificador, tipo de dado e escopo) elas funcionam de forma semelhante às variáveis. Na prática de programação, embora não seja uma regra, os identificadores das constantes criadas são, normalmente, indicados com letras em caixa alta; todas maiúsculas; eis alguns exemplos: • PI • TECLA • GRAVIDADE • DESCONTO • TAXA • FATOR Nos programas em que determinado valor permanece constante, é sempre mais interessante empregar constante, e com escopo global. Por exemplo, para a constante PI: Const PI=3.141592653589793 //ANTES das declarações das variáveis 22 Nota: Sempre que possível deve-se empregar variáveis locais nos programas. As variáveis globais, devido à exposição em todo o programa, estão sujeitas a interferências e acessos externos indevidos, o que pode comprometer todo o código. Além disto, em algumas linguagens de programação, as variáveis globais fragmentam o código executável, tornando-o maior e além do necessário, fazendo com que haja perda de performance. 1.8 - Programação x Codificação Existem dezenas de linguagens de programação nas quais um mesmo programa pode ser codificado (ou, implementado, como preferem alguns). Mas, não se deve confundir Programação com Codificação; rigorosamente falando, o termo “Linguagem de Programação” deveria ser alterado para “Linguagem de Codificação”. Programar é criar uma rotina, seguindo uma lógica, para executar um trabalho qualquer. Esta definição, certamentelevará o leitor a pensar que programar é criar uma receita de bolo; e é isto mesmo! Afinal, escrever um programa nada mais é do que criar uma receita para resolver um problema qualquer. O trabalho da LP é apenas a tradução das ações da rotina a serem implementadas, em códigos na sintaxe exigida pela linguagem; é claro que a Codificação é importante, mas não é a parte mais fundamental na criação do programa; pois, na hora da codificação o problema já deve estar resolvido. 23 ❖ Exemplo 1.5 - Ler dois números, inteiros e positivos e criar um pseudocódigo para calcular e mostrar o MDC (Máximo Divisor Comum) desses dois números. Embora seja um assunto bem popular e ensinado no Curso Fundamental, o MDC (maior número inteiro positivo que divide, simultaneamente, dois ou mais números) é muito importante em estudos de Matemática Superior, como, por exemplo, na proteção de dados através da criptografia de chave assimétrica, em matrizes, e até na computação quântica (algoritmo de Shor). Assim, baseando na sua definição formal, existem várias maneiras de calcular o MDC; vamos descrever duas, considerando os números 36 e 90. 1 - Através dos divisores dos dois números, na seguinte sequência: Passo 1 - Leia o primeiro número (36) Passo 2 - Leia o segundo número (90) Passo 3 - Mostre divisores de 36 (1, 2, 3, 4, 6, 9, 12,18 36) Passo 4 -Mostre divisores de 90(1,2,3,5,6,9,10,15,18,30,45 90) Passo 5 - Verifique qual o maior divisor comum a 36 e 90 (18) Passo 6 - Mostre o MDC 2 - Através do “Algoritmo De Euclides” [4] Passo 1 - Leia o primeiro número Passo 2 - Leia o segundo número Passo 3 - Divida o maior número pelo menor Passo 4 - Se(resto da divisão for 0) Então MDC é o menor; Vá para o Passo 12, Senão: Siga em frente Passo 5 - Divida o dividendo pelo resto Passo 6 - Se(resto da divisão for 0) Então Vá para o Passo 11 Senão: Siga em frente Passo 7 - Considere o resto como o novo dividendo Passo 8 - Considere o divisor como o resto anterior 24 Passo 9 - Divida o dividendo pelo divisor do resto anterior Passo 10 - Volte ao Passo 4 Passo 11 - Considere o penúltimo resto como o MDC Passo 12 - Mostre o MDC Então, para o caso de calcular o MDC(90,36) o esquema abaixo mostra como seria a aplicação do “Algoritmo de Euclides” 90 36 resto 18 Em seguida o resto 18 é transportado para o lado direito de 36 e divide-se o 36 por 18, posicionando o novo resto (0) abaixo do 18: 90 36 18 Resto 18 0 Repete-se este procedimento até encontrar o resto 0 (zero); o penúltimo resto obtido (anterior ao primeiro resto 0) é o MDC dos dois números dados. Baseado na segunda forma de calcular o MDC, através no “Algoritmo de Euclides” descrito acima, a solução do Exemplo 1.5 é dada pelo pseudocódigo a seguir, e a codificação poderia ser feita em qualquer das inúmeras linguagens e/ou ambientes de programação, mas, a base SEMPRE é o algoritmo/pseudocódigo que, realmente, é a solução do problema. 25 Programa "CalculaMDC" //Calcula o MDC de dois números:“Algoritmo de Euclides”. //Em Pseudocódigo. //Autor: Mário Leite. //---------------------------------------------------- Declare Num1, Num2, N1, N2, Aux, MDC: inteiro Início {Inicializações convenientes para entrar no loop de Num1 -1 Num2 -1 Enquanto ((Num1<=0) ou (Num2<=0)) Faça Escreva("Entre com o primeiro número: ") Leia(Num1) Escreva ("Entre com o segundo número: ") Leia(Num2) FimEnquanto //fim do loop de leitura dos números EscrevaLn("") //salta uma linha N1 Num1 N2 Num2 {Calcula o MDC com o "Algoritmo de Euclides"} FimEnquanto (N2<>0) Faça Aux N1 N1 N2 N2 (Resto(Aux/N2) FimEnquanto //fim do loop de cálculo do MDC MDC N1 EscrevaLn("MDC(",Num1,",",Num2,")"," = ", MDC) FimPrograma A implementação (codificação) do problema “Calcular o MDC de dois números” pode ser feita em várias linguagens de programação: compiladas ou interpretadas, mas seguindo uma lógica de programação para alcançar esse objetivo, baseada num único algoritmo/pseudocódigo. E, embora fossem considerados dois números bem determinados (90 e 36), poderia, também, 26 solicitar as entradas para quaisquer dois números inteiros. Mas, o importante é frisar que, em princípio, não importa em qual linguagem de programação o programa será codificado: o MAIS IMPORTANTE é saber qual algoritmo a ser seguido para obter o resultado esperado. 1.9 - Exercícios Propostos 1 - Explique, com suas próprias palavras, o que é “Lógica de Programação”. 2 - Por que não se deve partir direto para a codificação de um programa sem, antes, criar o algoritmo/pseudocódigo. 3 - Qual é a vantagem de se declarar um endereço de memória RAM como constante, em vez de variável? Dê um exemplo. 4 - Qual é a vantagem de fazer o pseudocódigo depois do algoritmo de um programa?. 5 - Explique por que o conceito de variável é fundamental na programação, 6 - Se você tivesse que nomear uma variável para armazenar o nome do Campeonato Mundial de Futebol da FIFA para 2024, qual dos identificadores é o mais apropriado? A ( ) CampeonatoMundialDeFutebol2024 B ( ) CampeonatoMundialFIFA2024 C ( ) FIFA2024 D ( ) FutebolFIFA2024 E ( ) CampeonatoFIFA2024 7 - Explique, com um exemplo, a diferença entre Algoritmo e Pseudocódigo. 27 8 - De acordo com as teorias de Mark A. Changizi[7], se os vulcanianos - planeta natal do Dr. Spock - tiverem três dedos em cada mão (tal como a criaturinha do filme ET - O Extraterrestre), então, provavelmente, o sistema de numeração deles seria o da base hexa (base 6). Considerando essa teoria, marque nas alternativas abaixo, a que aparece um número (representado na Base Decimal) que jamais poderia ser escrito na Base Vulcaniana, considerando que a Matemática vale para todo o Universo. Explique, o porquê da sua resposta. A ( ) 31234 B ( ) 4356 C ( ) 234100 D ( ) -1 E ( ) 0 9 - Sabemos que para realizar uma tarefa é necessário executar alguns passos (poucos ou muitos, dependendo da solução adotada). Suponha que um cliente deseja que você resolva um problema para ele, através de um programa; e, considerando o esquema abaixo, qual dos três caminhos você escolheria para solucionar esse problema? A ( ) O caminho de cima. B ( ) O caminho do meio. C ( ) O caminho de baixo. D ( ) Aquele que produzisse uma solução mais eficaz. E ( ) Qualquer um serviria. 28 10 - Explique porque a instrução X = X + 1 escrita na linguagem C, por exemplo, não pode ser interpretada como uma equação matemática. 11 - Crie um algoritmo para verificar se um determinando número é primo, ou não. 29 Capítulo 2 - O Visualg 2.1 - Introdução ao Capítulo O Visualg é um ambiente de software onde é possível editar, interpretar e executar um programa de computador escrito em pseudocódigo, numa linguagem bem próxima ao Português. Foi desenvolvida originalmente pelo professor Cláudio Morgado de Souza[8] até a versão 2.5, e atualmente gerido pelo professor Antonio Carlos Nicolodi[9] a partir da versão 3.0 com novo layout e novos recursos. É um dos mais populares interpretadores de algoritmos, e que não depende de bibliotecas sofisticadas como DLLs, OCX ou de componentes pré-fabricados. Roda na plataforma Windows®95 e posteriores, e pode ser baixado livremente em sites disponíveis na Internet sem quaisquer custos adicionais. Este capítulo mostra os recursos e a sintaxe da pseudolinguagemutilizada por esta ferramenta, com esquemas e exemplos bem esclarecedores. 2.2 - Básico sobre Aprendizagem em Programação No mundo informatizado de hoje, com as comunicações feitas através de bits e bytes, estamos cheios de novas TIC´s (Tecnologia em Informática e Comunicação), como os notebooks, tablets, smartphones, e até os bons e velhos desktops. As pessoas vivem falando que “baixaram” um aplicativo para isto ou para aquilo. Mas, para criar esses aplicativos é preciso utilizar alguma linguagem de programação para resolver o problema do usuário, através do desenvolvimento de códigos-fonte, e depois http://pt.wikipedia.org/wiki/Software http://pt.wikipedia.org/wiki/Portugu%C3%AAs_estruturado 30 transformá-los em programas práticos; caso contrário a comunicação não vai existir, e o problema não será corretamente resolvido, como desejaria o usuário. De uma forma geral, a criação do código-fonte de um programa para resolver um problema, abrange várias fazes (o que não será mostrado aqui, por fugir ao escopo deste livro); e, dependendo do ambiente de desenvolvimento, isto pode não ser trivial. Entretanto, de um modo geral, para criar converter um algoritmo em código-fonte, o programador precisa conhecer uma linguagem de programação e, principalmente, ter uma base bem sólida de lógica de programação. E para conseguir isto, o programador necessita ter uma boa formação acadêmica, podendo ser adquirida em cursos de informática voltados para a área de programação de computadores. Nesses cursos os programadores aprendem (ou. pelo menos deveriam aprender) lógica de programação; como definir a sequência lógica do programa e implementar a solução. Não raramente, os iniciantes encontram muitas dificuldades em aprender a “lógica de programação”, por precisar intrinsecamente de uma certa dose de “intuição”, integrado a um processo cognitivo de aprendizagem. Por isto, muitos acabam desanimando e desistindo; tanto em cursos de computação quanto em engenharias nos seus primeiros ciclos; e um dos motivos é que eles precisam montar os algoritmos com a lógica, antes de aprenderem como eles funcionam. Muitos professores, para ajudá-los no início do curso, adotam suas técnicas de ensino com alguns métodos, tais como: algoritmos descritivos, diagramas de blocos (que alguns chamam de fluxogramas) e as pseudolinguagem de programação como o português estruturado, também conhecido popularmente como portugol; utilizando essas técnicas, o aprendizagem é bastante facilitado no início de um curso nas áreas de Ciências Extas e/ou Engenharias. 31 2.3 - Histórico do Visualg De 1980 a 1983, os professores Antonio Carlos Nicolodi e Antônio Manso - este da Universidade de Coimbra (Portugal) - criaram uma pseudolinguagem baseada no estilo portugol. O projeto foi formulado e montado para ajudar os alunos de “Lógica de Programação” pois,eles tinham que usar a linguagem de programação Pascal como ferramenta básica; mas, assim como todas as linguagens de programação, o Pascal tem toda a sua sintaxe escrita em inglês, o que causava alguns transtornos e muita desistência dos alunos iniciantes nessa disciplina. E, como titular desta disciplina, em instituição de ensino, no Brasil, o professor Antonio Carlos Nicolodi sentia o problema de perto; os alunos estavam com muita dificuldade, nessa tal “Lógica de Programação”, já que eram usados métodos antigos e ainda muito americanizados, com linguagens de programação real, em Inglês; isto era um problema sério para o aprendizado. Então, em meados de 1985 foi adotado este novo método: o Português Estruturado (portugol) conforme está compilado na Wikipédia, no link https://pt.wikipedia.org/wiki/Portugol (em 13/03/2020 - 15:58). O portugol foi baseado na semântica de numa família de linguagens de programação de computadores (1960/1970) chamada Algol (do inglês Algorithmic Language - Linguagem de Algoritmos), considerada a “mãe de várias outras linguagens”, pois é baseada em uma estrutura modular que trabalha com blocos estruturados de comandos. Sua sintaxe foi adotada para os microcomputadores na linguagem de programação Pascal, e que era muito difundida em todas as universidades do Brasil naquela época, por ser bem mais simples que o Cobol. Entretanto, assim como o Algol, o Cobol era destinado para trabalhar em máquinas de grande porte chamados de mainframes, e a lógica de programação daquela época usava como ferramenta principal o https://pt.wikipedia.org/wiki/Portugol 32 fluxograma (na verdade, diagrama de blocos). Por isto, foi adotada a estrutura simples do Algol, mas com as características do Pascal, já adaptada para micros (como o famoso Turbo Pascal); daí nasceu o portugol, que foi extremamente difundido no Brasil e nos vários países de língua Portuguesa. Deste modo, para criar a solução lógica dos problemas, os alunos ainda tinham que montar os seus algoritmos em portugol, usando os seus cadernos e testá-los, antes de traduzir para a linguagem Pascal, compilá-los e, então, testá-los para conferir se estavam corretos. E esses testes eram feitos através do famoso e trabalhoso “Teste de Mesa”, onde escreviam no seu próprio caderno, montando uma tabela com os nomes de todas as variáveis, e a cada passo do algoritmo alteravam os seus conteúdos, usando como ferramenta informações “mentais” em situações imaginárias. Isso era muito tedioso e não muito eficiente; mas tinha que ser usado para verificar se o algoritmo estava correto e sem erros de lógica. E depois de tudo isto, quando não já houvesse mais nenhum erro, então o aluno iniciante deveria transcrever as linhas do algoritmo, escritos em portugol, para uma linguagem de programação (como Pascal ou C), usando um editor de textos para, então, codificar o programa, executar e ver os resultados na tela do computador. E caso fosse detectado algum erro, deveria refazer tudo de novo, reiniciando o ciclo torturante da programação. Observe a figura 2.1 que mostra um exemplo de “teste de mesa” criado para depurar o programa “Trocas”, que lê dois números, A e B, faz a troca entre eles e os exibe com seus valores trocados. O pseudocódigo é mostrado a seguir... 33 Programa Trocas //Faz trocas entre dois números Declare A, B, X: inteiro Início Escreva("Digite o primeiro número A: ") Leia(A) Escreva("Digite o segundo número B: ") Leia(B) X A A B B X EscrevaLn("") //salta linha EscrevaLn("Valor final de A: ", A) EscrevaLn("Valor final de B: ", B) FimPrograma Sequência A B X 1 3 4 - 2 3 4 3 3 4 4 3 4 4 3 3 Figura 2.1 - Teste de mesa do programa “Trocas” 34 O teste de mesa para testar/depurar o programa “Trocas” é muito simples e fácil de criar; entretanto, para programas mais complexos, esse processo de teste pode ficar inviável e muito complexo. Assim, era preciso uma ferramenta que agilizasse o ciclo de criação/teste/depuração do programa, voltado para os programadores iniciantes. 2.4 - O Visualg no auxílio à Programação O Visualg (acrônimo de Visual Algoritmo - Visualizador de algoritmos) é um software que permite criar, depurar e interpretar os algoritmos; o que o torna uma ferramenta muito poderosa para os alunos iniciantes (e mesmo profissionais), pois os programadores podem escrever diretamente nele os seus algoritmos em portugol, sem precisar utilizar fluxogramas ou fazer testes de mesa. E com é uma pseudolinguagem de programação perfeitamente identificada com o portugol, o programador se sente muito confortável para testar as soluções algoritmizadas. O programador, iniciante ou não, pode escrever e testar seus algoritmos com todos os recursos de um bom editor de textos (sem formatação), mas, com recursos mais avançados, além de comandos e funçõesbilt in eficientes. Também permite testar o algoritmo e acompanhar a execução passo a passo; observando as instruções, os comandos e os conteúdos das variáveis a cada linha do algoritmo. Isto faz com que o programador entenda melhor a lógica da solução e consiga detectar anomalias e/ou possíveis erros na lógica da programação, podendo corrigi-los de forma rápida, simples e eficiente. A ferramenta possui várias janelas e caixas de diálogos explicando suas funcionalidades; e também possui uma autoexplicação de cada área na “barra de status”, na parte inferior da janela principal. Além disto, os usuários podem exportar todo o algoritmo de qualquer tamanho para um arquivo-texto já transformado na sintaxe da linguagem de programação Pascal, 35 cujo “Nome do arquivo.extensão” já é sugerido através de uma caixa de diálogo padrão no ambiente Windows®; pronto, rápido e sem nenhum esforço. O Visualg, em sua versão mais recente, possui algumas funcionalidades novas, novos comandos, e novas funções, permitindo a seus usuários escreverem os seus códigos, tanto em portugol padrão sem acentos e cedilha escritos em minúsculos, quanto com acentos e cedilha, só que em escritos em MAIÚSCULAS. Além disto, permite a todos os usuários personalizar quase totalmente o software e os algoritmos de maneira mais funcional, especificando informações sobre o nome da disciplina, nome do professor, nome do curso, nome da unidade do curso, etc; sempre evoluindo para ser mais intuitivo e melhor. 2.4.1 - A Tela Principal do Visualg Ao carregar a ferramenta o que se apresenta é uma tela como a da figura 2.2a, que mostra o IDE (Integrated Development Environment - ambiente de desenvolvimento integrado) - tela principal do Visualg (versão 3.0x); mostrando um template com alguns termos iniciais indicativos. As futuras versões poderão ter algumas diferenças em relação a esta, porém muito sutis, pois o objetivo da ferramenta é se apresentar, de maneira bem intuitiva e bem interativa com o programador. É nessa tela (janela principal da ferramenta) onde se define o principal ambiente de trabalho do programador; é onde o algoritmo deve ser escrito para que o programa possa ser interpretado e executado, de modo a solucionar o problema proposto pelo usuário. Por outro lado, é importante frisar que o algoritmo deve ser tal que apresente a solução que traga eficiência e mais eficácia possível, interagindo bem com o usuário, e apresentando uma solução mais geral, quando for o caso. Por exemplo: se o problema for “calcular a soma dos dez primeiros números naturais”, o programador deve tentar fazer com que a solução 36 seja a mais geral; por exemplo, “calcular a soma dos n primeiros números naturais”, deixando para o usuário escolher quantos números (valor de n) ele quer que sejam somados, e não apenas dez. Isto é, deve apresentar uma solução mais geral possível, reaproveitável e, consequentemente, mais profissional. Figura 2.2a - Janela principal do Visualg A figura 2.2b mostra o programa “Trocas” no ambiente do Visualg, exibindo no editor da ferramenta o seu código-fonte na janela principal, na sua área de definição personalizada. 37 Figura 2.2b - Exemplo de código-fonte do programa no editor do Visualg 2.4.2 - Características Básicas da Ferramenta A área total de edição de um programa em Visualg pode ser subdividida, didaticamente, em três, conforme mostra o esquema do quadro 2.1. 38 1ª) Área de identificação e documentação do programa algoritmo "Nome_do_programa" // Disciplina : [nome do projeto/disciplina] // Professor(a): [Nome do professor da disciplina, se for o caso] // Descrição: Descrição do que o programa faz (objetivo) // Autor(a): Nome do autor (ou aluno se for o caso) // Data atual: Data do sistema 2ª) Área de declarações globais Arquivo Const Tipo Var 3ª) Área dos comandos/instruções Inicio //início do programa principal Aqui são digitadas as instruções em pseudocódigo. fimalgoritmo //fim do programa principal Quadro 2.1 - As áreas de desenvolvimento do Visualg As configurações básicas dos elementos de um programa seguem padrões preestabelecidos pela ferramenta. As palavras-chave (termos reservados) aparecem, originalmente, na cor azul (sublinhadas); as strings (textos entre aspas) na cor vermelha, valores numéricos na cor preta, valores lógicos (verdadeiro e Faso) na cor vermelha, os tipos de dados na cor marrom e sublinhados e as variáveis na cor preta normal. Isto facilita muito a edição de um programa, além de ajudar na depuração de erros. Mas, embora as fontes desses elementos 39 possam ser alteradas no menu Manutenção/Configurações, sugere-se que sejam mantidas como determina os padrões. Nota 1: Obviamente, por não ser colorido, aqui neste livro os elementos “coloridos” aparecerão com a cor meio “acinzentada” para indicar esta singularidade, em contraste com o texto normal. Nota 2: Cada linha de código deve ser escrita integralmente numa única linha do editor; uma linha de instrução não pode ocupar mais de uma linha de texto. Nota 3: Na seção de declarações os termos “Arquivo”, “Const” e “Tipo” (para acessar arquivo, criar constantes e registros, respectivamente), não aparecem de imediato; devem ser colocadas de acordo com as necessidades do programa, e NESTA ORDEM. 2.5 - Pseudocódigo x Visualg O capítulo anterior mostrou que para solucionar um problema através de um programa de computador, é necessário criar o algoritmo que implementa a solução, e em seguida formalizar mais tecnicamente esse algoritmo através do chamado “pseudocódigo”. As linhas de um programa em pseudocódigo traduzem os passos do algoritmo de uma forma mais técnica e mais rigorosa; e para isto são empregados termos que permitem compactar as ordens descridas informalmente no algoritmo. Assim, são empregados termos mais próximos de uma linguagem real; por exemplo, Leia(A) em vez de “Pegue o primeiro número” como é escrito no algoritmo; esta reescrita faz com que o futuro código-fonte fique mais fácil de ser implementado. Embora a escrita em pseudocódigo possa ser em Português livre, para que possa ser colocado dentro do editor do Visualg é preciso que ele sofra pequenas adaptações para o portugol dessa 40 ferramenta. Por exemplo, Faça passa a ser Faca (sem a cedilha), assim como Então que deve ser escrito como Entao (sem o til). Além destes termos em Português, outros comandos sofreram algumas alterações aqui neste livro como, por exemplo, a estrutura Selecione..FimSelecione que no Visualg deve ser Escolha..FimEscolha. A tabela 2.1 abaixo mostra comparações entre alguns termos utilizados no pseudocódigo e seu correspondente em Visualg, o que revela uma semelhança total entre eles. Isto significa que o pseudocódigo do programa pode ser, efetivamente, já escrito como o Visualg o reconhece; entretanto, como o pseudocódigo é uma maneira livre de formalizar o algoritmo, assim, ele pode ser escrito em livre Português, como é feito aqui neste livro. Pseudocódigo Visualg O que faz/Onde utilizar Então Entao Em estruturas de decisão. Senão Senao Em estruturas de decisão. Selecione Escolha No início de uma estrutura de seleção. FimSelecione FimEscolha No final de uma estrutura de seleção. CasoContrário OutroCaso Alternativa default em estrutura de seleção. Faça Faca Em estruturas de repetição lógica com teste no início. Até Ate Em estrutura de repetição numérica. AtéQue Ate Em estruturas de repetição lógica com teste no final. Abandone Interrompa Comando para sair incondicionalmente de um loop. Tamanho() Compr() Função que retorna tamanho de uma strings. 41 CaracNum() CaracpNum() Função que converte caractere em número.NumCarac() NumpCarac() Função que converte número em caractere. Posição() Pos() Função que dá a posição de um caractere numa string. Tabela 2.1 - Portugol do Pseudocódigo versus portugol do Visualg Nota: Embora possa ser escrito exatamente conforme exige a sintaxe do Visualg, aqui neste livro optamos por escrever o pseudocódigo em Português livre, além de alterar alguns termos para ficarem melhor explicados para o leitor, como por exemplo, na estrutura Selecione..FimSelecione em vez de já escrever Escolha..FimEscolha. Outra alteração, mesmo sendo bem sutil, é o caso da função que converte caractere um número: CaracNum (eliminando p) em vez de diretamente CaracpNum, como exige o Visualg, assim como na função Tamanho (que dá a quantidade de caracteres de uma string) em vez de Compr no Visualg. Estas alterações foram feitas apenas para que o pseudocódigo pudesse expressar melhor, em Português, as linhas de código do programa. 42 ATENÇÃO: Em temos de escrita do código de um programa no ambiente de desenvolvimento do Visualg o padrão da ferramenta é apresentar as palavras-chave em letras minúsculas, tal como se apresentam na linguagem C. Entretanto, apenas para dar um melhor significado a todas as palavras reservadas e/ou comandos e funções, aqui neste livro optamos pelos estilo “camel”, para enfatizar esses termos. Por exemplo, a palavra-chave que aparece em todos os programas em Visualg é algoritmo, assim como fimalgoritmo; em letras minúsculas. Aqui neste livro adotamos um estilo em que TODAS as palavras-chave devam aparecer SEMPRE com a primeira letra em maiúscula, e depois com uma combinação de maiúsculas e/ou minúsculas. Deste modo, ficará Algoritmo e FimAlgortimo para indicar início do programa e fim do programa, respectivamente. No caso de FimAlgoritmo para enfatizar a ação “Fim do Algoritmo”, fazendo com que o comando tenha mais “força” ao ser lido pelo programador, assim como LimpaTela, FimSe, FimEnquanto, etc. Embora o Visualg não seja “case sensitive” (o programador pode escrever os comandos e funções sem se importar com maiúscula ou minúsculas), aqui neste livro é adotado este estilo que reflete mais as ações, como por exemplo: FimEscolha em vez de fimescolha pois, como pode ser notado, a primeira alternativa reflete bem mais a ação do que a segunda, indicando “Fim da Escolha”! E também para comandos e funções simples: Div, em vez de div, Mod em vez de mod, Copia em vez de copia, CaracpNum em vez de caracpnum, Int em vez de int, Abs em vez de abs, Escreva em vez de escreva, Leia em vez de leia, etc. 43 2.6 - Funcionalidades Práticas do Visualg O programador pode escrever e testar seus algoritmos com todos os recursos de um bom editor de textos no padrão Windows®, mas com recursos mais avançados, além de novos comandos e funções melhores. E depois, ainda pode testar e acompanhar passo a passo a execução do algoritmo, além das instruções e conteúdo das variáveis a cada linha do programa, para entender melhor e detectar anomalias e/ou erros; e, se necessário, corrigir e modificá-los de forma rápida, simples e eficiente. Esta é uma das vantagens do Visualg, como ferramenta de auxílio ao aprendizado de programação, dispensando recurso antigos de depuração do futuro código-fonte, ainda na fase de criação do programa. A barra de Status (figura 2.3) é um desses recursos extras na edição/testes dos programas. Figura 2.3 - Barra de status do Visualg Depois de editar o programa, e caso queira, o usuário poderá exportar todo o algoritmo de qualquer tamanho para um arquivo- texto já transformado na sintaxe da linguagem de programação Pascal, E, além de uma nova aparência, na versão 3.0 foram acrescentados novos comandos e novas funções, permitindo aos seus usuários escreverem seus algoritmos, tanto na versão antiga (em minúsculo, sem a grafia portuguesa, para manter a compatibilidade com os algoritmos escritos nas versões antigas) quanto com todos os acentos e com o "Ç": SÓ QUE, NESTE CASO, EM MAIÚSCULAS. Observe os exemplos comparativos a seguir... 44 Versões 2.xx Versão 3x j <- 1 j <- 1 Para k de 1 Ate 100 Faca Para k De 1 ATÉ 100 FAÇA j <- k + 1 j <- k + 1 Se(j Mod 2 = 0) Entao Se(j Mod 2 = 0) ENTÃO Escreval(j) Escreval(j) FimSe FimSe FimPara FimPara Nota: Apenas por uma questão de estilo, adotaremos neste livro a escrita da versão 2.xx, como mostrado na tabela 2.1. Mas, o leitor pode utilizar a sintaxe da versão 3.xx, sem problemas; é apenas uma questão de gosto e estilo pessoal. 2.7 - Itens do Menu Principal Figura 2.4 - Barra de Menus e Barra de Botões de atalho 2.7.1 - Opção “Arquivo” Arquivo - Contém itens que permitem manipular os arquivos com os algoritmos, como: Novo, Abrir, Salvar, Salvar Como, Imprimir e Sair. A figura 2.5 mostra todos os itens desta opção. 45 Figura 2.5 - Itens da Opção “Arquivo” Abaixo estão descritas as opções da janela da opção “Arquivo”. • “Novo” permite ao usuário criar um novo programa, apagando, “caso não salve”, o conteúdo que estava anteriormente na área de programas. Também pode-se usar as teclas de atalho Ctrl+N. • “Abrir” permite ao usuário abrir um programa que foi salvo ou criado anteriormente e carregá-lo para a área de programas. Também pode-se usar as teclas de atalho Ctrl+A. • “Salvar” e “Salvar Como” permitem ao usuário salvar um programa que ainda não foi salvo e chamar a caixa dele para a área de programas. Também pode-se usar as teclas de atalho Ctrl+S e Ctrl+Alt+C, respectivamente. Sugere-se que o nome do programa seja salvo com o 46 mesmo nome do programa, embora isto não seja obrigatório. • “Imprimir” permite imprimir o programa em uma impressora conectada ao microcomputador, e configurada para o Windows®. Nesta opção também é mostrada uma lista com os últimos cinco nomes e localização dos arquivos usados pelo programa. • “Sair” fecha e encerra a ferramenta, retornando ao sistema operacional. Figura 2.6a - Abrir um arquivo já salvo 47 Figura 2.6b - Salvando um arquivo que está no Editor Quando o usuário for salvar um programa em um arquivo na mídia, dentro do Windows®, o nome do arquivo já é automaticamente sugerido como o nome do exercício que está entre “aspas” no início do programa (depois da palavra-chave Algoritmo), acrescentando a extensão .alg 48 2.7.2 - Opção “Editar” Figura 2.7 - Salvando um arquivo que está no Editor Esta opção da barra do “Menu Principal” permite ao usuário usar recursos de um editor de texto, próprio da ferramenta; conforme mostra a figura 2.7. • “Desfazer” permite ao usuário desfazer o(s) último(s) comando(s) ou serviço(s) efetuado(s). Pode-se usar as teclas de atalho Ctrl+Z. • “Refazer” permite voltar atrás e refazer o que o usuário já tinha desfeito. • “Recortar” permite ao usuário recortar uma parte do programa. A alternativa é pressionar as teclas de atalho Ctrl+X. 49 • “Copiar” permite ao usuário copiar uma parte do programa para a memória temporária. As teclas de atalho Ctrl+C podem ser usadas para o mesmo propósito. • “Colar” permite ao usuário colar num local do programa, o que havia sido copiado na memória temporária Podem ser usadas as teclas de atalho Ctrl+V. • “Indentação” permite ao usuário forçar a indentação; ou seja, colocar todo o texto no formato hierárquico tabulando de três em três caracteres a cada nível, melhorando a estética do programa. A ação semelhante pode ser conseguida com as teclas de atalho Ctrl+G. • Selecionar Tudo, permite ao usuário selecionar todo o texto do algoritmo. Podem ser usadas as teclas de atalho Ctrl+T. • “Localizar...” permiteao usuário procurar e/ou localizar palavras ou parte de um texto, dentro do programa inteiro. Alternativamente, podem ser usadas as teclas de atalho Ctrl+L. • “Localizar o Próximo” permite ao usuário procurar e/ou localizar a próxima palavras ou parte de um texto, já encontrada dentro do programa inteiro. Pode-se usar a tecla de atalho F3. • ”Localizar a Anterior” permite ao usuário procurar e/ou localizar a palavra anterior da parte de um texto, já encontrada no programa inteiro. A tecla de função F4 produzirá o mesmo efeito de for pressionada. • “Substituir...” permite ao usuário substituir a(s) palavra(s) já encontrada(s) por outra(s) dentro do programa inteiro. Pressionando as teclas de atalho Ctrl+U o efeito será o mesmo. 50 • “Gravar Bloco...” permite ao usuário gravar parte do texto dentro de um arquivo temporário do programa. Pressionando as teclas de atalho Ctrl+W o mesmo efeito será produzido. • “Inserir Bloco...” permite ao usuário inserir dentro do programa um arquivo temporário após a última linha do algoritmo. Antes de FimAlgoritmo. Pode-se usar as teclas de atalho Ctrl+R para que isto seja conseguido. Na figura 2.8 - submenu de “Localizar” - mostra uma caixa de diálogo onde o usuário pode digitar a palavra a ser pesquisada em “Procurar por:” e filtrar pelas opções que podem ser marcadas em pela “Direção” da pesquisa “para Frente” ou ”para Trás” Figura 2.8 - Pesquisa de texto no programa Ainda, na figura 2.8, em “Opções”, o usuário poderá fazer a pesquisa da palavra de várias maneiras quanto à sua grafia. 51 2.7.3 - Opção “Run” Esta opção da barra do “Menu Principal” permite executar (rodar) os algoritmos; como mostra a figura 2.9a. Figura 2.9a - Opção do submenu Run • “Rodar o Algoritmo” roda diretamente o programa, e pode-se analisar a lógica do programa. A tecla de função F9 é a alternativa para essa ação. • “Rodar Passo a Passo” executa o programa linha por linha, onde cada linha será executada se o usuário clicar nesta opção do menu ou apertar tecla de atalho F8. • “Rodar com Tempo” o usuário define um intervalo de tempo que o programa esperará para executar a linha; esse tempo é definido por uma caixa de opções conforme exibida (vide figura 2.9b), Pode-se usar as teclas de atalho Shif+F9. • “Parar” (Stop) permite ao usuário parar a execução do algoritmo manualmente, antes do seu termino. As teclas de atalho Ctrl+F2 pode ser usadas como alternativa. 52 • “Liga/Desliga breakpoint” permite ao usuário colocar pontos de paradas dentro do programa, para fins de testes. A tecla de função F5 pode ser usada como alternativa. • “Desmarcar todas” (os breakpoints) permite ao usuário desmarcar todas as marcas de breakpoints. Pode-se usar as teclas de atalho Ctrl+F5. • “Executar em modo DOS” (opção temporariamente desativada n versão 3x). • “Linhas (Ativa/Desativa)” permite ao usuário ativar ou desativar a numeração das linhas que aparecem na lateral esquerda do programa. • “Gerar valores Aleatórios” permite ao usuário gerar números aleatórios quando o programa precisar. • “Perfil” permite ao usuário criar um perfil dentro do programa. Pode-se usar a tecla de atalho F7. • “Pilha de ativação” permite ao usuário criar uma pilha de ativação dentro do programa. Pode-se usar as teclas de atalho Ctrl+F3 como alternativa a essa opção. Figura 2.9b - Intervalo de tempo na opção “Rodar com Tempo” 53 2.7.4 - Opção “Exportar” Esta opção da barra do” Menu Principal” permite ao usuário exportar o programa, já convertendo-o em uma linguagem de programação, Pascal ou C/C++ e Java (ainda em desenvolvimento) como mostra a figura 2.10. Figura 2.10 - Exportando o programa em Visualg para uma Linguagem Na opção para exportar “a Linguagem de programação Pascal”, o Visualg já transforma as linhas do português estruturado do algoritmo para os comandos da linguagem evitando assim, que o usuário tenha que reescrever todo o código-fonte, com exceção de alguns comandos e algumas funções que existem na ferramenta, mas não existem na linguagem Pascal. 2.7.5 - Opção “Manutenção” Nesta opção o usuário encontra os recursos para alterar: cor de fontes, aparência, dados dos usuários e dos lugares onde são usados. A figura 2.11a mostra os itens desta opção. Figura 2.11a 54 • “Configurações” permite ao usuário alterar o ambiente do Visualg através de três abas como são mostradas na figura 2.11b. Figura 2.11b - Opções de configuração da ferramenta ▪ Na aba Editor o usuário pode alterar as configurações primárias que irão afetar toda a aparência do código, em tempo de codificação do programa: ✓ Largura da Tabulação: número de colunas que a indentação irá considerar. ✓ [x] Usar a tabulação inteligente. ✓ Fonte: alterar o tipo do fonte (Courier New é o default) padrão do Windows®.. ✓ Tamanho da fonte “11” é o default. 55 ✓ Elementos: este item troca as cores dos elementos do texto do programa conforme é apresentado em exemplos: Comentários Constantes Fundo do Editor Palavras-Chave Palavras especiais Tipos de dados Texto em Geral ✓ Atributos: podem ser alterados a cor e o estilo de cada um dos elementos, em: Negrito Itálico Sublinhado E como resultado, cada um desses elementos pode ser visualizado na caixa de comentários chamada “Exemplo” na janela a direita e abaixo. ▪ A aba Listas mostra algumas listas que podem ser cadastradas dentro do Visualg para ajudar os usuários, como é mostrado na figura 2.11c. Nesta aba os usuários podem criar listas padrões para uso dentro dos algoritmos e usá-los quando necessário como, por exemplo: • MESES de um ano (Janeiro, Fevereiro, Março, ...) • DIAS da semana (Segunda-feira, Terça-feira, ...) • ESTADOS do Brasil (Minas Gerais, Santa Catarina, Rio de Janeiro, Bahia Paraná, ...) • TIMES de futebol (Flamengo, Vasco, São Paulo,...)) • CIDADES de um estado (Tombos, Florianópolis, Gaspar, Maringá, Campinas, etc) 56 Figura 2.11c - Opções de configuração de Ambiente ✓ O botão [Nova...] permite ao usuário criar uma nova lista. ✓ O botão [Excluir..] permite ao usuário excluir (apagar) uma lista já criada. ✓ A aba Personalizar permite ao usuário fazer alterações nas informações para tornar o Visualg personalizado, além de poder modificar as caixas de edição, conforme indica a figura 2.11d. Essas alterações personalizam o programa que está sendo editado, tais como: ✓ Entidade 57 ✓ Disciplina ✓ Professor ✓ Turma Especial ✓ Endereço Figura 2.11d - Opções de alterações na identificação do programa As alterações poderão ser feitas pelo usuário em função da importância do programa que está sendo criado, mas, isto não é obrigatório; a não ser no caso em que a ferramenta esteja sendo usada para fins didáticos e/ou em aula expositiva para alunos iniciantes na ferramenta. “Calculadora” oferece uma calculadora básica, parecida com a das versões antigas do Windows®, mas com uma configuração própria sendo possível copiar os dados para a área de memória temporária e colar quando voltar ao texto do algoritmo; veja na figura 2.11e. 58 Figura 2.11e - A Calculador do Visualg “Calendário” oferece um calendário anual, como mostrado na figura 2.11f. Figura 2.11f - O Calendário do Visualg 59 2.7.6 - Opção “Help” A opção Help (Ajuda) da barra do “Menu Principal” permite ao usuário, consultar um manual dentro do próprio Visualg, pois em cada janela há um conjunto de telas para ajudar os usuários. A figura 2.12a mostra os itens das opções do submenu. Figura 2.12a - Itens da Opção Help do Visualg “Tela do Visualg” permite ao usuário abrir um gerenciador do manual completo no formato HTML ou arquivos CHM[10]em tela cheia de dentro do próprio Visualg, contendo todas as informações importantes do software, como mostra a figura 2.12b. Figura 2.12b - A Tela de Help do Visualg para um manual da ferramenta 60 E como pode ser notado, o gerenciador HTML de Help possui uma barra de botões, e seu conteúdo dividido em duas áreas; sendo que a área da esquerda tem duas abas que contém tópicos de pesquisas, onde o usuário pode alternar entre os itens para sanar as dúvidas, como nas figuras 2.12c e 2.12d. Figura 2.12c - Help em HTML Ícones permitem ocultar as guias de pesquisas e imprimir o seu conteúdo em uma impressora, Voltar, Avançar e Opções, e também modificar o gerenciador de Help. Figura 2.12d - Abas do Help Na área das guias do “Help” a aba “Conteúdo” o usuário pode escolher os tópicos de cada item cujo conteúdo aparecerá na área da direita da janela. 61 Figura 2.12e - Pesquisa da palavra e mostra o conteúdo “A Linguagem do Visualg” mostra aos usuários o arquivo HTML diretamente com os comandos, funções, operadores e outras informações da linguagem do Visualg como mostra a figura 2.12f. Figura 2.12f - O item: A Linguagem do Visualg 62 “Referência da Linguagem do Visualg” oferece ao usuário uma coleção de todas as palavras-chaves da Linguagem do Visualg como mostra a figura 2.12g. Figura 2.12g – Referências, palavras chaves 63 “Sobre os autores do Software” mostra os autores do Visualg; das versões que deram origem a ele, como indica a figura 2.12h; em destaque o professor Antonio Carlos Nicolodi que modificou e que, atualmente, é o gestor da ferramenta. O botão [Donativos] permite saber mais informações sobre a ferramenta e como colaborar com seu desenvolvimento. O botão [Voltar ao programa] permite voltar á tela principal onde o programa atual editado. Figura 2.12h - O gestor atual do Visualg 64 2.8 - Áreas Funcionais do Visualg O IDE do Visualg se divide, funcionalmente, em cinco áreas como visto na figura 2.13a 1. Área de Identificações gerais do programa. 2. Área de declarações globais. 3. Área de criação do programa. 4. Área das variáveis de memória. 5. Área de visualização dos resultados. Área das Varáveis de Memória Área de declarações globais Área de identificações gerais do Programa Área de criação do programa (entre Inicio e FimAlgoritmo) Área de visualização dos resultados Figura 2.13a - As áreas de desenvolvimento do Visualg 65 Embora sejam cinco as áreas funcionais do IDE do Visualg (vistas na figura 2.13a), estas podem ser compactadas em apenas três, básicas, conforme são descritas a seguir... 2.8.1 - Áreas do Programa (edição do código-fonte) Esta é a área que mais se destaca no IDE do Visualg, pois é nela onde a “magia” acontece; permite ao usuário criar, editar e interpretar o algoritmo escrito em uma pseudolinguagem, já definida como portugol, e utilizada em muitas literaturas sobre programação; no Brasil e em vários outros países de língua Portuguesa. Na verdade, é uma aproximação do portugol original, mas com muito mais recursos, mais comandos e mais funções. Nessa área o usuário tem algumas informações à sua disposição para criar e editar os seus códigos. A figura 2.13b mostra a aparência do formato inicial de um programa com as suas três sessões e algumas informações extras. • As linhas numeradas. • O nome (temporário) do arquivo entre os colchetes sendo “semnome” quando não tiver nenhum arquivo criado e salvo com outro nome, ou em branco. • A sessão do cabeçalho iniciando sempre com palavra reservada Algoritmo e com nome do arquivo “semnome” sempre entre aspas. • Os comentários: opcionais, mas essenciais quando o aluno é iniciante. • A sessão onde são declaradas as variáveis de memórias, com seus tipos. • A sessão de Inicio do algoritmo: é aqui que as linhas de instruções são iniciadas para montar o programa principal. 66 • A sessão de final do algoritmo (programa): onde é colocado a palavra reservada FimAlgoritmo. A figura 2.13b mostra um modelo de como é, inicialmente, a “Área do Programa”. Figura 2.13b - A “Área de Programa” do Visualg 2.8.2 - Área das Variáveis de Memória É nesta área que o usuário (programador) pode ver, em tempo de execução - quando o programa estiver rodando - o conteúdo das variáveis de memória, criadas. Assim, pode-se averiguar se o programa realmente está correto ou quando algum erro de lógica acontece. Esta área dispensa o “teste de mesa” para apurar a corretude do algoritmo, pois o próprio Visualg se encarrega disto (vide figuras 2.13c e 2.13d) 67 Figura 2.13c - As colunas da “Área das Variáveis de Memória” Esta área é dividida em quatro colunas, onde são mostrados: ▪ Escopo ▪ Nome ▪ Tipo ▪ Valor A coluna Escopo mostra informações a respeito de onde se origina uma variável; se ela é global ou local; se pode ser visualizada tanto no programa (ou rotina principal) quanto pelas UDFs (UDF (sigla em Inglês para User Define Function - função ou procedimento definidos pelo usuário); assim a sua visualização poderá ser: • Global - Pode ser vista (enxergada, acessada, manipulada) por todo o programa e por todas as UDFs existentes no programa. 68 • Local - Só pode ser vista (enxergada, acessada, manipulada) no módulo que à criou: como uma UDF (função ou um procedimento). A figura 2.13d, mostra um exemplo de acompanhamento dos valores instantâneos de algumas variáveis. Figura 2.13d - Acompanhamento do status de variáveis em execução A coluna Nome contém o nome (identificador) da variável. A coluna Tipo dá o tipo da variável. • inteiro • real • caractere • logico A coluna Valor mostra o conteúdo da variável, naquele instante do processamento. 69 ❖ Exemplo 2.1 - Ler o salário bruto de um funcionário, o percentual de desconto para a Previdência Social, e no final mostrar: • O salário bruto lido. • O valor do desconto que incidiu sobre o salário bruto. • O salário líquido recebido. • Algoritmo "ControleSalarial" //Descrição: Controla os dados de salário de funcionário. //Autor(a) : Antonio Carlos Nicolodi //Data atual : 04/03/2020 //------------------------------------------------------- Var SalBruto, SalLiq, PercDesc, Desc: real Inicio Escreva("Digite o salário bruto: ") Leia(SalBruto) Escreva("Digite o percentual de desconto: ") Leia(PercDesc) Desc <- (SalBruto*PercDesc)/100 SalLiq <- SalBruto - Desc Escreval("") Escreval("Salário Bruto lido: ",SalBruto) Escreval("Desconto para INSS: ",Desc) Escreval("Salário líquido: ",SalLiq) FimAlgoritmo Ao pressionar a tecla F9 será executado o algoritmo, e mostrar o resultado na tela do console, como mostra a figura 2.14a. 70 Figura 2.14a - Saída do programa “ControleSalarial” Agora que o algoritmo do programa “ControleSalarial” foi testado e já constatada a sua corretude, deve-se fechar janela do Console, pressionando a tecla Esc, Se quiser converter o código em Pascal, basta clicar em “Exportar Para” no menu principal e selecionar a opção “Pascal”; isto provocará a abertura de uma janela tal como mostrada na figura 2.14b. 71 Figura 2.14b - Gerador do código-fonte em Pascal a partir do Visualg Nota: Dentro da janela da figura 2.10b aparecerá inicialmente a seguinte informação: “ATENÇÃO: Esta rotina ainda está em desenvolvimento. O código gerado pode apresentar incorreções sintáticas”. Isto quer dizer que, caso seja necessário, o Visualg poderá mostrar apenas comentários, em vez de de comandos pois, existem muito mais comandos e/ou funções na pseudolinguagemda ferramenta e que não existem na linguagem de programação Pascal. O programa mostra como ficou o código escrito nessa linguagem. 72 Após esta etapa o usuário então poderá salvar esse código, que já está na linguagem Pascal, para um arquivo-texto com o nome sugerido pelo Visualg, que é o próprio nome do programa, mas já com a extensão “.pas”, para isto basta clicar no botão [Salvar] e salvar novamente. Nota: Nas versões mais antigas do Visualg era permitido criar apenas 500 variáveis incluindo os elementos dos vetores e matrizes, no total. Atualmente esse valor passou para 65535; são 64K bytes de memória utilizados. 2.8.3 - Área de Visualização dos Resultados Considerando o programa do Exemplo 2.1, observe o que acontece, na figura 2.14c. Figura 2.14c - Visualização variáveis do “ControleSalarial” em execução 73 A figura 2.14c mostra um exemplo de visualização das variáveis na “Área das variáveis de memória”, do programa "ControleSalarial", e a figura 2.14d, os resultados na “Área de Visualização dos resultados”. Figura 2.14d- Visualização dos resultados de “GeraValoresRelativisticos” 2.9 - Funcionalidades dos Botões da Barra de Ícones O Visualg oferece ícones para ações na ferramenta, de maneira rápida, substituindo as ações do Menu Principal. A figura 2.15 mostra a “Barra de Ícones”, e logo em seguida a descrição da funcionalidade de cada um deles. Figura 2.15 - A Barra de Botões/Ícones do Visualg A tabela 2.2 descreve as funcionalidades de cada elemento da barra de ícones que fornece as tarefas disponíveis na ferramenta como atalhos para as principais ações. 74 Ícone Atalho Funcionalidade [Ctrl+N] Cria um novo "modelo" de programa, substituindo o texto atual no editor. [Ctrl+A] Abre um arquivo de programa que já salvo, e substitui o texto atual no editor. A setinha mostra arquivos já salvos. [Ctrl+S] Salva o programa atual do editor; se for a primeira vez a ser salvo será pedido o nome e o local de gravação do arquivo. [F9] Executa o programa que está atualmente no editor de texto. Roda o programa [F8] Passo a passo - Executa (roda) o programa linha por linha, acompanhando o fluxo do programa, vendo 75 as variáveis, etc. Permite depurar o programa. Timer - Executa o programa com tempo predeterminado, sem precisar pressionar qualquer tecla para prosseguir. [CtrF2] Parar - Encerra imediatamente a execução do programa em execução. Fica desabilitado quando o programa não está sendo executado. [F5] Liga/Desliga Breakpoints - Cria pontos de parada em linhas de instruções do programa. Esta ação não funciona no modo passo a passo. Para continuar deve ser pressionada a tecla [F9]. 76 [CtrF5] Marga/Desmarc a Breakpoints Marca/desmarca pontos de parada já criados. Restaura a tela inicial do ambiente e retorna à tela original do programa. [Ctrl+X] Recorta o texto selecionado e o move para o Clipboard. [Ctrl+C] Copia o texto selecionado na memória no Clipboard. [Ctrl+V] Cola o conteúdo do Clipboard no local do cursor. Grava bloco - Abre uma janela para salvar o bloco selecionado; cria uma biblioteca de funções. Insere um bloco de códigos na posição do cursor. [Ctrl+Z] Desfaz a ação criada no editor de texto. 77 [Shift+Ctrl+ Z] Refaz a ação que havia sido anteriormente criada no editor. [Ctrl+L] Localiza uma string no editor de digitada numa janelinha que se abre. [F3] Localiza próxima ocorrência. [F4] Localiza a ocorrência anterior. [Ctrl+U] Abre janelinha para digitar a string que se deseja localizar e substituir no editor de texto. [Ctrl+G] Corrige automaticamente a indentação do programa e coloca as instruções dentro de uma estrutura de três colunas à direita da coluna inicial. [Ctrl+P] Imprime o programa que está no editor. Se for preciso configurar a 78 impressão use a opção Imprimir. [F7] Perfil - Após a execução de um programa mostra quantas vezes cada linha foi executada. Gera alguns números aleatórios na faixa selecionada e incrementada.sta us [Ctrl+F3] Mostra a pilha de ativação dos procedimentos e funções. Mostra uma calculadora. Mostra um calendário. [F1] Ativa Ajuda (on-line) Encerra o Visualg e retorna ao sistema operacional. Tabela 2.2 - Descrição das tarefas da “barra de ícones” 79 2.10 - A Barra de Status A “Barra de Status” do Visualg (figura 2.16) também é uma ótima fonte para que o usuário possa se informar sobre a situação do algoritmo que está sendo criado/editado. A tabela 2.3 mostra como ela se apresenta em situações “normais”, dividida em quatro partes. Figura 2.16 - A “Barra de Status” do Visualg Parte Descrição 0000015:0043 Dá a posição do cursor (linha:coluna) na edição do programa. Status Mostra informações do status do programa, como: modificado ou executando. Use as setas... Mostra a mensagem FIXA: “Use as setas para Movimentar-se ou Ctrl+j para ver a lista dos comandos e funções. Permite Criar, Alterar Esta parte mostra uma mensagem sensitiva. Onde o ponteiro do mouse estiver, ele mostra uma mensagem diferente. Tabela 2.3 – Partes da barra de status do programa 2.11 - Palavras Reservadas A linguagem de programação utilizada pelo Visualg é parecida com o Português, estruturada no estilo portugol, e permite que seja empregada em todas as situações em que haja necessidade de resolver algum problema de maneira automatizada e baseado na lógica. Este estilo segue as regras de codificação da linguagem Pascal, justamente para que a aprendizagem seja a mais produtiva possível. A codificação do programa é baseada na solução do 80 algoritmo editado, e deve levar em consideração que, mesmo não sendo uma linguagem real de programação, também possui “palavras reservadas” (palavras-chave). A figura 2.17 (obtida pressionado as teclas Ctrl+J) mostra algumas dessas palavras que não podem ser empregadas como identificadores. Figura 2.17 - Palavras reservadas do Visualg obtidas com Ctrl+J 81 2.12-Funções, Comandos Internos e Palavras Chaves Função Tipo O que faz Abs() Função Retorna o valor absoluto.. Aleatorio Comando Liga/desliga o gerador de números aleatórios, e pode substituir o comando Leia(). Asc() Função Exibe o código ASCII de um caractere. Carac() Função Exibe o caractere do código ASCII. CaracpNum() Função Converte caractere em número, se isto for possível. Copia() Função Copia subtexto de um texto Compr() Função Retorna o tamanho de uma sequência de caracteres. Const Comando Declara (cria) uma constante. Cos() Função Dá o cosseno de ângulo rad. Cronometro Comando Dá o tempo de processamento desde on até off. Exp() Função Potência de um número. Grauprad() Função Converte graus em radianos Int() Função Retorna a parte inteira de um número real, sem arredondar. Interrompa Abandona um loop de maneira incondicional. LimpaTela Comando Limpa a tela de janela DOS. Log() Função Dá o logaritmo decimal de um número real positivo. Logn() Função Dá o logaritmo natural de um número real positivo Maiusc() Função Converte em letras maiúsculas. Minusc() Função Converte em letras minúsculas. Numpcarac() Função Converte pata em caractere. Pausa Comando Para até pressiora tecla [F9] 82 Numpcarac() Função Converte pata em caractere. Pausa Comando Para até pressiora tecla [F9] Pos() Função Dá a posição inicial de um caractere num texto.RaizQ() Função Dá a raiz quadrada de um número real não negativo. Randi() Função Gera números randômicos na faixa indicada. Quad() Função Dá quadrado de um número real. Sen() Função Dá o seno de um ângulo, em rad. Tan() Função Dá a tang. de ângulo em rad. Timer(t) Comando Interrompe o processamento por t milissegundos. Pos() Função Dá a posição inicial de um caractere num texto. RaizQ() Função Dá a raiz quadrada de um número real não negativo. Tabela 2.4 - Algumas funções e comandos oferecidos pelo Visualg Nota1: A diferença entre função e comando é que a primeira sempre opera de maneira tal que seu nome vem ANTES dos parênteses e retorna um resultado que pode ser atribuído a uma variável de tipo compatível com o seu. Por exemplo, a instrução x <-Int(3.456) terá x com o valor 3, sendo x do tipo inteiro. No caso de comandos não existe nenhum retorno. Por exemplo, Cronometro on apenas liga o relógio, e o comando Cronometro off desliga o relógio. Depois de Cronometro off o tempo;o mesmo acontece com o comando LimpaTela: apenas limpa a tela dos resultados mostrado. Nota2: Pressionando, simultaneamente, Ctrl+j serão exibidos todos os comandos e funções do Visualg. 83 Palavras reservadas são termos que a linguagem reserva para si mesma (além dos comandos e funções) e que não podem ser utilizadas como identificador de quaisquer elementos de um programa: nome do programa, nome de variável, nome de constante, nome de procedimento, nome de função, etc. A tabela 2.5 mostra as principais palavras-chave do Visualg. Aleatorio Enquanto Funcao Para Algoritmo Entao Inicio Passo Arquivo Escolha Int Pausa Asc Escreva Inteiro Pos Ate Escreval Interrompa Real Carac Faca Leia Procedimento CaracpNum Falso LimpaTela Repita Caractere FimAlgoritmo Logico Retorne Caso FimEnquanto Maiusc Se Compr FimEscolha Minusc Senao Copia FimFuncao Mod Tan Cronometro FimPara Nao Var Debug FimProcedimento Numpcarac Vetor E FimRepita OU Verdadeiro Eco FimSe OutroCaso Xou Tabela 2.5 - Palavras reservadas em Visualg 84 2.13 - Recursos de Cálculos Numéricos Para manipular cálculos numéricos, o Visualg oferece uma boa relação de comandos e funções, como foi mostrado na figura 2.16. Os mais utilizados nos programas são os seguintes: • Int(operação) //função que retorna a parte inteira de uma operação ou número real. • Abs(N) //função que retorna o valor positivo (módulo) de um número N. • RaizQ(N) //função que retorna a raiz real de um número N não negativo. • Exp(N,p) //função que retorna o valor da potência p de um número N.. • LogN(N) //função que retorna o logaritmo natural de um número N (N>0). • Log(N) //função que retorna o logaritmo decimal de um número N (N>0). • Randi(faixa) //função que retorna um número randômico dentro da faixa indicada. • x Mod y //operador que dá o resto inteiro da divisão de x por y (inteiros). • x Div y //operador que dá o quociente inteiro da divisão de x por y (inteiros). • : //operador “dois pontos” utilizado para exibir valores reais arredondados.. Por exemplo: Escreval(Num:5:2) mostra Num com tamanho total 5 e 2 casas decimais. 85 2.14 - Manipulação de Caracteres Trabalhar com strings (conjunto de caracteres entre aspas) é sempre um problema em todas as linguagens de programação; no C, por exemplo, o programador “sofre” muito para lidar com esse tipo de dado. No Pascal existem os tipos “char” e “string”, justamente para programas que precisam manipular esses tipos de dados. Para manipulação de caracteres (individualmente ou formando strings) o Visualg também oferece funções/comandos que facilitam o trabalho do programador. Abaixo, estão alguns comandos e funções para esse propósito: • Var Letra: caractere //comando que declara a variável Letra do tipo caractere. • Var Frase: caractere //comando que declara a variável Frase do tipo caractere. • Var VetLetras: vetor[1..26] de caractere //comando que declara a variável VetLetras um vetor de no máximo 26 elementos do tipo caractere. • Var MatLetras: vetor[1..5,1..6] de caractere //comando que declara a variável MaLetras uma matriz de no máximo 30 elementos do tipo caractere, com 5 linhas e 6 colunas. • Asc ("x") //função que retorna um inteiro de código ASCII do primeiro caractere x. • Carac (n) //função que retorna o caractere para o código n da tabela ASCII. • CaracpNum("x") //função que retorna o caractere x convertido em valor numérico, quando isto for possível. Por exemplo, CaracpNum("24"), retornará o inteiro 24. 86 • Compr(string) //função que que retorna o tamanho de uma string. • Copia(string,j,k) //função que que retorna k caracteres de uma string, a partir da posição j dessa string. • Maiusc(Frase) //função que converte a variável caractere Frase em caixa alta (maiúscula). • Minusc(Frase) //função que converte a variável caractere Frase em caixa baixa (minúscula). • NumpCarac(n) //função que retorna o número n convertido em caractere. Por exemplo, NumpCarc(24), retornará a string "24" . • Pos("x", string) /função que retorna a posição do caractere x em uma string. Se esse caractere não estiver na string retorna 0 (zero). O programa "ManipulaCaracteres" mostra utilizações práticas dessas funções. 87 Algoritmo "ManipulaCaracteres" //Mostra a utilização de várias funções de caracteres. //Autor: Mário Leite //----------------------------------------------------- Var x, y, z, w: caractere n: inteiro Inicio x <- "2" //atribui à variável x o caractere "2" y <- "4" //atribui à variável y o caractere "4" Escreval(x+y) //será exibido "24" na tela Escreval(CaracpNum(x) + CaracpNum(y)) //será escrito 6 na tela Escreval(NumpCarac(3+4) + x) //será exibido "72" na tela z <- "Brasil, o melhor!" Escreval(Maiusc(z)) //será exibido "BRASIL,O MELHOR!" na tela Escreval(Compr(z)) //será escrito 17 na tela x <- "Brasil, centro do Universo" Escreval(Pos("c",x)) //será escrito 9 na tela Escreval(Pos("x",x)) //será escrito 0 na tela. Não existe o caractere "x" na variável x. Escreval(Asc(x)) //será exibido 66 na tela - código ASCII de "B". w <- Carac(65) + Carac(66) + Carac(67) Escreval(w) //será exibida a string "ABC" na tela n <- CaracpNum(w) Escreval(n) //será exibida 0 ("ABC" não é considerado um caractere ASCII z <- Copia(x,19,8) Escreval(z) //será exibida a string "Universo" na tela. Escreval(Maiusc(Copia(x,19,8))) //exibirá a string "UNIVERSO" na tela. FimAlgoritmo A figura 2.18 mostra as saídas da execução do programa “ManipulaCaracteres”. 88 Figura 2.18 - Saída da execução do programa “ManipulaCaracteres” 2.15 - Operações de Entrada e Saída A figura 2.19 mostra o esquema de qualquer sistema aberto, onde tem obrigatoriamente, os três elementos básicos: Entradas - Processamento – Saída Entradas Processamento Saídas Figura 2.19 - Esquema básico de um Sistema Aberto Em Programação ocorre, exatamente, a mesma situação: 89 1) Entradas dos Dados 2) Processamento 3) Saídas As Entradas são representadas pela leitura dos dados ou, atribuições diretas; o Processamento utiliza comandos/funções nas linhas de código; as Saídas são o resultado do processamento, entregando ao usuário a(s) informação (s) por ele esperada(s). No Visualg a forma mais prática de entrar com os dados é a leitura, operacionalizada pelo comando Leia; e a saída é executada pelos comandos Escreva e Escreval. A diferença entre esses dois comandos é que enquanto o comando Escreva exibe um valor e o cursor permanece na mesma linha, o comando Escreval exibe o valor e o cursor é posicionado na próxima linha. Observe as duas linhas de intruçõesabaixo, e a figura 2.20a. Escreva("Hoje tem roda de samba.") Escreva("O rock brasileiro dos anos 80 era muito bom!") Figura 2.20a - Saida com os dois comandos Escreva 90 A figura 2.20a mostra o resultado (saída) da execução das duas linhas de instruções, ambas com o comando Escreva. Neste caso a segunda frase da segunda instrução saiu imediatamente após a primeira frase. Isto aconteceu porque na primeira instrução foi usado o comando Escreva, que escreveu a frase “Hoje tem roda de samba.”; então, como não houve “salto” de linha, a saída seguinte saiu colada imediatamente no final da primeira frase. Para evitar isto, é que existe o comando Escreval (esse “éle” no final de Escreva indica new line) para mostrar a próxima saída em em nova linha. Então, alterando a primeira instrução, fica: Escreval("Hoje tem roda de samba.") Escreva("O rock brasileiro dos anos 80 era muito bom!") Figura 2.20b - Saída com o primeiro comando modificado para Escreval Em TODOS os programas, quando as entradas são solicitadas, deve-se colocar um comando Escreva, ANTES do comando de 91 entrada. Isto é fundamental para explicar o usuário o que deve ser a entrada, o que ele deve digitar; caso contrário, sem a mensagem explicativa, a interatividade com o usuário ficará prejudicada. Por exemplo, suponha que se deseja calcular a área de uma circunferência que tem um determinado raio. Observe na figura 2.21a o que ocorre caso não haja uma mensagem explicativa para essa entrada... Figura 2.21a - Esperando entrada sem uma mensagem explicativa Observe na figura 2.21a, que, mesmo tendo um título sobre o que o programa faz, a entrada não tem mensagem explicativa, e o usuário não saberá o que o programa está pedindo; o cursor fica piscando na segunda linha do programa, mas, isto não quer dizer, absolutamente nada para o usuário; não tem nenhum esclarecimento sobre o que digitar! Agora, observe, na figura 2.21b, quando uma mensagem explicativa é colocada, ANTES, da instrução de leitura: fica muito mais interativo com o usuário. 92 Figura 2.21b - Com a mensagem esclarecedora fica mais interativo Embora esses dois comandos de entrada/saída já tenham sido utilizados em exemplos anteriores, este item mostrou a real importância de suas utilizações para que os programas fiquem mais interativos com o usuário. Também é interessante enfatizar que a mensagem esclarecedora, ANTES do comando Leia deve ser com Escreva e não com Escreval, para que o cursor fique piscando imediatamente após a mensagem. As saídas desejadas pelos comandos Escreva/Escreval são separadas por vírgulas (,) dentro dos parênteses, exigido pela sintaxe. Observe o esquema abaixo, onde deseja-se exibir um texto e um valor numérico: Escreva("Digite o novo valor:", Valor) Comando de Saída Vírgula separadora texto (string entre aspas retas) variável Leia(Valor) Comando de Entrada Variável 93 2.16 - Arredondando Valores de Saída Observe a figura 2.22a; ela retrata uma saída semelhante à saída da figura 2.22b, reportando a saída do programa “ControleSalarial” do Exemplo 1, mas na segunda figura os dois valores finais estão arredondados, para um salário bruto de 2468.24 e desconto de 9.5%. Note que os resultados do desconto e do salário liquido foram, respectivamente, 234.4828 e 2233.7572 na primeira figura; isto é, ambos os valores com quatro casas decimais para os centavos, o que é meio estranho em qualquer moeda. Assim, é melhor apresentar os resultados monetários com duas decimais, como é de praxe nas operações financeiras. Para isto o Visualg oferece uma maneira bem simples de fazer esse arredondamento dentro do comando de saída Escreva/Escreval, na sintaxe: Valor:tamanho:decimais ▪ Valor é o valor real a ser formatado ▪ Tamanho: tamanho total do valor formatado ▪ Decimais: número de decimais desejado. Figura 2.22a - Saída do programa "ControleSalarial” sem formatação 94 Alterando as duas linhas de instruções para formatar com duas decimais, fica assim: Escreval("Desconto para INSS: ",Desc:8:2) Escreval("Salário líquido: ",SalLiq:5:2) O resultado dos valores, agora formatado, com duas decimais é visto na figura 2.22b. Figura 2.22b - Saída do programa "ControleSalarial” com formatação 95 2.17 - Mensagens de Erros ao Rodar o Programa Ao selecionar a opção “Executar” do menu principal, ou, simplesmente pressionando a tecla de atalho F9 da janela principal do Visualg, o interpretador da ferramenta inicia a leitura/interpretação/execução de cada linha do programa-fonte (pseudocódigo em portugol), a partir da primeira linha do programa principal, começando em “Inicio”. Caso exista algum erro o processamento é imediatamente interrompido, e será exibida uma janela mostrando o ocorrido, através de uma mensagem ao usuário. E como acontece em todas as linguagens, existem, basicamente, três tipos de erros que podem ocorrer num processo de criação/execução de programas em Visualg. ✓ Erro de Sintaxe ✓ Erro de Computação ✓ Erro de lógica (bug) 2.17.1 - Erro de Sintaxe Este tipo de erro ocorre quanto uma palavra reservada da linguagem não está escrita corretamente. Neste caso, ao ler/interpretar a palavra o interpretador não a reconhece; o processamento é interrompido de imediato, e uma mensagem é emitida ao usuário alertando para esse fato; e mostrando, também, o número da linha do programa onde ocorreu tal erro. Por exemplo, no programa “FuncaoTrigInversa” abaixo, ocorre um erro na linha de código Ang <- ArcSeno(S)*RD2GR onde o programa está atribuindo à variável Ang o valor do ângulo (em graus) cujo seno é digitado pelo usuário. Neste caso, o termo ArcSeno não existe para o Visualg como uma função interna; a palavra correta para esta função é ArcSen (sem a letra o no final). Ocorreu um erro de sintaxe! 96 Algoritmo "FuncaoTrigInversa" //Calcula e mostra a função inversa do seno de um ângulo. //Autor: Mário leite //------------------------------------------------------ Const RD2GR=57.29577951308232 //converte radianos para graus Var Ang, S: real Inicio Escreva("Digite o seno do ângulo: ") Leia(S) A cor fica preta normal (estranho) Ang <- ArcSeno(S)*RD2GR Escreval("Ângulo cujo seno é",S,": ",Ang," graus.") Escreval("") FimAlgoritmo A figura 2.23a mostra o resultado da tentativa de rodar o programa. Figura 2.23a - Erro de sintaxe no programa "FuncaoTrigInversa" 97 A figura 2.23a mostra a resposta do Visualg a esta situação, emitindo a mensagem “Variável ‘ArcSeno’ não foi encontrada”, e se “desculpando” por “não haver uma explicação para tal problema”, além de mostrar o número da linha onde tal erro ocorreu. Na verdade, ArcSeno não foi colocada no programa como uma variável; ela foi empregada erradamente pelo programador como uma função interna para retornar o valor do ângulo que possui um seno digitado pelo usuário; e mostra que o erro ocorreu na linha 10 do código-fonte do programa. O usuário tem a opção de clicar em um dos dois botões oferecidos: [Continuar] ou [Terminar]: se optar por continuar nada demais acontece (o sistema apenas dá uma piscada e continua como está); se clicar em [Terminar]] a execução termina e volta para a tela de edição, e o poderá fazer as correções necessárias. Corrigindo para o nome correto da função (ArcSen) o programa roda normalmente e exibe o resultado esperado. A figura 2.23b mostra o resultado do processamento após feita a correção. Algoritmo "FuncaoTrigInversa" //Calcula e mostra a função inversa do seno de um ângulo. //Autor: Mário leite //------------------------------------------------------ Const RD2GR=57.29577951308232 //converte radianospara graus Var Ang, S: real Inicio Escreva("Digite o seno do ângulo: ") Leia(S) Cor fica azul (palavra-chave correta) Ang <- ArcSen(S)*RD2GR Escreval("Ângulo cujo seno é",S,": ",Ang," graus.") Escreval("") FimAlgoritmo 98 Figura 2.23b - Saída correta do programa "FuncaoTrigInversa" Como foi comentado no código acima, quando o programador digita qualquer palavra-chave (que não seja um tipo de dado) o Visualg a coloca na cor azul (padrão); caso não fique desta cor o termo pode ter sido digitado de maneira incorreta; é uma forma bem rápida de corrigir o código, antes de tentar executar o programa! Um outro caso de erro de sintaxe é quando o programador quer fazer uma coisa, mas ordena outra para o computado; errando totalmente a sintaxe, não por um simples erro de grafia da palavra-chave, mas errando grosseiramente ao escrever algo que não existe na linguagem, mesmo com a boa intenção de fazer a coisa certa! Por exemplo, no programa “CalculaRaizQuadrada” abaixo ocorre um erro na linha de código R <- Sqrt(N), onde programador deseja atribuir à variável R o valor da raiz quadrada de um número N lido. 99 Algoritmo "CalculaRaizQuadrada" //Calcula e mostra a raiz quadrada de um número real. //Autor: Mário leite //--------------------------------------------------- Var N, R: real Inicio Escreva("Digite um número: ") Leia(N) R <- Sqrt(N) Escreval("Raiz quadrada de",N,":",R) Escreval("") FimAlgoritmo A figura 2.24a mostra a resposta do Visualg a esta situação, emitindo a mensagem de que “Variável ‘SQRT’ não foi encontrada”, se “desculpando” por “não haver uma explicação para tal problema”, e mostrando que o erro ocorreu na linha 9 do código-fonte. Na verdade, Sqrt não foi colocada no programa como uma variável; ela foi empregada, erradamente, pelo programador como uma função interna para extrair a raiz quadrada de um número digitado pelo usuário, tal como se faz na maioria das vezes, pois Sqrt é uma função interna de muitas linguagens de programação, justamente para este fim: extrair a raiz quadrada de um número real, não negativo; no caso a raiz quadrada de 142. Este é um vício de programação que pode ser normal, quando o usuário está acostumado a codificar em outra linguagem. 100 Figura 2.24a - Erro de interpretação num programa em Visualg O nome correto da função do Visualg para extrair a raiz quadrada de um número real não negativo é RaizQ. Observe agora, na figura 2.22b, quando se troca Sqrt por RaizQ no programa “CalculaRaizQuadrada”; o programa roda perfeitamente! Algoritmo "CalculaRaizQuadrada" //Calcula e mostra a raiz quadrada de um número real. //Autor: Mário leite //--------------------------------------------------- Var N, R: real Inicio Escreva("Digite um número: ") Leia(N) R <- RaizQ(N) Escreval("Raiz quadrada de",N,":",R) Escreval("") FimAlgoritmo 101 Figura 2.24b - Saida do programa sem erro de interpretação em Visualg 2.17.2 - Erro de Computação Aqui serão considerados os erros de “Falta de declaração de Variáveis”, e “Erros em cálculos matemáticos”. Ainda, considerado o programa “CalculaRaizQuadrada”, observe o código dele abaixo onde foi omitida a declaração da variável N. Algoritmo "CalculaRaizQuadrada" //Calcula e mostra a raiz quadrada de um número real. //Autor: Mário leite //--------------------------------------------------- Var R: real Inicio Escreva("Digite um número: ") Leia(N) R <- RaizQ(N) Escreval("Raiz quadrada de",N,":",R) Escreval("") FimAlgoritmo 102 Ao tentar rodar o programa é exibida a mensagem “Variável N não foi encontrada”, como mostra a figura 2.25a. Figura 2.25a - Erro na execução do programa; falta declarar variável E observe o que acontece quando o usuário digita um valor negativo (-142). Embora não seja erro de sintaxe, ocorre erro de operação matemática conhecida no jargão da computação como “Invalid floating point operation” (erro de cálculo em ponto flutuante - no caso, tentativa de extrair raiz quadra de um número negativo). Tal tipo de erro ocorre também em todas as situações em que a operação matemática resulte num overflow ou underflow (estouros de memória). A figura 2.25b mostra o erro cometido. 103 Figura 2.25b - Erro na execução do programa com estouro de memória 2.17.3 - Erro de Lógica (bug) Nestes casos NÃO É ERRO DO COMPUTADOR, e sim do programador que não criou o código-fonte corretamente para obter o resultado esperado. A “culpa” é exclusiva de quem criou o programa; nenhum sistema é capaz de detectar esse tipo de erro! Observe o programa abaixo, onde o objetivo é calcular exibir a soma dos números ímpares de uma série de números digitados pelo usuário. A entrada dos dados termina quando for digitado o número 0 (zero) . 104 Algoritmo "SomaImpares" //Soma apenas os números ímpares de uma lista digitada //Autor: Mário Leite //------------------------------------------------------- -------- Var j, Num, Soma: inteiro Inicio Soma <- 0 Num <- 9000 Enquanto (Num<>0) Faca Escreva("Digite um número inteiro [zero termina]: ") Leia(Num) Se(Num Mod 2 = 0) Entao Soma <- Soma + Num FimSe FimEnquanto Escreval("Soma dos números ímpares digitados: ", Soma) FimAlgoritmo Ao rodar o programa "SomaImpares" o resultado 218 é nostrado na figura 2.26; mas está INCORRETO! O resultado CORRETO seria 624 ao fazer a soma do números ímpares digitados: 3+37+45+19+467+53. O erro foi um bug do programa, na estrutura de decisão, onde testa se o número lido é ímpar: em vez de Se(Num Mod 2 <> 0) foi escrito Se(Num Mod 2 = 0), somando os pares, em vez dos ímpares! 105 Figura 2.26 - Resultado incorreto devido a um bug no programa 2.17.4 - Erro de Incompatibilidade de Tipos Observe o programa da figura 2.27a. Figura 2.27a - Erro na declaração de variáveis: incompatibilidade de tipo 106 Ao tentar rodar o programa da figura 2.27a o Visualg responde com uma mensagem de erro mostrada na figura 2.27b. Figura 2.27b - Mensagem de erro de incompatibilidade de tipo Por que ocorreu o erro ao tentar rodar o programa mostrado na figura 2.27b?! O processamento de somas algébricas e/ou multiplicação/divisão que contenta parcelas e/ou fatores do tipo real, sempre vai gerar 107 resultado do tipo real; então a variável que o armazenará tem que ser do tipo real. Na dúvida sobre o tipo de dado resultante, deve- se optar sempre por variáveis do tipo real; por isto foi gerada a mensagem. “Erro na atribuição de valores na variável AREA: REAL para INTEIRO. Para evitar esse erro, a variável area teria que ser declarada como real; a variável raio poderia continuar como inteiro. 2.17.5 - Erro de Instrução fora de área Na área de “Declarações” (de arquivos, de constantes, de variáveis e de registros - nesta ordem) ANTES de Inicio, não pode haver instruções. As instruções só podem ser digitadas entre Inicio e FimAlgoritmo”. Se alguma instrução for digitada na área de “Declarações”, o interpretador do Visualg emitirá uma mensagem de erro. Observe a figura 2.28a, que mostra o programa “AreaCirculo” no editor do Visualg, em local proibido (dentro da “Seção de Declarações”). Figura 2.28a - Programa “AreaCirculo” com instruções em local proibido 108 Ao tentar rodar o programa, dá um erro, como mostrado na figura 2.28b. Figura 2.28b - Alerta de erro na execução do programa “AreaCirculo” Observe na figura 2.28b, que já na primeira linha de instrução detectada fora do local permitido, dá erro na interpretação. E, caso fosse removida essa primeira linha, o erropersistiria na segunda, até que todas as linhas de instruções fossem removidas dessa área proibida para instruções. Agora, vamos remover essas linhas da “Seção de Declarações” e colocá-las no local correto: a partir do comando Inicio, como na figura 2.28c. 109 Figura 2.28c - Programa “AreaCirculo” com instruções em local correto Agora, o programa roda normalmente, e apresenta o resultado correto. (vide a saída na figura 2.28d) Figura 2.28d - Saída correta do programa “AreaCirculo” 110 Note que, agora, com as quatro linhas de instruções digitadas, corretamente, na “Seção de Comandos”, o programa rodou sem problemas, e mostrou o resultado desejado: a área do círculo de raio 4. Entretanto, devemos lembrar que o valor da área de um círculo, dado seu raio, pode ter valores diferentes um do outro. Isto acontece devido à constante universal PI, que pode ser empregada com um número de casas decimais bastante variável (até o final de 2019 PI havia sido calculado com mais de 31 trilhões de decimais). O identificador PI representa, exatamente, essa constante, cujo valor utilizado é 3.14159265358979 (com quatorze decimais). Deste modo, para utilizar o valor de 3.141592653589793 (com quinze decimais), o programa usou PII como identificador da constante, em vez de PI, pois PI é uma palavra reservada do Visualg. Outro detalhe a ser notado nas figuras 2.28a e 2.28c é que o nome do programa aparece como “semnome”; isto acontece porque o programa ainda não fora salvo num arquivo em disco. E embora o arquivo possa ser salvo com qualquer nome válido, uma boa prática é salvar o arquivo com o mesmo nome do programa. Assim, vamos salvar o programa no arquivo “AreaCirculo.alg” no seguinte local: D:/Livros/Livro9/Codigos, como mostra a figura 2.29a. 111 Figura 2.29a - Salvando o programa “AreaCirculo” no local desejado Figura 2.29b - Arquivo do programa “AreaCirculo” salvo em arquivo 112 2.17.6 - Erro de Falta de Terminadores “Estruturas de Controle” - que serão vistas no Capítulo 4 - são comandos compostos que permitem tomar decisões, e repetir um bloco de linhas de instruções. Em Visualg todas as estruturas de controle têm uma instrução de início e outra para indicar o seu término; assim, é muito comum acontecer do programador se esquecer, ou mesmo duplicar o terminador de uma dessas estruturas, causando erro na hora de executar o programa. Por exemplo, as estruturas de decisão começa com apalavra-chave Se e exige o terminador FimSe para indicar seu término; então, pode ocorrer que o programador se esqueça desse terminador.. Observe o programa “VerificaValor” na figura 2.30a, e o resultado na tentativa de executar o programa, na figura 2.30b, mostrando a mensagem: “Esperava encontrar FimSe”, indicando que faltou esse terminador na estrutura . Figura 2.30a - Código-fonte do programa “VerifValor” no editor 113 Figura 2.30b - Erro na execução do programa “VerifValor” Observa na figura 2.30b que, mesmo lendo corretamente o valor digitado, ocorreu um erro ao tentar “fechar” a estrutura, devido à falta do terminador FimSe. Agora, vamos introduzir um “pequeno” erro de digitação no programa: apenas deslocar o dois pontos (:) para depois das aspas, na instrução de leitura (primeira linha de código do programa): Escreva("Digite um valor" : ). veja como fica na figura 2.31a. O resultado da tentativa de execução do programa pode ser visto figura 2.31b. 114 Figura 2.31a - Código-fonte do programa “VerifValor” no editor Figura 2.31b - Erro na execução do programa “VerifValor” 115 Note que a mensagem de erro emitida pelo Visualg, na figura 2.31b, não esclarece bem a respeito do que provocou o erro “Não há explicação disponível para este problema”. Além disso, observe que nada apareceu na janela DOS; nenhum saída! Neste caso, o erro ocorreu devido à sintaxe errada de uma instrução de saída. Mensagens de erro assim (sem um esclarecimento real), pode acontecer; vai depender do programa e do contexto do código. Por isto, o usuário deve ter cuidado na digitação do código do programa. Observe o programa “MostraParesNaFaixa”, no editor do Visualg, mostrado na figura 2.32a. Figura 2.32a -Código-fonte do programa “MostraParesNaFaixa” 116 Na figura 2.32b o Visualg emitiu a mensagem “Esperava encontrar FimPara”, ao tentar rodar o programa “MostraParesNaFaixa”, indicando que esse terminador faltou na estrutura de repetição Para..FimPara (que será estudada no Capítulo 4). Entretanto, apareceu a instrução de fim de programa “FimAlgoritmo”, deixando dúvidas se essa instrução também tem erro além de mostrar outra mensagem “Não há explicação para este problema”! Na verdade, a explicação foi dada ao dizer que “não encontrou FimPara”. Portanto, o usuário deve ficar bem atendo na hora de digitar o código do programa no editor do Visualg, para evitar que ocorra erros que podem ser fáceis de evitar, mas, às vezes, difíceis de entender a mensagem. Figura 2.32b-Erro na execução do programa “VerifMostraParesnaFaixa” 117 2.18 - Medindo o Tempo de Processamento Um dos recursos bem interessante e bastante prático oferecido pelo Visualg é a medição do tempo de processamento de um bloco ou do programa todo. Este recurso é dado pelas instruções Cronometro on e Cronometro off. A primeira dispara o cronômetro (marca o início da medição) e a segunda desliga o cronômetro (marca o fim da medição). ... Cronometro on //aqui o cronômetro é ligado e o tempo começa a ser contado ... ... Cronometro off //aqui o cronômetro desliga e o tempo de processamento é exibido A figura 2.33 mostra o resultado da execução de um programa que gera alguns números randômicos pares. O tempo gasto para gerar esses números foi de 22s e 797ms; o resultado é exibido na “Área de visualização dos resultados”. Figura 2.33 - Resultado da medição do tempo de processamento 118 2.19 - Depurando Programas A depuração (debunggin) é muito importante quando estiver ocorrendo resultados estranhos ao rodar um programa. É um processo de encontrar e reduzir defeitos num programa; nesses defeitos estão incluídos aqueles tipos que previnem o programa de ser executado e aqueles que produzem um resultado inesperado. A depuração de um programa no Visualg é feita, pressionando a tecla F8 (para executar passo a passo as linhas de instruções) em vez da tecla F9, que executa todo o código sem paradas. E, embora exista o comando debug(expressão) para depurar uma linha de código, o uso de F8, em conjunto com breakpoint, é mais prático. Para ver isso na prática, vamos considerar o programa abaixo, denominado “CalculaMedia”, que lê quatro notas parciais de um aluno e calcula a média aritmética dessas notas, exibindo-a com apenas uma casa decimal. Para fazer o debugging de um programa em Visualg, basta criar um breakpoint na linha de código que pode estar ocorrendo o bug e pressionar F8 para ir executando o programa passo a passo. Por exemplo, no programa mencionado o resultado da média das notas 7.6, 8.5, 7.4 e 7.1 está apresentando um resultado estranho: 25.3, em vez de 7.5; conforme mostra a figura 2.34. 119 Figura 2.34 - Resultado incorreto do programa ”Calculamedia” Então, o programador deve desconfiar dos valores entrados, ou do cálculo da média. Desse modo, coloca-se um breakpoint na linha de instrução do cálculo da média, pressiona F8 para ir observando o fluxo do programa passo a passo (vide figura 2.35). Figura 2.35 - Executando o programa ”Calculamedia” passo a passo 120 Assim, o bug do programa pode ser encontrado, e a instrução reescrita corretamente, envolvendo a soma das nota com parênteses: media <- (nota1+nota2+nota3+nota4)/4Fazendo essa alteração, o resultado da média das quatro notas sairá correto, como mostra a figura 2.36. Figura 2.36 - Executando o programa ”Calculamedia” passo a passo 2.20 - Comentários Os comentários são fundamentais para documentar o código de uma rotina ou um bloco de instruções. Dependendo da linguagem de programação os símbolos para indicar um “comentário” podem variar; mas, no Visualg pode ser empregado um par de 121 barras paralelas inclinadas (//) para comentar uma linha, como também chaves { } para comentar um bloco de linhas. Os comentários são utilizados para explicar linhas de instruções de modo a esclarecer melhor a funcionalidade dentro do programa; como por exemplo, nas instruções abaixo. Soma (Nota1+Nota2+Nota3+Nota4) //Soma as notas Media Soma/4 //Calcula a média aritmética das notas Tudo que for digitado depois das duas barras (//) é ignorado pelo processador; mas é muito importante para esclarecer melhor o que está sendo feito. É claro que não se deve comentar o óbvio; no exemplo acima foi apenas para exemplificar o uso deste recurso em programação. Veja a expressão matemática abaixo. M = C(1+i)t Se não houver nenhum comentário para explicar melhor o que significa cada termo desta instrução, ficaria difícil entender o que se deseja com esta equação depois de passado algum tempo da criação do programa. As figura 2.37a e 2.37b mostram um programa de cálculo financeiro com as variáveis comentadas de duas maneiras diferentes. 122 Figura 2.37a - Variáveis comentadas em linhas separadas Os comentários são muito importantes para documentar os trechos mais complexos dos programas, e sempre devem aparecer nas aplicações. Isto é importante, pois esses trechos ficam mais explícitos para que nas manutenções futuras o programador possa entender melhor a lógica do programa. Para comentar um bloco de linhas basta colocá-lo entre chaves { }; por exemplo, comentar as variáveis do programa “Financeiro” mostrado acima. 123 Figura 2.37b - Variáveis comentadas em um bloco de linhas 2.21 - Exercícios Propostos 1 - Qual é a vantagem de se usar a “Barra de Ícones” do Visualg para executar uma ação na criação de um programa, sabendo que essas mesmas ações podem ser obtidas na “Barra do Menu Principal”? 2 - Qual é a diferença entre comandos e funções (internos) no Visualg? Dê exemplos. 3 - Se o Visualg não é uma linguagem real, qual é a sua importância no aprendizado de Linguagem de Programação? 4 - Existem erros no programa “AreaCirculo” escrito em Visualg. Mostre quais são esses erros. 124 Algoritmo "AreaCirculo" //Calcula a área de um círculos,dado o seu raio. //----------------------------------------------------- Var raio, area: inteiro Const: PI=3.14159265 Inicio Escreva("Digite o valor do raio do círculo: ") Leia(raio) area <- PI*raio^2 Escreva("Área do círculo: ", area) FimAlgoritmo 5 - Observe o programa abaixo, em Visualg: ele vai rodar?!. Explique! Algoritmo "AreaTriangulo" //Calcula a área de um triângulo dada sua base e altura. //----------------------------------------------------- Inicio Var B, h, Area: real Escreva("Digite o valor da base: ") Leia(b) b <- Abs(b) Escreva("Digite o valor da altura: ") Leia(h) h <- Abs(h) Area <- b*h Escreval("") Escreval("Área do triângulo:", Area) Escreval("") FimAlgoritmo 6 - Marque com V os identificadores válidos para variáveis e com F para os não válidos. A ( ) DevIR20 125 B ( ) AmanhaDeManhaVouPedirOCafePraNosDois C ( ) MédiaGeral D ( ) QteMaçãs E ( ) 2aNota F ( ) Nota2 G ( ) Cata_Vento H ( ) DevoluçãoIR20 I ( ) R$Ganho J ( ) Const 7 - Marque com V as alternativas que contenham instruções válidas (com resultados normais) e com F as que contenham instruções inválidas nos programas em Visualg, sabendo que as variáveis A, B e C são numéricas do tipo inteiro, e D do tipo logico. A ( ) Declare A, B, C: real B ( ) Var A, B, C, D: inteiro C ( ) A <- B =C D ( ) D <- A>C E ( ) C <- C > ( A+B) F ( ) A <- RaizQ(B/C) G ( ) A <- (A Mod A) H ( ) B <- (B Div C) I ( ) D <- nao(A>(B+C)) 8 - Se você pode codificar um programa diretamente numa linguagem real, por exemplo, Python, qual seria a vantagem de usar o Visualg, antes dessa codificação? 9 - Marque a única expressão INVÁLIDA no Visualg, com A=3, B=4 e C=Verdadeiro. A ( ) C <- (B > (RaizQ(B)/A*B)) B ( ) (A>B) e C ou (nao(A<=B) ) C ( ) (B<=A) ou C e (não.(A<=5)) 126 D ( ) (C>=B) e A<B E ( ) C <- (B<C) e (nao((nao(nao(nao((A+B)<C))))))) 10 - Observe o trecho de programa abaixo para calcular as duas raízes reais de uma equação do 2º grau do tipo ax2 + bx + c = 0, supondo que todas as variáveis tenham sido declaradas corretamente. As duas raízes, x1 e x2 SEMPRE serão mostradas num programa em Visualg? Explique sua resposta! ... Escreva("Digite o valor da constante a: ") Leia(a) Escreva("Digite o valor da constante b: ") Leia(b) Escreva("Digite o valor da constante c: ") Leia(c) x1<- (-b + RaizQ(b^2-4*a*c))/(2*a) x2<- (-b - RaizQ(b^2-4*a*c))/(2*a) Escreval("Primeira raiz:: ",x1) Escreval("Segunda raiz:: ",x2) ... 11 - Escreva os valores resultantes das expressões abaixo, sabendo que A=3, B=4 e C=5 (inteiros). A ( ) A + B/A B ( ) A + (B/A) C ( ) A > B D ( ) A <= B E ( ) A + RaizQ(B)/A*B ) F ( ) nao(A>B) e B<=C) G ( ) (B<=A) e (C>=B) ou (nao(A<=5)) H ( ) (C>=B) e (A<=B) I ( ) nao((nao(A>B) e (C=B)) ou (A<B)) J ( ) A <- (B<C) e (nao((nao(nao(nao(A+C)))))) 127 Capítulo 3 - Tipos de Dados no Visualg 3.1 - Introdução ao Capítulo Neste capítulo serão estudados os tipos de dados suportados pelo Visual; por exemplo, no programa "AreaTriangulo", dos “Execícios Propostos” do capítulo anterior, vimos a seguinte instrução, antes do Inicio do programa: Var b, h, Area: real Esta instrução declara (define) três variáveis do tipo real (b, b, Area), todas do tipo real, para armazenar valores numéricos com ou sem casas decimais. Em outras palavras, o comando Var define o tipo de dado que será armazenado naquele endereço de memória; isto é, o TIPO de dado das três variáveis. Do ponto de vista formal pode-se dizer que “um tipo de dado define uma área de memória com certas características e um conjunto de operações que sobre ela pode ser aplicado”. Um tipo de dado define uma faixa de valores permitida para operações. 3.2 - Tipos Primitivos de Dados De um modo geral os tipos primitivos podem ser agrupados em três grandes grupos: • Numérico • Caractere • Lógico O tipo Numérico abrange quaisquer valores que se traduzem em números, e se subdividem em duas categorias: inteiro e real. Por exemplo, para armazenar o número de filhos de um casal deve ser utilizado o tipo inteiro, uma vez que não existe por exemplo, 2.5 filhos: ou são 2 filhos ou são 3 filhos. Já o tipo real define uma 128 faixa de números que pode conter casas decimais e usados em quaisquer operações matemáticas, mas que não é o ideal, neste exemplo, para armazenar o número de filhos de um casal. O tipo Caractere, também conhecido como string (alfanumérico, texto, literal ou cadeia), define uma ampla faixa de valores com os quais só é possível efetuar uma única operação: a concatenação; junção de cadeias: “Ana “ + “Lúcia” = “Ana Lúcia”. Este tipo de dado não pode ser empregado em operações matemáticas. O tipo Lógico armazena apenas um dos dois possíveis valores lógicos: Verdadeiro ou Falso, e só empregado em expressõeslógicas. Dependendo da linguagem de programação, o tipo numérico pode ser subdivididos em outros para atender as necessidades da aplicação. Por exemplo, um valor numérico que não tem casa decimal é considerado um inteiro, mas, armazenar o número de filhos de um casal é um pouco diferente do que armazenar o número de habitantes da cidade de São Paulo. O tipo numérico é dividido em inteiros e reais; e mesmo assim estes ainda podem ser subdivididos em outros tipos para melhor atender as especificidades da aplicação, com a linguagem utilizada. O esquema da figura 3.1 mostra como os tipos de dados se apresentam, em termos gerais, independentemente de qualquer classificação secundária em uma linguagem formal de programação. Num programa qualquer, em pseudocódigo, essa figura fornece a base do uso desses dados nas operações. 129 Figura 3.1 - Tipos básicos de dados No caso do tipo inteiro (normal) suas características são as seguintes: • Faixa: -2147483648 a +2147483647 • Operações: suporta as quatro operações elementares e mais algumas permitidas pela Matemática; por exemplo, potenciação. O tipo real abrange o tipo inteiro e quaisquer valores que possuam casas decimais; isto é, o tipo real tem uma faixa de valores bem maior que a dos inteiros. • Faixa: -3.4x10-4932 a +3.4x104932 • Operações: suporta as quatro operações elementares e mais outras permitidas pela Matemática; por exemplo, raiz quadrada de apenas números não negativos dando como resultado um número real. 130 O tipo caractere, comumente chamado de string, define os dados que podem conter qualquer tipo de caractere. Entretanto, para indicar este tipo os valores têm que ser escritos entre aspas retas (" ") , e a única operação permitida é a concatenação. O tipo lógico (booleano) é aquele que armazena apenas um dos dois valores lógicos permitidos pela lógica formal: Verdadeiro ou Falso; e as operações têm que ser do tipo relacional, sempre dando como resultado um valor lógico. 3.3 - Tipos Complexos[12] Os tipos complexos são, na verdade, derivados dos tipos básicos primitivos; assim, por exemplo, pode existir uma matriz de números inteiros ou de caracteres, ou ainda uma estrutura (registro) com elementos de vários tipos básicos. Na linguagem C e nas suas correlatas, existe, adicionaçlmente, o tipo void, que não foi relacionado no esquema da figura 3.1; este é um tipo meio “esquisito”, pois representa um tipo “sem tipo sem valor”. Na verdade ele foi criado para justificar o “retorno” de uma rotina que não retorna nada; isto é, foi criado para que a linguagem C não precisasse trabalhar com rotinas chamadas procedimentos; bastante comuns em outras linguagens, e que não têm retorno. De qualquer forma, qualquer outro tipo de dado sempre será uma composição dos três tipos primitivos básicos: numérico, caractere, lógico. 3.4 - Os Tipos de Dados Considerados no Visualg No Visualg os tipos de dados utilizados são os tipos primitivos: • Numérico (inteiro e real) • Caractere (texto) • Lógico Variáveis do tipo inteiro possuem valores na faixa de - 2147483647 a +2147483647, o que nas outras linguagens é 131 chamado de “inteiro longo”. Por razões de controle interno, o limite inferior dessa faixa, no Visualg, é uma unidade maior que a considerada nas linguagens de programação formais, que é - 2147483648. Variáveis do tipo real seguem o mesmo padrão de faixa do tipo real da linguagem Pascal. Variáveis do tipo lógico só podem assumir dois valores: Verdadeiro ou Falso. O uso de qualquer um tipo de dado para uma variável vai depender, exclusivamente, da característica do seu conteúdo a ser manipulado dentro da lógica do programa. 3.5 - Declaração de Variáveis no Visualg Embora já tenha sido apresentados alguns exemplos de programas com declarações de variáveis, vamos formalizar este procedimento aqui neste item, e com detalhes adicionais. Como já foi mencionado, as variáveis representam endereços da memória RAM, e são utilizadas para armazenar dados e resultados de processamentos. E, como armazenam dados, é preciso que os tipos de dados de cada uma delas seja, previamente, declarado (definido) para que o interpretador do Visualg possa indicar à CPU a melhor maneira de fazer a alocação do endereço de memória. Assim, se uma determinada variável for declarada como sendo do tipo inteiro, então o valor 4.3578 não poderá ser armazenado corretamente nessa variável; certamente será truncado e considerado apenas 4, pois, as decimais serão ignoradas. Deste modo, é preciso prestar bem atenção nos tipos de dados das variáveis que serão usadas no programa. Todas as variáveis utilizadas num programa em Visualg TÊM que ser declaradas antes de serem inicializadas, ou lidas. O comando para declarar variáveis é a palavra-chave Var, obedecendo a sintaxe: 132 Var x1,x2,x3,..,xn: tipo A sintaxe acima declara as n-variáveis x como sendo de um determinado tipo de dado; isto é, TODAS de um mesmo tipo. Se fossem variáveis de tipos diferentes, teriam que ser declaradas em linhas separadas, para cada tipo. Var x1,x2,x3: inteiro X4, x5: real X6, x7, x8: caractere X9: logico Observe que na sintaxe de declaração usa-se apenas um Var para declarar TODAS as variáveis, mesmo que sejam de tipos deferentes, em linhas distintas. A figura 3.2a mostra como fica dentro do editor do Visualg as declarações dessas nove variáveis. Figura 3.2a - Declarando variáveis de um programa em Visualg É claro que, se executarmos o programa acima nada vai aparecer como resultado, pois na “Seção de Comandos” nada foi digitado, 133 como pode ser conferido na figura 3.2b; tanto na janela DOS (tela preta) quanto na janela da “Area de Visualização dos Resultados”. Figura 3.2b - Saída do programa: nada exibido Às vezes, o programador pode cometer erro ao declarar uma mesma variável mais de uma vez; e quanto isto acontece é emitida uma mensagem de aviso, como no caso abaixo, se a variável x7 fosse declarada mais de uma vez numa mesma linha (mesmo tipo de dado), ou em linha distinta com outro tipo de dado. Veja a figura 3.3. 134 Figura 3.3 - Erro na interpretação: variável declarada mais de uma vez Quando ocorre algum erro na interpretação (tentativa do Visualg em ler o comando) o programa trava, e é necessário clicar no botão [Terminar] para reparar o erro e reeditar a instrução corretamente. Clicar no botão [Continuar] não adianta nada, esses casos! 135 ❖ Exemplo 3.1 - Criar um programa que calcule e mostre a raiz cúbica de 12. A figura 3.4a e a figura 3.4b mostram, respectivamente, o programa “CalculaReizCubica12” no editor, em duas versões diferentes e com seus respectivos resultados na execução, em função das declarações das duas variáveis: num e raizCub. Figura 3.4a - Programa com problema de declaração de tipo errada 136 Neste caso, houve erro na tentativa de atribuir um resultado do tipo real [12^(1/3)] na extração da raiz cúbica de 12 a uma variável do tipo inteiro. Agora, declarando corretamente a variável raizCub numa linha separada, para o tipo real, não haverá erro na interpretação e o resultado será exibido normalmente, como pode ser confirmado na figura 3.4b. Figura 3.4b - Programa com saída norma 137 3.6 - Operadores e Operações Os operadores são símbolos utilizados para realizar cálculos, bem como instrumentos complementares usados para permitir ao usuário modificar, avaliar, comparar e checar o conteúdo das variáveis, auxiliando na montagem de fórmulas nas expressões numéricas e de cadeias de caracteres dentro de um algoritmo. Também são muito utilizados dentro de comandos simples e compostos. Embora possa existir vários tipos de operadores nas linguagens formais, eles podemser divididos em apenas três grandes categorias básicas: Aritméticos, Relacionais e Lógicos: Operador Símbolo Tipo O que faz Unário – Unário Inverte o sinal de valor numérico. Potenciação ^ Binário Eleva um número a uma potência. Divisão real / Binário Divide dois números reais, dando um resultado real, se o divisor não for 0. Multiplicação * Binário Multiplica dois valores reais, dando como resultado um valor real. Divisão inteira Div Binário Divide dois números inteiros, dando um resultado inteiro, se o divisor não for 0. Por exemplo, 7 Div 2 = 3, Resto da divisão Mod Binário Dá o resto inteiro da divisão inteira entre dois números inteiros. Por exemplo: 7 Mod 2 = 1. Adição + Binário Soma dois valores reais, resultando em um valor real. Subtração – Binário Subtrai um valor real de outro, dando como resultado um valor real. Tabela 3.1 - Operadores Aritméticos na hierarquia das operações 138 Operador Símbolo O que faz Igual a = Verifica se duas expressões, ou conteúdo de duas variáveis, possuem o mesmo valor. Diferente de <> Verifica se duas expressões, ou conteúdo de duas variáveis, possuem valores diferentes. Menor que < Verifica se uma expressão, ou conteúdo de uma variável, é menor que o conteúdo de outra. Maior que > Verifica se uma expressão, ou conteúdo de uma variável, é maior que o conteúdo de outra. Menor ou igual <= Verifica se uma expressão, ou conteúdo de uma variável, é menor ou igual ao conteúdo de outra. Maior ou igual >= Verifica se uma expressão, ou conteúdo de uma variável, é maior ou igual ao conteúdo de outra. Tabela 3.2 - Operadores Relacionais 139 Operador Símbolo Tipo O que faz Negação nao Unário Inverte o valor lógico de uma expressão lógica, de modo que se for Verdadeiro passa a ser Falso, e se for Falso passa a ser Verdadeiro. Conjunção e Binário Liga dois valores lógicos, de modo que o resultado só será Verdadeiro se ambos forem Verdadeiro, caso contrário, se pelo menos, um dos valores for Falso resultará Falso. Disjunção ou Binário Liga dois valores lógicos, de modo que o resultado será Verdadeiro se pelo menos, um destes valores for Verdadeiro, e será Falso se ambos forem Falso. Disjunção Exclusiva xou Binário Liga dois valores lógicos, de modo que o resultado será Verdadeiro se um dos dois valores for Falso e o outro Verdadeiro; e será Falso se ambos os valores forem Verdadeiro ou ambos Falso. Tabela 3.3 - Operadores Lógicos na hierarquia das operações Nota: Embora exista uma hierarquia para os operadores, os parênteses sempre são os mais prioritários, podendo alterar a ordem de operação numa expressão. O que estiver dentro dos parênteses mais internos será primeiramente executado, obedecendo o sentido lógico operativo na expressão: “da esquerda para a direita”. Conclusão: Tentar, por exemplo, colocar um valor do tipo real num local preparado para receber um tipo inteiro é como se quisesse colocar o conteúdo de um copo cheio d’água numa 140 xícara de cafezinho; vai derramar! Mas, embora o contrário seja possível - colocar o conteúdo de uma xícara num copo - seria um desperdício de espaço! Portanto, escolher o tipo de dado mais compatível com o conteúdo a ser armazenado (alocação estática, adotada pelo Visualg) é bom, e pode economizar espaço na RAM. Os operadores aritméticos são empregados em instruções que envolvem cálculos matemáticos entre duas expressões numéricas, produzindo um resultado numérico. Os operadores relacionais são empregados em comparações de duas expressões, e o resultado só pode ser num valor lógico: Verdadeiro ou Falso. Os operadores lógicos[13] são empregados para unir duas expressões de tal modo que o resultado é um valor lógico, modificado de acordo com os valores lógicos de cada expressão, e dando como resultado um dos dois valores possíveis: Verdadeiro ou Falso; tal como nas chamadas proposições. Considere a seguinte frase: “O leite é preto”; apesar de ser estranha para nós é uma proposição, já que seu valor é Falso assim como a frase “o leite é branco”, cujo valor lógico é Verdadeiro. Já a frase exclamativa “Olha que coisa mais linda, mais cheia de graça!” não é uma proposição, pois não permite um valor lógico como resultado. Portanto, somente são consideradas proposições as frases que podem ter como resultado um valor lógico. A hierarquia das operações ou das expressões aritméticas segue as regras da matemática; e assim como tal, deve-se sempre observar a única regra básica para toda e qualquer formula: 1. Primeira Regra : sempre da esquerda para a direita; 2. Segunda Regra : precedência (ou prioridade): 1a Parênteses (...): tudo que estiver entre os parênteses será executado primeiro. 2a Exponenciação: dentro de uma formula será executada prioritariamente. 141 3a Multiplicação e Divisão: será executado o operador que aparecer primeiro. 4a Soma e Subtração: será executado o operador que aparecer primeiro. Observe a instrução: X <- 100*2/5 (com x do tipo real) O valor armazenado na variável X após executar a instrução 100*2/5, será 40; pois o processamento será feito assim: 1º) 100 será multiplicado por 2 ==> 200 2º) 200 será dividido por 5 ==> 40 3º) o valor 40 será atribuído à variável X. Os operadores relacionais são utilizados sempre dentro de expressões de comparações; e os valores a serem comparados devem ser sempre dos tipos: Numéricos (inteiros ou reais) ou do tipo caractere. E o resultado dessa comparação sempre retornará um valor do tipo lógico (Verdadeiro ou Falso). Um dos operadores, talvez o mais importante para a programação, e que não foi mostrado nas tabelas anteriores, é o operador de atribuição, cujo símbolo em Visualg é representado por <- (sinal de “menor que” seguido do sinal de subtração, Atribuir à variável Soma o valor de 0 (inicializar essa variável): Soma <- 0 • Incrementar a variável Soma de 1: Soma <- Soma + 1 • Atribuir à variável Raiz a raiz quadrada de um número N: Raiz <- RaizQ(N) • Atribuir à variável x1 o resultado de expressão: x1 <- (- b+RaizQ(Delta))/(2*a) Nota: Observe nos exemplos de atribuições acima, que o termo Raiz pode ser utilizado como identificador de variável. Mas, RaizQ (apenas com a inclusão do Q) não pode ser identificador de variável, pois é uma palavra reservada do Visualg (função interna) que retorna a raiz quadrada de um número real não negativo. 142 Os operadores relacionais e lógicos são sempre utilizados em operações que envolvem comparações, e onde os resultados dessas comparações sempre retornam valores lógicos. Estes tipos de operadores são geralmente empregados dentro de comandos de desvios condicionais (que serão vistos com mais detalhes no próximo capítulo). Resumo: Como as variáveis podem ser consideradas “caixas” que contém “algo” para ser guardado na memória RAM do computador, o Tipo de Dado seria o “tipo de material” dessa “caixa”; portanto, cada material deve ser guardado em caixas do tipo adequado. Então, fazendo uma analogia com a sua natureza: se o material (valor) é líquido a caixa tem que ser de um material (tipo) que suporte líquido. Em termos de tamanho: se o material for muito pequeno, seria um desperdício utilizar uma caixa muito grande; caso contrário, se o material for algo muito grande a caixa também deve ser de tamanho compatível, se não o material não caberá nela! • Exemplo 3.2 - Criar um programa em Visualg para realizar as principais operações matemáticas. No programa “OperacoesMatematicas” são lidos dois números: num1 e num2; ambos inteiros e maiores que zero. 143 Algoritmo "OperacoesMatematicas" //Faz operações matemáticasem função de um menu de //opções. //Autor: Mário Leite //------------------------------------------------------ Var Num1, Num2: real Soma, Subt, Mult, Divide, Pote, Raiz: real Inicio Escreva("Entre com o primeiro número: ") Leia(Num1) Escreva("Entre com o segundo número [diferente de zero]: ") Leia(Num2) Escreval("") Escreval("Adição: ") Soma <- (Num1+Num2) Escreval(Num1," +",Num2," = ",Soma) Escreval("") Escreval("Subtração: ") Subt <- (Num1-Num2) Escreval(Num1,"-",Num2," = ", Subt) Escreval("") Escreval("Multiplçicação: ") Mult <- (Num1*Num2) Escreval(Num1,"-",Num2," = ", Mult) Escreval("") Escreval("Divisão: ") Divide <- (Num1/Num2) Escreval(Num1, " /", Num2, " = ", Divide) Escreval("") Escreval("Potenciação: ") Escreva("Entre com a base: ") Leia(Num1) Escreva("Entre com o expoente [diferente de zero]:") Leia(Num2) Pote <- (Num1^Num2) 144 Escreval(Num1, " ^", Num2, " = ", Pote) Escreval("") Escreval("Radiciação: ") Escreva("Entre com o número: ") Leia(Num1) Escreva("Entre com índice da raiz [número positivo]:") Leia(Num2) Raiz <- (Num1^(1/Num2)) Escreval("Raiz índice",Num2,"de",Num1,"=", Raiz) Escreval("") FimAlgoritmo //fim do programa "OperacoesMatematicas" A figura 3.5 mostra a saída do programa “OperaçoesMatematicas”; entrando com os dados solicitados nas respectivas operações Figura 3.5 - Saída do programa “OperacoesMatematicas” 145 ❖ Exemplo 3.3 - Dadas quatro notas parciais de um aluno, calcular a média escolar com um número de casas desejado pelo usuário. O programa “MediaEscolar” , cujo código é mostrado na figura 3.6, é uma opção de solução em Visualg. Figura 3.6 - Código-fonte do programa “MediaEscolar” no editor A figura 3.7a mostra a saída do programa no na “janela DOS”, e a figura 3.7b nas “Areas de Visualizações”. 146 Figura 3.7a - Saída do programa “MediaEscolar” (janela DOS) 147 Figura 3.7b - Saída de “MediaEscolar” (janelas de visualizações) 3.7 - Exercícios Propostos 1 - Para que servem os tipos de dados nos programas? 2 - Além dos três tipos básicos de dados, por que existem outros? 3 - É possível fazer cálculos com o tipo Lógico? Explique! 4 - Qual tipo de dado deve ser utilizado para armazenar um número de telefone? Explique! 5 - O programa abaixo, em Visualg, não vai rodar. Explique o porquê. 148 Algoritmo "DivideNumero" //Mostra o resultado da divisão de um número por outro. //----------------------------------------------------- Var num, den, div: inteiro Início Escreva("Digite o numerador: ") Leia(num) Escreva("Digite o denominador: ") Leia(den) div <- num/den EscrevaLn("Área do triângulo:", Area) FimAlgoritmo 6 - Observe o trecho de programa abaixo para calcular as duas raízes reais de uma equação do segundo grau do tipo ax2 + bx + c = 0, e suponha que as três constantes e as raízes x1 e x2 tenham sido declaras corretamente. As duas raízes, x1 e x2, SEMPRE serão mostradas com seus valores corretos? Explique sua resposta! ... Escreva("Digite o valor da constante a: ") Leia(a) Escreva("Digite o valor da constante b: ") Leia(b) Escreva("Digite o valor da constante c: ") Leia(c) x1 <- (-b + RaizQ(b^2-4*a*c))/2*a x2 <- (-b - RaizQ(b^2-4*a*c))/2*a Escreval("Primeira raiz:: ",x1) Escreval("Segunda raiz:: ",x2) ... 7 - Quais serão as respectivas saídas do programa “MostraResultados”, quando for executado? 149 Algoritmo "MostraResultados" Var A, B, C: real Início A <- 3 B <- 4 C <- 5 Escreval(A + B/A) Escreval(A +(B/A)) Escreval(A > B) Escreval(A <= B) Escreval(A + RaizQ(B)/A*B) Escreval(nao(A>B) e (B<=C)) Escreval(((B<=A) e (C>=B)) ou ((nao(A<=5)))) Escreval((C>=B) e (A<=B)) Escreval(nao((nao(A>B) e (C=B)) ou (A<B))) Escreval((A<=(B<C)) e (nao((nao(nao(nao(C<(A+C)))))))) FimPrograma 8 - Marque a única expressão INVÁLIDA em Visualg, sabendo que A=3, B=A e C=Falso. A ( ) C <- B > (RaizQ(B)/A*B) B ( ) (Falso) e (B >A) C ( ) C <- (B=A) ou (C (e (nao(A<=5))) D ( ) C <- (A+B) - B E ( ) C <- (B<C) e (nao((nao(nao(nao((A+B)<C))))))) 9 - Declare variáveis para armazenar: devolução do imposto de renda de 2020, nome de um cliente, total de vendas no mês de dezembro, resposta do usuário se confirma ou não a exclusão de um cliente do arquivo e o total de alunos do sexo feminino de um colégio. 150 10 - Crie um programa em Visualg que leia o nome de um aluno, suas quatro notas parciais e mostre a média ponderada dessas notas, sabendo que: peso da primeira nota é 2, da segunda nota é 3, da terceira nota é quatro e da quarta nota é seis. 11 - Observe o programa abaixo, em Visualg. Seu objetivo é mostrar a velocidade final de um corpo abandonado a uma distância H da superfície, considerando o valor da aceleração da gravidade uma constante de valor 9,80665 m/s². Entretanto, mesmo estando correta a expressão da queda livre, o programa não vai rodar. Explique porque! Algoritmo "QuedaLivre" Var V, H, T: real Const G=9.80665 Inicio T <- 32,5 V = (1/2)*G*T^2 Escreval("Velocidade do corpo em 32,5 segundos: ",V) FimAlgoritmo 12 - Marque com C os valores do tipo caractere, com I os valores do tipo inteiro, com R as variáveis do tipo real e com L os do tipo lógico. A ( ) 4.66667 B ( ) “4.66667” C ( ) -43 D ( ) Falso E ( ) “56” F ( ) “Boa noite” G ( ) Verdadeiro H ( ) 3.14128265 151 Capítulo 4 - Estruturas de Controle Visualg 4.1 - Introdução ao Capítulo Observando a maioria dos programas mostrados até agora, podemos notar que as instruções são executas sequencialmente, sem desvios. É como se não houvesse nenhuma necessidade de orientar o fluxo do programa para determinado local do programa, tal como acontece no programa “Armazenamentos”, que vai atribundo valores a variáveis e mostrando mostrando os resultados de maneira sequencial. Algoritmo "Armazenamentos" //Exemplo simples de atribuições/armazenamentos e //escritas. //----------------------------------------------------- Var A, B, C, D: inteiro Inicio D 0 Escreval("Valor de D: ",D) A 2 Escreval("Valor de A: ", A) B 3 Escreval("Valor de B: ", B) C 5 Escreval("Valor de C: ", C) C C + 1 Escreval("Valor de C: ",C) D A + C Escreval("Valor de D: ",D) FimAlgoritmo 152 A execução do programa começa na palavra Algoritmo e vai interpretando/executando linha por linha até o final em FimAlgoritmo. Não há qualquer desvio do fluxo, pois não há nenhuma decisão a ser tomada, e nem mesmo repetição de comandos; é um programa inteiro com instruções sequenciais. Mas, na prática, isto não acontece, pois, em situações reais sempre aparece condições a serem analisadas e que, dependendo da resposta, o fluxo do programa pode seguir caminhos diferentes. Uma outra situação é quando é necessário escrever uma instrução repetidas vezes como, por exemplo, exibir cinco vezes a frase “Hoje vai chover”. Uma solução simples, seria: Escreval("Hoje vai chover: ") Escreval("Hoje vai chover: ") Escreval("Hoje vai chover: ") Escreval("Hoje vai chover: ") Escreval("Hoje vai chover: ") Embora as cinco instruções acima resolva o problema, esta não é uma boa solução; é bem ineficiente, caso fosse repetir não cinco, mas cinquenta, ou cinco mil vezes a mesma frase. Para resolver problemas mais complexos do que repetir simples instruçõessequenciais, ou tomar decisões impostas pelo lógica do programa, é que existem as chamadas “Estruturas de Controle”. 4.2 - Estruturas de Controle Com os tipos de dados e operadores apresentados no capítulo anterior, podemos definir um conjunto de estruturas, baseado na lógica, que permite ao programador criar soluções bem elegantes, utilizando instruções e comandos para solucionar o problema apresentado. Essas estruturas definem controles que se convencionou chamar de “comandos compostos”, e podem ser classificados em três tipos fundamentais: 153 • Estruturas de Decisão (desvios condicionais) • Estrutura de Seleção (estrutura Case) • Estruturas de Repetição (loops) Nota: A expressão “comando” aqui neste livro se refere à uma ordem ou ação específica escrita no código para que o processador possa executá-la. A expressão “instrução”, embora muitos autores a empreguem no sentido de “comando”, será utilizada num sentido mais amplo para indicar o que o processador deve fazer numa linha de código do programa, que pode envolver vários comandos e expressões. Por exemplo, X <- RaizQ(Num) + FunFatorial(n) + Soma/j. ✓ RaizQ é uma função interna para extrair a raiz quadrada de um número não negativo. ✓ FunFatorial é um comando (função definida pelo usuário), para calcular o fatorial. ✓ Soma/j é uma operação de divisão que compõe uma instrução. A linha de código X<-RaizQ(Num) + FunFatorial(n) + Soma/j pode ser chamada de instrução, ou comando (sem consequências graves), mas, correto seria considerar LINHA DE CÓDIGO. Mas, existem casos em que uma coisa se confunde, rigorosamente, com a outra: por exemplo, a instrução LimpaTela (que também é chamada de COMANDO, sem retorno), é por si só, uma linha de código. Operador de Atribuição Variável Linha de código Instruções X <- RaizQ(Num) + FunFatorial(n) + Soma/j Função interna Função criada pelo programador Expressão matemática 154 Muitos autores chamam uma Instrução de “Comando”; outros chamam de “Comando” os procedimentos internos de uma linguagem (uma função interna que não tem retorno). Por exemplo, para límpar a tela do monitor de vídeo: ClrScr (em Pascal), Cls (em VB), clc (em SciLab) LimpaTela (em Visualg), etc. Todas estas palavras-chave, nas suas respectivas linguagens, podem ser chamadas de COMANDO. Também, as palavras- chave de leitura, tais como: Read (em Fortran), Read (em VB), readline (em PHP), Read e ReadLn (em Pascal), input( em Python e em SciLab), Leia (em Visualg). Para a escrita temos: Print (Em Basic), Write e WriteLn (em Pascal), printf (em SciLab), print (em PHP e em Python), println (em Julia), Console.WriteLine (em VB.net) e Escreva (em Visualg). Resumindo: TODAS as palavras-chave que indicam uma ordem expressa e sem retorno, podem ser consideradas COMANDOS. 4.2.1 - Estruturas de Decisão Estes tipos de estruturas de controle também são conhecidos como “Desvios Condicionais”, provocam um desvio no fluxo natural do programa, ao ser detectada alguma condição a ser analisada. E podem ser divididos em três tipos: ▪ Estrutura de Decisão Simples (Desvio Condicional Simples) ▪ Estrutura de Decisão Composto (Desvio Condicional Composto) ▪ Estrutura de Decisão Encadeado (Desvio Condicional Encadeado) 4.2.1.1 - Estrutura de Decisão Simples Os comandos de desvios condicionais simples formam estruturas de controle em que a decisão sobre a direção do fluxo do 155 programa é condicionada a apenas uma alternativa, de acordo com o valor lógico resultante da condição analisada. Se(condição) Entao Linha1 Linha2 Linha3 linhas de código executadas se condição Verdadeiro ... LinhaN FimSe A “Estrutura de Decisão Simples” funciona da seguinte maneira: Quando o fluxo do programa depara com um Se(condição)..FimSe a expressão lógica de condição é executada; se o resultado for Verdadeiro todas as instruções entre Se e o terminador FimSe serão executas. Caso contrário, nenhuma dessas instruções serão executadas e o fluxo do programa seguirá normalmente DEPOIS do terminador FimSe. O programa “VerifPar1” a seguir, ilustra o mecanismo de execução desse tipo de desvio condicional. Palavras-chave que indicam início da estrutura de decisão. Palavra-chave que indica fim da estrutura de decisão. 156 Algoritmo "VerifPar1" Var num, rest: inteiro Inicio LimpaTela Escreva("Digite um número inteiro e positivo: ") Leia(num) Num <- Abs(Int(num))//garante que Num seja inteiro e não negativo rest <- (Num Mod 2) Se(Rest=0) Entao Escreval("O número", Num, " é par.") FimSe Escreval("") FimAlgoritmo Num e num, Rest e rest para o Visualg é a mesma coisa, pois a ferramenta não é case sensitive como algumas linguagens de Programação (C, Python, SciLab, Java). O programa “Verif”Par1” roda normalmente; e um exemplo de saída pode ser visto na figura 4.1a. 157 Figura 4.1a -Um exemplo de saída do programa “VerifPar1” Observe que o programa “VerifPar1” atende ao que foi proposto: verificar se um dado número digitado é par. Então, se o número digitado for par uma mensagem será exibida ao usuário esclarecendo; ENTRETANTO, embora atenda ao proposto, ele não atende BEM, pois, se o número não for par nada será informado ao usuário. Isto deixa meio “capenga” a lógica da programação, como pode ser comprovado na figura 4.1b. 158 Figura 4.1b - Outro exemplo de saída do programa “VerifPar1” 4.2.1.2 - Estrutura de Decisão Composta No item anterior, o programa “VerifPar1”, embora esteja perfeitamente correto (mostra a mensagem quando o número digitado é par), não é completamente eficaz, pois caso o número digitado não seja par (como no caso da figura 4.1b), nenhuma mensagem é mostrada, e o usuário não fica inteiramente satisfeito com o seu desempenho. Assim, para tornar uma estrutura de decisão mais eficiente e eficaz, complementando a informação em outras situações, é que existe a “Estrutura de Decisão Composta”, que oferece a alternativa de código para quando a condição testada resultar num valor falso. Neste caso temos duas alternativas, sendo uma delas obrigatória. 159 A sintaxe deste tipo de estrutura é mostrada no esquema a seguir... condição Verdadeiro ? Se(condição) Entao Linha11 Linha12 sim Linha13 executa estas instruções ... Linha1N Senao Linha21 Linha22 não Linha23 executa estas instruções ... LinhaN FimSe Então, agora, reutilizando o programa “VerifPar1”, introduzindo a estrutura de “Desvio Condicional Composto”, e renomeando-o para “VerifPar2”, ficando do seguinte modo: 160 Algoritmo "VerifPar2" Var num, rest: inteiro Inicio LimpaTela Escreva("Digite um número inteiro e positivo:") Leia(num) Num <- Abs(Int(num rest <- (Num Mod 2) Se(Rest=0) Entao Escreval("O número", Num, " é par.") Senao Escreval("O número", Num, " não é par.") FimSe Escreval("") FimAlgoritmo Agora, com a alternativa de instruções para condição Falso, o programa ficou muito mais interativo com o usuário, oferendo duas possíveis respostas para a análise do número digitado. Nota: Algumas linguagens de programação oferecem um terceiro tipo de Estrutura de Decisão, que muitas vezes é chamado de “Estrutura de Decisão Encadeada”, do tipo: Se(condição) Então Senão Se(condição1) Então ... Senão Se(condição2) Então ... FimSe O Visualg ainda não oferece esse tipo de estrutura, mas ele pode ser simulado com a utilização de vários Se(condição)... aninhados. 161 Observe, agora, na figura 4.2, com o emprego da “Estrutura de Decisão Composta”, como fica a saída do programa, alterado, e compare com a saída da figura 4.1b. Figura 4.2 - Exemplo de saída do programa “VerifPar2” Observe o código do Exemplo 4.1 abaixo, que calcula a média final de um aluno, em que a “Estrutura de Decisão Encadeada” foi simulada no Visualg. ❖ Exemplo 4.1 - Calcular a média de um aluno em função de quatro notas parciais, e do exame (se for necessário). O programa “CalculaMediaFinal” é uma solução para o que se pede no Exemplo 4.1, observando, nesta solução, que temos uma “Estrutura de Decisão Composta”, aninhada (dentro) de uma outra mais externa. Esse tipo de situação é bastante comum, quando se tem condições a serem testadas dentro de outra condição mais externa. Note que embora não possua, explicitamente, comandos compostos para estruturas de decisão 162 encadeada, os comandos Se(condição)..Entao..Senao podem ser agrupados para fazer uma simulação perfeita nessas situações. Algoritmo "CalculaMediaFinal" //Calcula a média de quatro notas, com “Estruturas de //de Decisões” aninhadas. //Encadeada”. //Autor: Mário Leite //----------------------------------------------------- Var Nota1,Nota2,Nota3,Nota4: real Soma, Media, Exame: real Inicio Escreva("Digite a primeira nota: ") Leia(Nota1) Escreva("Digite a segunda nota: ") Leia(Nota2) Escreva("Digite a terceira nota: ") Leia(Nota3) Escreva("Digite a quarta nota: ") Leia(Nota4) Soma Nota1 + Nota2 + Nota3 + Nota4 Media Soma/4 Escreval("Média: ", Media) Escreval("") //salta linha Se(Media>=7.0) Entao Escreval("Aprovado") Senao Escreva("Digite a nota do exame: ") Leia(Exame) Media (Media*4 + Exame*6)/10 Escreval("Média final: ", Media) Se(Media>=6.0) Entao Escreval("Aprovado") Senao Escreval("Reprovado") FimSe FimSe FimAlgoritmo 163 4.2.2 - Estrutura de Decisão Selecionada Esta estrutura, também conhecido simplesmente como “Estrutura de Seleção”, “Desvio Selecionado” ou ainda “Estrutura Case”, é utilizada para desviar o fluxo de um programa no qual são oferecidos várias condições representadas por casos, comparados a um valor previamente conhecido, onde para cada Caso existe um bloco de instruções a ser executado, dependendo da comparação ser Verdadeiro. A sintaxe textual para esse tipo de estrutura é mostrada no esquema abaixo. Escolha(variável/expressão) Caso1 Linha11 Linha12 ... Linha1N Caso2 Linha21 Linha22 ... Instrução2N --- --- CasoN LinhaN1 LinhaN2 LinhaN3 ... LinhaNM OutroCaso LinhaA LinhaB ... LinhaZ FimEscolha 164 Escolha(variável/expressão): marco de início da estrutura. Caso´s: valores que serão comparados com (variável/expressão). OutroCaso: início do bloco de instruções a sere executado se nenhum Caso anterior for Verdadeiro. FimEscolha: marco de término da estrutura. (variável/expressão) é um valor qualquer, previamente conhecido, que será comparado com valores estabelecidos em cada “Caso”. O processamento começa lendo (variável/expressão); em seguida compara o seu conteúdo com cada valor definido nos “casos”. No primeiro caso que for verdadeiro seu bloco de instruções será executado, e em seguida o fluxo continuará após o marco FimEscolha. Se nenhum dos casos for verdadeiro então serão executadas as instruções entre OutroCaso e FimEscolha; por isto, neste tipo de estrutura este último bloco alternativo pode se tornar vital para a lógica do programa. Esta estrutura deve ser empregada em situações em que o usuário precisa escolher uma alternativa de execução quando são oferecidas várias alternativas como, por exemplo, em um menu de opções de ações, como no caso do famoso e tradicional CRUD: : “1-Incluir”, “2-Alterar”, “3-Excluir”, “4-Pesquisar”, “5-Finalizar”. ❖ Exemplo 4.2 - Definir o status de um aluno em função de n notas parciais obtidas. 165 Algoritmo "StatusAluno1" //Define a situação acadêmica de um aluno, em função da //média final obtida. //Autor: Mário Leite //----------------------------------------------------- Var j, n: inteiro Nota, Soma, Media, Exame: real Inicio Repita Escreva("Número de notas[min 2-max 10]" :") Leia(n) Ate((n>=2) e (n<=10)) Escreval("") Soma <- 0.00 //inicializa o somatório das notas Para j De 1 Ate n Faca //loop numérico para ler Repita //valida cada nota digitada Escreva("Digite a nota #",j,": ") Leia(Nota) Ate((Nota>=0)e(Nota<=10)) //fim das validações Soma <- Soma + Nota //acumula soma das notas FimPara //fim do loop de leitura das notas Media <- Soma/n //calcula a média Escolha Media Caso 3.0 Ate 5.0 Escreval("Conselho de Classe") Caso 5.1 Ate 6.9 Escreval("Em Exame") Caso 7.0 Ate 10.0 Escreval("Aprovado") OutroCaso Escreval("Reprovado") FimEscolha FimAlgoritmo //fim do programa "StatusAluno1" 166 O trecho do programa a seguir, mostra como funciona a “Estrutura De Seleção”. Leia(Letra) //tipo caractere Escolha Letra Caso "A" Escreval("Esta é a opção da letra A") Caso "B" Escreval("Esta é a opção da letra B") Caso "C" Escreval("Esta é a opção da letra C") Caso "D" Escreval("Esta é a opção da letra D") Caso "E" Escreval("Esta é a opção da letra E") OutroCaso Escreval("Esta é a opção de nenhuma vogal") FimEscolha Também é possível variações em caso de múltiplas escolhas, em situações de Casos com mais de um valor dentro da opção: Caso V1 Ate V2, como é mostrado no trecho de programa a seguir... 167 ... Escreva("Digite uma nota do aluno de 1 à 10: ") Leia(x) //tipo real Escolha x Caso 3.0 Ate 5.0 Escreval("Nota está Ruim.") Caso 5.1 Ate 6.5 Escreval("Nota Satisfatório.") Caso 6.6 Ate 8.5 Escreval("Nota Boa.") Caso 8.6 a 10.0 Escreval("Nota Ótima.") OutroCaso Escreval("Nota fora da faixa ou valor inválido! ") FimEscolha Escreva("Digite uma letra correspondente a vogal: ") Leia(Letra) //tipo caractere Escolha Letra Caso "A","B" Escreval("Esta é a opção da letra A ou B.") Caso "C","D" Escreval("Esta é a opção da letra C ou D.") Caso "E" Escreval("Esta é a opção da letra E.") OutroCaso Escreval("Esta é a opção de nenhuma vogal") FimEscolha ... 4.2.3 - Estruturas de Repetição (loops) Estas estruturas oferecem comando para controlar os laços (loops) de repetições de blocos de instruções. Neste caso, o bloco 168 de instruções será continuamente executado até que (ou enquanto) uma condição seja atendida. Elas podem ser classificadas em dois grupos, dependendo do tipo de condição a ser testada: ▪ Loops Lógicos ▪ Loop Numérico 4.2.3.1 - Loop Lógico Com Teste no Início Este é o tipo de loop lógico mais empregado nos programas, por ser bem intuitivo. O esquema abaixo mostra a sua sintaxe. {Inicializações} Palavra-chave que indica início da estrutura Enquanto (condição) Faca Linha1 Linha2 Linha3 ... ... LinhaN FimEnquanto Palavra-chave que indica fim da estrutura Instruções a serem executadas enquanto condição for Verdadeira 169 Nota: {Inicializações}, embora não faça parte da sintaxe da estrutura, é um bloco de linhas de código que deve anteceder a entrada do fluxo do programa na estrutura de repetição. E nesse bloco TEM que existir alguma linha de código que envolva a condição, de modo que a torne Verdadeiro, para que oprograma possa “entrar” no loop. Se, por caso, condição já for Falso no bloco de instruções o programa desviará e não executará as linhas de código do loop. Então, é NECESSÁRIO que condição seja Verdadeiro, previamente, para que o loop seja executado, pelo menos uma vez. Outro detalhe FUNDAMENTAL, é que deve existir alguma linha de código dentro das executadas no loop que o incremente, para que em algum momento condição se torne Falso; nesse instante o laço é rompido e o fluxo do programa volta ao seu percurso normal, na primeira linha de código APÓS o terminador FimEnquanto. Portanto, esse tipo de loop lógico depende diretamente de duas premissas: uma linha de código para inicializar condição com valor Verdadeiro e uma outra para realimentar o loop, de modo que condição se torne Falso em algum momento. Se a primeira premissa não for atendida o loop não será executado; se a segunda premissa não existir, as linhas de código dentro da estrutura serão executadas indefinidamente, produzindo um loop “infinito” (eterno). Ao ler o comando Enquanto(condição) o programa executará todas as linhas de código dentro da estrutura, enquanto condição for Verdadeiro. No momento em que condição de tornar Falso o fluxo seguirá normalmente após o terminador FimEnquanto. Os dois casos a seguir ilustram três situações de uso da estrutura Enquanto(condição)..Faca..FimEnquanto;. a primeira sem a 170 devida inicialização de condição, a segunda sem a realimentação do loop e a terceira com a sintaxe correta. ❖ Exemplo 4.3 - Somar os números digitados pelo teclado, enquanto não digitar 0. Algoritmo "SomaNumerosDigitados" //Soma os números digitados pelo teclado, enquanto não digitar 0 (zero). //Autor: Mário Leite //----------------------------------------------------- Var Num, Soma: real Cont: inteiro Inicio LimpaTela Cont <- 0 Soma <- 0 Enquanto (Num<>0) Faca Escreva("Digite um número [zero encerra]: ") Leia(Num) Soma <- Soma + Num Cont <- Cont + 1 Escreva("Soma parcial: ", Soma) Escreval("") FimEnquanto Escreval("") Escreval("") Escreval("Soma total dos",(Cont-1)," números válidos digitados:", Soma) FimAlgoritmo Primeira versão da solução: Sem a devida inicialização da condição Aqui a variável Num deveria ser inicializada com um valor diferente de zero. 171 A figura 4.3a mostra a saída do programa “SomaNumerosDigitados" considerando-o sem a linha de código de inicialização Verdadeira para a condição (Num<>0). Note que, por isto, o loop não foi executado, e o resultado saiu errado! Figura 4.3a - Saída da primeira versão do programa: SEM a inicialização da condição 172 Algoritmo "SomaNumerosDigitados" //Soma os números digitados pelo teclado, enquanto não digitar N (zero). //Autor: Mário Leite //----------------------------------------------- --------------------------- Var Num, Soma: real Cont: inteiro Inicio LimpaTela Cont <- 0 Soma <- 0 Num <- 999 //inicializa convenientemente a variável de controle do loop Enquanto (Num<>0) Faca Soma <- Soma + Num Cont <- Cont + 1 Escreva("Soma parcial: ", Soma) Escreval("") FimEnquanto Escreval("") Escreval("") Escreval("Soma total dos", (Cont-1)," números válidos digitados:", Soma) FimAlgoritmo Segunda versão da solução: SEM realimentação do loop Nesta segunda versão NÃO FOI considerada a realimentação do loop; e neste caso o programa fica rodando sem parar (em loop eterno), não produzindo uma saída definitiva pois, as linhas de código dentro do loop ficam sendo executadas continuamente, sem parar. A figura 4.3b mostra que o valor da variável Soma ficará eternamente sendo calculado... Aqui deveria uma linha de código para realimentar o loop. 173 Figura 4.3b - Saída da Segunda versão do programa: SEM a realimentação do loop 174 Algoritmo "SomaNumerosDigitados" //Soma os números digitados pelo teclado, enquanto não digitar 0 (zero). //Autor: Mário Leite //----------------------------------------------------- Var Num, Soma: real Cont: inteiro Inicio LimpaTela Cont <- 0 Soma <- 0 Num <- 999 Enquanto (Num<>0) Faca Escreva("Digite um número [zero encerra]: ") Leia(Num) Soma <- Soma + Num Cont <- Cont + 1 //realimentação do loop Escreva("Soma parcial: ", Soma) Escreval(“”) FimEnquanto Escreval("") Escreval("") Escreval("Soma total dos",(Cont-1)," números válidos digitados: ",Soma) FimAlgoritmo Terceira versão: correta; COM a inicialização da condição e COM a realimentação do loop A figura 4.3c mostra a saída correta do programa "SomaNumerosDigitados". 175 Figura 4.3c - Saída da versão Correta do programa: COM inicialização e COM realimentação 4.2.3.2 - Loop Lógico com Teste no Final Este é o segundo exemplo de loop lógico; isto é, uma estrutura de repetição em que uma instrução lógica (condição) deve ser testada para que o loop se desenvolva. Mas, ao contrário do loop “Enquanto..Faça..FimEnquanto” que pode não ser executado nenhuma vez, este é executado sempre pelo menos uma vez. Isto acontece porque o teste da condição fica no final do loop, e não no início, como naquele. Este tipo é muito utilizado quando se quer validar alguma entrada de dados; por exemplo, impedir que o usuário entre com um número negativo para calcular seu fatorial. O loop se repete ATÉ que a entrada seja um número 176 maior ou igual a zero. Sua sintaxe esquemática é mostrada abaixo: Indica início da estrutura Repita Linha1 Linha1 Linha3 ... ... LinhaN Ate(condição) ❖ Exemplo 4.4 - Calcular a soma dos N primeiros números naturais. Terminador da estrutura. Condição a ser testada. estrutura. Linhas de código que serão executadas até que condição seja Verdadeiro. 177 Algoritmo "CalculaSomaNaturais1" //Calcula a fatorial de um número, fazendo validação. //Autor: Mário Leite //----------------------------------------------------- Var j, N, Soma: inteiro Inicio Escreva("Quantos números naturais serão somados?: ") Leia(N) Repita Escreva("Quantos números naturais serão somados?: ") Leia(N) Escreval("") Ate(N>1) Soma <- 0 j <- 1 Enquanto (j<=N) Faca Soma <- Soma + j j <- j + 1 FimEnquanto Escreval("") Escreval("Soma dos", N, " primeiros números naturais: ",Soma) FimAlgoritmo A figura 4.4 mostra uma ´possível saída do programa "CalculaSomaNaturais1" 178 Figura 4.4 - Saída do programa "CalculaSomaNaturais1" Nota: É importante frisar que os testes da expressão que analisa a condição nos dois tipos de loop lógico são expressões que se equivalem logicamente em termos de teste da condição. Enquanto(x<=y) <==> Ate(x>y) O programa "CalculaSomaNaturais2" tem o mesmo propósito que o anterior: calcular e mostrar a soma dos N primeiros números naturais. Entretanto, neste caso, foi utilizada a estrutura de repetição Enquanto..Faca..FimEnquanto para fazer a validação da entrada. 179 Algoritmo "CalculaSomaNaturais2" //Calcula a fatorial de um número, fazendo validação. //Autor: Mário Leite //----------------------------------------------------- Var j, N, Soma: inteiro Inicio N <- -999 //inicialização conveniente para entrar no loop Enquanto (N<=1) Faca Escreva("Quantos números naturaisserão somados?: ") Leia(N) Escreval("") FimEnquanto Soma <- 0 j <- 1 Enquanto (j<=N) Faca Soma <- Soma + j j <- j + 1 FimEnquanto Escreval("") Escreval("Soma dos", n, " primeiros números naturais: ",Soma) FimAlgoritmo 4.2.3.3 - Loop Numérico Este loop é de um tipo não lógico; e muitas vezes, também é chamado de “Loop Automático” pois, ele inicializa e incrementa a variável do tipo inteiro que o controla, automaticamente. Este é o tipo de loop mais indicado quando se deseja repetir um bloco de linhas de código, sabendo a priori, quantas vezes a repetição será executada; isto é, se for conhecido o valor inicial e o valor final da variável de controle. Neste caso as repetições acontecerão até atingir o número de vezes previamente definido na própria estrutura; a sintaxe textual é mostrada no esquema a seguir... 180 {Inicializações} Para VarCont De Início Ate Fim [Passo <p>] Faca Linha1 Linha2 Linha3 ... LinhaN FimPara VarCont É a variável de controle do loop, que por tradição são utilizadas as letras minúsculas i, j, k, l, m, n. Início Valor inicial inteiro assumido por VarCont. p Valor inteiro do incremento da variável de controle. Se p não for definido é assumido o padrão 1; mas neste caso a palavra-chave Passo não pode aparecer. Fim Valor máximo inteiro que a variável de controle pode assumir. A respeito deste tipo de loop, é MUITO IMPORTANTE observar o seguinte: ✓ NÃO EXISTE instrução de realimentação; a realimentação é 1 ou dada por Passo p. Também NÃO EXISTE uma instrução específica para inicializar a variável de controle no bloco de {Inicializações} como havia nas duas estruturas anteriores. A inicialização da variável de controle do loop é estabelecida na própria estrutura, e é sempre um valor numérico inteiro. Bloco de instruções a ser repetido. 181 ✓ NÃO PODE ser atribuído nenhum valor à variável de controle (VarCont) dentro do loop, pois seu valor só deve ser alterado pela própria estrutura. ✓ É permitido criar um loop dentro de outro; este caso define os chamados loops aninhados, e todas as instruções do laço mais interno são integralmente executadas prioritariamente para cada valor da variável de controle do laço mais externo. ❖ Exemplo 4.5 - Contar de 1 até 100, de 2 em 2. Para Cont De 1 Ate 100 Passo 2 Faca //contará valores de 1 à 100 de 2 em 2 Escreval(Cont) //mostra conteúdo de Cont em cada linha FimPara ❖ Exemplo 4.6 - Contar o número de tipos de caracteres que existe em uma frase. Algoritmo "ContaCaracteresNaFrase" //Conta os caracteres de uma frase: letras (maiúsculas //minúsculas), espaços,números e caracteres especiais. //----------------------------------------------------- Var j,n,ContMai,ContMin,ContEspa: inteiro ContNum,ContEspe,CodCar: inteiro Frase, Car: caractere Cond1, Cond2, Cond3, Cond4: logico Inicio Escreva("Digite a frase: ") Leia(Frase) n <- Compr(frase) ContMai <- 0 ContMin <- 0 ContEspa <- 0 ContNum <- 0 182 ContEspe <- 0 Para j De 1 Ate n Faca Car <- Copia(Frase,j,1) //pega um caractere CodCar <- Asc(Car) Cond1 <- ((CodCar>=65) e (CodCar<=90)) Cond2 <- ((CodCar>=97) e (CodCar<=122)) Cond3 <- (CodCar=32) //espaço em branco Cond4 <- ((CodCar>=48) e (CodCar<=57)) Se(Cond1) Entao ContMai <- ContMai + 1 Senao Se(Cond2) Entao ContMin <- ContMin + 1 Senao Se(Cond3) Entao ContEspa <- ContEspa + 1 Senao Se(Cond4) Entao ContNum <- ContNum + 1 Senao ContEspe <- ContEspe + 1 FimSe FimSe FimSe FimSe FimPara Escreval("Resumo dos caracteres encontrados:") Escreval("----------------------------------") Escreval("Número de letras maiúsculas: ", ContMai) Escreval("Número de letras minúsculas: ", ContMin) Escreval("Número de espaços encontrados: ", ContEspa) Escreval("Número de dígitos numéricos: ", ContNum) Escreval("Número de caracteres especiais: ", ContEspe) Escreval("Número total de caracteres da frase: ", n) Escreval("") FimAlgoritmo//fim do programa "ContaCaracteresNaFrase" 183 Nota: Observe no programa “ContaCaracteresNaFrase”, que se não fossem aplicadas as devidas indentações no bloco de “{Verificação do tipo de caractere da frase}”, seria muito difícil entender a lógica da programação para fazer o que se pede. Portanto, em TODOS os locais onde existem estruturas de controle (seja ela do tipo que for) as INDENTAÇÕES devem ser colocadas, e o espaço em cada uma delas deve ser 3 ou 4; nem menos e nem mais, para não ficar pequena e nem grande demais!. A figura 4.5 mostra um exemplo de saída do programa "ContaCaracteresNaFrase". Figura 4.5 - Saída da execução do programa "ContaCaracteresNaFrase" 184 4.3 - Aninhamento de Decisões Usando Se's Esta é uma das técnicas de programação muito adotada pela maioria dos usuários nos algoritmos, e recomendada pelos professores, pois os alunos ficam mais “afiados” na lógica. E, embora o emprego intenso de vários comandos Se..Entao usando o desvio SIMPLES junto com o desvio COMPOSTO, possa exigir um esforço computacional adicional, esta técnica ajuda muito na compreensão da lógica dentro de programas mais complexos. Observe o exemplo abaixo, onde existem vário desvios condicionais dentro de um mais externo, para escrever a situação acadêmica final de um aluno, em função da média de n notas parciais ou, se precisar da nota de um exame final. ❖ Exemplo 4.7 - Mostrar a situação acadêmica final de um aluno, em função de notas parciais e/ou do Exame final. O programa "StatusAluno2" é uma solução para o problema do Exemplo 4.7, mostrando o status acadêmico de um aluno, após calcular sua média de quatro notas parcial e verificar se ele vai necessitar de fazer o Exame Final para ser aprovado. Algoritmo "StatusAluno2" //Dá o status de um aluno em função da média/exame. //----------------------------------------------- Var Nota, Soma, Media, Exame: real j: inteiro Inicio Soma <- 0.0 Para j De 1 Ate 4 Faca Repita Escreva("Entre com a nota ", j, ": ") Leia(Nota) Ate(Nota>=0) e (Nota<=10)) Soma <- Soma + Nota 185 FimPara Escreval("") //salta linha Media <- Soma/4 Se(Media>=7.0) Entao //aprovado direto Escreval("Aprovado direto: ", Media) Senao //tem que fazer exame Repita Escreva("Entre com a nota do Exame: ") Leia(Exame) Ate((Exame>=0) e (Exame<=10)) FimSe Media <- (Media+Exame)/2 Se(Media>=5) Entao Escreval("Aprovado por exame: ", Media) Senao Escreval("Reprovado: ", Media) FimSe Escreval("") FimAlgoritmo 4.4 - Indentações Um programa de computador, seja ele codificado em qualquer linguagem, é um texto puro; porém, não deve ser escrito tal como um poema, ou um artigo sobre um assunto científico, ou mesmo como uma carta comercial ou pessoal. O texto do código-fonte é composto de ordens dadas ao tradutor para que ele as converta em linguagem de máquina. E embora ao tradutor não interesse como ele está escrito, pois o que interessa é a sintaxe correta, o programador deve se preocupar em manter o texto elegante e bem legível. Indentações são espaços - de dois a quatro - que o programador deve colocar para evidenciar as instruções sujeitas a uma estrutura; seja ela de decisão, seleção ou repetição. No caso de “Estruturade Decisão”, observe o trecho de programa abaixo. 186 Leia(a) Leia(b) Se(b<>0) Entao c a/b Escreval(a,"dividido por ",b,"=", c) Senao Escreval("Operaçãoimpossível!") FimSe Indentações Observe o código-fonte do programa “MostraMedia” a seguir; ele está correto mas sem indentações, além de faltar mensagens esclarecedoras nas entradas; isto o torna meio confuso, com legibilidade muito ruim e sem a devida interação com o usuário. Algoritmo "MostraMedia" Var Nota1,Nota2,Nota3,Nota4,Soma,Media: real Inicio Leia(Nota1) Leia(Nota2) Leia(Nota3) Leia(Nota4) Soma <- (Nota1 + Nota2 + Nota3 + Nota4) Media <- Soma/4 Escreval("Média das notas: ", Media) Se(Media<7) Entao EscrevaLn("Reprovado") Senao Escreval("Aprovado") FimSe FimAlgoritmo 187 O programa “Loops” abaixo está correto, mas sua legibilidade é simplesmente terrível! Algoritmo "Loops" //Programa sem indentação //------------------------------------- Var i,j,k,l,x,y: inteiro Inicio Escreva("Digite um valor para y: ") Leia(y) Para i De 1 Ate 10 Faca x <- y Para j De 1 Ate 20 Faca Para k De 1 Ate 30 Faca Para l De 1 Ate 40 Faca x <- x + 1 FimPara FimPara FimPara FimPara FimAlgoritmo Pergunta: Quantas vezes a instrução x x+1 será executada? A análise é bem difícil sem as indentações necessárias. 4.5 - Exercícios Propostos 1 - Para que servem os loops? 2 - Qual é a diferença fundamental entre um loop com teste no início e um loop com teste no final? 3 - Mostre uma vantagem e uma desvantagem de um loop lógico quando comparado com um loop numérico. 4 - Mostre um laço com um erro de lógica, e a consequência desse erro. 188 5 - Crie um programa que calcule as raízes quadradas de dez números digitados pelo usuário. 6 - Repetir o que foi pedido no exercício anterior, agora, porém, deixando o usuário digitar a quantidade de números desejada. 7 - Crie um programa para verificar se um caractere digitado é uma letra. 8 - Deseja-se criar um programa em que seja exigido declarar: variáveis, constantes e registros. Mostre como seriam colocadas essas declarações num programa em Visualg. 9 - Qual valor de Soma será mostrado no programa abaixo? Explique a resposta. Algoritmo "CalculaSoma" Var j, Soma: inteiro Inicio Soma <- 0 j <- 1 Enquanto (j>1) Faca Soma <- Soma + j Escreval(Soma) j <- j + 1 FimEnquanto Escreval("") Escreval("Valor da soma: ",Soma) FimAlgoritmo 10 - Quantas vezes a variável k será exibida ao executar o programa "MostraVezes"? 189 Algoritmo "MostraVezes" Var k, Soma: inteiro Inicio Soma <- 0 k <- 0 Enquanto (Soma < 0) Faca Escreval(k) Soma <- Soma + 2 FimEnquanto Escreval("") FimAlgoritmo A ( ) 0 B ( ) 1 C ( ) 2 D ( ) 3 E ( ) 4 11 - O programa “CalculaIMC”, abaixo, tem um erro. Qual? Algoritmo "CalculaIMC" //Calcula o IMC (Indice de Massa Corpórea) de um adulto //Autor: Mário Leite //------------------------------------------------------- Const IMC=10 Var Peso, Altura: real Inicio Escreva("Digite o peso: ") Leia(Peso) Enquanto (Peso<=36) Faca //arbitra um peso mínimo para uma pessoa adulta Escreva("Digite o peso [mínimo 36]: ") Leia(Peso) Escreval("") FimEnquanto Escreva("Digite a altura: ") 190 Leia(Altura) Enquanto ((Altura<1.30) e (Altura>2.60)) Faca Escreva("Digite a altura: ") Leia(Altura) Escreval("") FimEnquanto IMC <- Peso/(Altura^2) Se(IMC<=16) Entao Escreval("Magreza grave") FimSe Se((IMC>16) e (IMC<=17)) Entao Escreval("Magreza moderada") FimSe Se((IMC>17) e (IMC<=18.5)) Entao Escreval("Magreza leve") FimSe Se((IMC>18.5) e (IMC<=25)) Entao Escreval("Saudável") FimSe Se((IMC>25) e (IMC<=30)) Entao Escreval("Sobrepeso") FimSe Se((IMC>30) e (IMC<=35)) Entao Escreval("Obesidade leve") FimSe Se((IMC>35) e (IMC<=40)) Entao Escreval("Obesidade severa") FimSe Se(IMC>40) Entao Escreval ("Obesidade mórbida") FimSe Escreval("") FimAlgoritmo //fim do programa "CalculaIMC" 12 - Pelo Teorema de Euler[11] sobre os poliedros convexos com V vértices, A arestas e F faces, vale a seguinte relação: V-A+F=2. O programa “VerifPoliedro” verifica qual poliedro em questão 191 e quantas faces ele possui. Mas falta linhas de código no programa para que ele fique mais correto. Quais linhas de código você adicionaria? Algoritmo "VerifPoliedro" //Verifica qual poliedro está sendo considerado e mostra sua quantidade de //faces. //Autor: Mário Leite //----------------------------------------------------- Var V, A, F: real Resp: logico Inicio Escreva("Digite o número de vértices do poliedro [4-6-8-12-20]: ") Leia(V) Escreval("") //salta linha Escreva("Digite o número de arestas do poliedro [6-12-30]: ") Leia(A) Escreval("") Resp Falso F 2 + A - V Se((V=4) e (A=6)) Entao Escreval("Tetraedro:", F, " faces") Escreval("Forma face: Triângulo") Resp Verdadeiro Senao Se((V=8) e (A=12)) Entao Escreval("Hexaedro:", F, " faces") Escreval("Forma face: Quadrado") Resp Verdadeiro FimSe Se((V=6) e (A=12)) Entao Escreval("Octaedro:", F, " faces") Escreval("Forma face: Triângulo") Resp Verdadeiro FimSe Se((V=20) e (A=30)) Entao Escreval("Dodecaedro:", F, " faces") Escreval("Forma face: Pentágono") 192 Resp Verdadeiro FimSe Se((V=12) e (A=30)) Entao Escreval("Icosaedro:", F, " faces") Escreval("Forma face: Triângulo") Resp Verdadeiro FimSe FimSe FimAlgoritmo //fim do programa "VerifPoliedro" 193 Capítulo 5 -Trabalhando com Vetores 5.1 - Introdução ao Capítulo Os vetores são muito importantes no ensino de Programação, uma vez que podem servir, até, como uma introdução a assuntos mais complexos de Estrutura de Dados. Além disto, é um assunto que sempre ajuda o programador a resolver problemas que envolvem dados indexados, permitindo criar soluções mais eficientes e mais eficazes, estendendo o conceito de variáveis. Neste capítulo os vetores são apresentados de maneira bem simples e com bastante exemplos de aplicações práticas em programas com o Visualg. 5.2 - Conceitos Básicos Nos capítulos anteriores os armazenamentos, manipulações e acesso aos endereços de memória foram todos baseados, exclusivamente, com variáveis simples. Isto é, variáveis que só podem armazenar um único valor em cada momento específico; pois esse tipo de variável não pode armazenar mais de um valor ao mesmo tempo. Neste capítulo será estudada uma classe de variáveis que podem manipular muitos valores ao mesmo tempo, com a definição dos chamados Vetores[14] que, na prática ,pode ser considerado uma “lista de valores ordenados e de um mesmo tipo de dado”. Os vetores representam uma classe especial de variáveis que, tendo apenas uma referência nn memória, podem armazenar e manipular muitos valores de um mesmo tipo de dado. Esta classe, de um modo mais geral, é chamada de array e também conhecida como matriz, variável composta, variável subscrita ou indexada, e define uma estrutura homogênea; isto é, os valores manipulados 194 por esse tipo de variável devem ser TODOS de um mesmo tipo de dado. A utilização de vetores em programação faz-se necessário quando é preciso manipular muitos valores de mesma origem, evitandotrabalhar com muitas variáveis. Por exemplo, numa situação típica de controle escolar, em que se deva verificar a situação acadêmica de um aluno em função de quatro notas que ele obteve ao longo de quatro meses. Caso fosse utilizar apenas variáveis simples, seria necessário criar quatro variáveis diferentes para que cada uma delas armazenasse uma nota diferente. Além disto, poderia ser necessário criar mais duas variáveis extras: uma para armazenar a soma das quatro notas e uma outra para armazenar a média das notas. Com a utilização de vetores, para armazenar e manipular as quatro notas parciais seria necessário criar apenas uma variável. E, embora na prática da programação, seja usual ainda, criar uma variável para guardar a soma dessas notas e uma outra para a média. seria possível usar o próprio vetor para armazenar, também, essas outras duas variáveis extras. O que significa que com apenas UMA variável seria possível controlar as notas, a soma e a média dessas notas! Portanto, todas as vezes que se deseja manipular valores de uma mesma origem (espécie) o uso de vetores torna a programação bem mais eficiente. A figura 5.1a mostra um esquema ilustrativo de um vetor que controla oito notas em Física de um aluno. Figura 5.1a - Vetor de notas de um aluno Fisica Nota1 Nota2 Nota3 Nota4 Nota5 Nota6 Nota7 Nota8 Física[1] Física[2] Física[3] Física[4] Física[5] Física[6] Física[7] Física[8] 195 O esquema da figura 5.1b mostra, mais detalhadamente, o que significa cada nota do aluno em termos vetoriais, supondo Fisica o nome do vetor, e como ficariam as oito notas obtidas com os seguintes valores: 7.2, 7.4, 7.0, 6.9, 7.1, 6.8, 7.3 e 7.5, respectivamente. Figura 5.1b - Elementos do vetor Fisica[ ] Suponha que o aluno peça vista da prova, e na correção o professor descobre que cometeu um erro de 0.1 ao somar os pontos obtidos nas questões: a quarta nota seja 7.0 em vez de 6.9 como havia publicado. Assim, o novo valor (7.0) deverá ser atribuído à quarta nota do aluno. A figura 5.2 mostra o esquema de como isto seria feito, indicando os itens que compõem o vetor Fisica[ ] no ambiente do Visualg. 196 elemento: lê-se assim “Fisica de 4” Fisica[4] 7.0 atribuição do novo valor ao elemento nome do vetor: Fisica índice do elemento: 4 Figura 5.2 - Itens de um elemento de vetor Fisica = [ 7.2, 7.4, 7.0, 7.0, 7.1, 6.8, 7.3, 7.5 ] vetor elementos do vetor alterado Nota: Em algumas literaturas os vetores são apresentados esquematicamente na vertical como na figura 5.1b. Entretanto, esta representação é apenas uma maneira de visualizar melhor, “fisicamente”, esses elementos matemáticos. Teoricamente, um vetor “vertical” é uma matriz que possui várias linhas e apenas uma coluna; e um vetor horizontal é uma matriz de apenas uma linha e várias colunas. 5.3 - Operações Elementares com Vetores As operações com vetores seguem as regras da Matemática e da Lógica, obedecendo a hierarquia em uma operação; por exemplo, tomando como exemplo o vetor Fisica[ ]. ✓ Somar: Fisica[6] + Fisica [3] = 6.8 + 7.0 ==> 13.8 ✓ Subtrair: Fisica [6] - Fisica [3] = 6.8 - 7.0 ==> -0.2 ✓ Dividir: Fisica [6] / Fisica [3] = 0.9714285 ✓ Multiplicar: Fisica [6] * Fisica [3] = 47.6 197 ✓ Elevar a uma potência: Fisica [3]^2 = 49.0 ✓ Extrair a raiz: RaizQ(Fisica [6]) = 2.6076809 ✓ Comparações: Fisica [3] > Fisica [6] ==> Verdadeiro ✓ Comparações: nao(Fisica [3] > Fisica [6]) ==> Falso Resumindo: as operações matemáticas e lógicas podem ser aplicadas aos elementos de um vetor, observando o tipo de dado. Entretanto, é importante frisar que a manipulação de vetores tem que ser elemento a elemento; não é possível, manipular um vetor de uma vez só, e nem fazer atribuições de vetor para vetor. Por exemplo, considere que as oito notas em Química, do mesmo alunos, fossem reunidas num vetor chamado Quimica[ ]. Quimica = { 7.2, 7.4, 7.0, 7.0, 7.1, 6.8, 7.3, 7.5 } Com os mesmos valores das notas em Física (com a quarta nota corrigida), e que fosse comparar o desempenho nas duas disciplinas, com a instrução abaixo: Quimica = Fisica !!??? ISTO NÃO PODE ser feito. Para fazer essa comparação tem que comparar elemento a elemento com estrutura de decisão dentro de um loop, como no fragmento a seguir... 198 ... EhIgual <- Verdadeiro Para j De 1 Ate 8 Faca Se(Quimica[j] <> Fisica[j]) Entao EhIgual <- Falso Interrompa FimSe FimPara Se(EhIgual) Entao Escreval("Respectivas notas de Física correspondem às de Química") Senao Escreval("Respectivas notas de Física não correspondem às de Química") FimSe 5.4 - Declaração de Vetores no Visualg Embora não sendo uma variável simples, os vetores também devem ser declarados ANTES de serem manipulados; esta é uma exigência das linguagens de programação tradicionais, e de algumas mais atuais. Por exemplo, declarar o vetor VetNum[ ] para armazenar nove valores inteiros. A declaração é feita no Visualg, dentro da “Seção de Declarações das variáveis” da seguinte maneira: Var VetNum: vetor[1..9] de inteiro Nome do vetor Declara vetor Tipo de dado do vetor Comando de declaração Faixa dos índices Na “faixa dos dados” 1 indica “índice do primeiro elemento” e 9 o “índice do último elemento” do vetor. Assim, o número de elementos (tamanho) do vetor é 9. 199 Nota: Em algumas linguagens de programação o índice inicial dos elementos de um vetor é 0 (zero), mas, no Visualg começa com 1, como na lógica humana de ordenação. 5.5 - Atribuição Direta Considerando o vetor VetNum[ ] mencionado anteriormente, com nove elementos inteiros, esta operação pode ser vista no programa "AtribuicaoDireta" onde são atribuídos nove valores inteiros, predeterminados: um a cada elemento desse vetor, como é mostrado no programa abaixo. Algoritmo "AtribuicaoDireta" //Armazena nove número inteiros por atribuição direta. //Autor: Mário Leite //--------------------------------------------------- Var VetNum: vetor[1..9] de inteiro Inicio VetNum[1] <- 2 VetNum[2] <- 15 VetNum[3] <- 11 VetNum[4] <- 0 VetNum[5] <- -7 VetNum[6] <- 16 VetNum[7] <- 8 VetNum[8] <- 9 VetNum[9] <- -1 FimAlgoritmo 200 5.6 - Atribuição por Leituras Individualizadas Neste caso as atribuições serão feitas com nove leituras; uma para cada elemento do vetor, como no programa abaixo, denominado “AtribuicaoPorLeitura1”. Algoritmo "AtribuicaoPorLeitura1" //Armazena nove número inteiros por leituras // individualizadas. //Autor: Mário Leite //------------------------------------------------------- Var VetNum: vetor[1..9] de inteiro Inicio Escreva("Digite o valor do primeiro elemento: ") Leia(VetNum[1]) Escreva("Digite o valor do segundo elemento: ") Leia(VetNum[2]) Escreva("Digite o valor do terceiro elemento: ") Leia(VetNum[3]) Escreva("Digite o valor do quarto elemento: ") Leia(VetNum[4]) Escreva("Digite o valor do quinto elemento: ") Leia(VetNum[5]) Escreva("Digite o valor do sexto elemento: ") Leia(VetNum[6]) Escreva("Digite o valor do sétimo elemento: ") Leia(VetNum[7]) Escreva("Digite o valor do oitavo elemento: ") Leia(VetNum[8]) Escreva("Digite o valor do nono elemento: ") Leia(VetNum[9]) FimAlgoritmo Esses dois métodos de atribuição não são eficientes e nem eficazes na prática, pois, “agridem” a lógica de programação, com soluções muito pobres e sem recursos. 201 No primeiro tipo de atribuição com o programa"AtribuiçãoDireta” fica evidente a falta de flexibilidade, uma vez que os valores atribuídos serão SEMPRE os mesmos, o que torna o programa sem um sentido prático. No programa "AtribuicaoPorLeitura1" a solução também é muito ineficiente pois, obriga o programador a digitar dezoito linhas de código (nove para mensagens e nove para ler os valores); imagine se, em vez de nove, fosse noventa valores!?. A figura 5.3a mostra como ficam as leituras dos elementos do vetor VetNum[ ] no programa "AtribuicaoPorLeitura1" Figura 5.3a - Leitura dos elementos do vetor por leituras diretas individualizadas 202 Então, a solução mais eficiente, e eficaz, é trabalhar com loop para manipular elementos de vetores, como será mostrado nos itens seguintes 5.7 - Atribuição por Leituras Através de Loop Neste caso a técnica é bem mais eficiente, uma vez que o número de linhas de código será, basicamente, quatro: 1) Início da estrutura do loop. 2) Mensagem explicativa para o usuário. 3) Leitura do elemento do vetor. 4) Término da estrutura do loop. Observe como funciona essa técnica no programa "AtribuicaoPorLeitura2", e compare os tamanhos dos códigos nas duas versões! Algoritmo "AtribuicaoPorLeitura2" //Armazena nove números inteiros por leituras em loop. //Autor: Mário Leite //---------------------------------------------------- Var VetNum: vetor[1..9] de inteiro j: inteiro Inicio Para j De 1 Ate 9 Faca Escreva("Digite o valor do elemento",j,": ") Leia(VetNum[j]) FimPara FimAlgoritmo A figura 5.3b mostra a saída do programa "AtribuicaoPorLeitura2". 203 Figura 5.3b - Leitura dos elemento do vetor através de um loop Além de reduzir drasticamente o número de linhas de código, a versão 2 do programa é bem mais rápida, quando se tem uma quantidade muito grande de leituras. Mas, ele pode se tornar mais geral ainda, em vez de se considerar um número fixo de elementos (no caso foi 9) ser solicitado, previamente, o tamanho do vetor (quantidade de elementos). Digamos que seja n; então, uma terceira versão do mesmo programa pode ser vista em “AtribuicaoPorLeitura3”, bem mais geral e completa para esses casos. 204 Algoritmo "AtribuicaoPorLeitura3" //Armazena nove número inteiros por leituras com quantidade //desejada. //Autor: Mário Leite //------------------------------------------------------- Const MAXELE=100 //define máximo de elementos do vetor Var VetNum: vetor[1..MAXELE] de inteiro j, n: inteiro Inicio Repita Escreva("Digite o número de elementos do vetor [min 2 - max",MAXELE,":") Leia(n) n <- Int(n) //garante n inteiro Ate((n>=2) e (n<=MAXELE)) Escreval("") Para j De 1 Ate n Faca Escreva("Digite o valor do elemento",j,": ") Leia(VetNum[j]) FimPara FimAlgoritmo A figura 5.3c mostra a saída do programa "AtribuicaoPorLeitura3". 205 Figura 5.3c - Leitura do vetor com loop (solução mais geral) Observe que nesta versão mais geral do programa, “AtribuicaoPorLeitura3”, foram introduzidas mais algumas linhas extras de código ANTES do loop de leitura dos elementos. 1. Const MAXELE=100 para definir um valor máximo do tamanho do vetor, podendo ser alterado, se for necessário. 2. Estrutura de repetição para validar o número de elementos do vetor, inclusive garantindo um valo inteiro para n, com a instrução Int(n). Todas as vezes em que houver entrada de um valor X que deva ser, necessariamente, inteiro, a instrução X <- Int(X) deve ser considerada. 206 5.8 - Operações Matemáticas Simples com Vetores Conforme foi introduzido no item 5.3, as operações elementares podem ser feitas com vetores, desde que seja considerado o sistema de elemento a elemento, do mesmo tipo. E além das operações matemáticas elementares (soma, subtração, multiplicação e divisão), e outras. 5.8.1 - Soma de Vetores Considere dois vetores U e V, ambos com n elementos inteiros, que devem ser somados. O programa “SomaDoisVetores” mostra como seus elementos podem ser somados, cujo resultado dessa soma é, também, um vetor S de tamanho n. Algoritmo "SomaDoisVetores" //Soma dois vetores, elemento a elemento. //Autor: Mário Leite //------------------------------------------------------- Const MAXELE=100 //define o tamanho máximo dos vetores. Var U, V, S: vetor[1..MAXELE] de inteiro j, n: inteiro Inicio Repita Escreva("Digite o número de elementos {min 2 – max",MAXELE,"]:") Leia(n) n <- Abs(Int(n)) //garante n inteiro e não negativo Ate((n>=2) e (n<=MAXELE)) Escreval("") Escreval("") {Leitura do vetor U} Para j De 1 Ate n Faca Escreva("Digite o elemento",j,"do primeiro vetor: ") 207 Leia(U[j]) FimPara Escreval("") {Leitura do vetor V} Para j De 1 Ate n Faca Escreva("Digite o elemento",j,"do segundo vetor: ") Leia(V[j]) FimPara Escreval("") {Soma o vetor U com o vetor V para obter o vetor S} Escreval("Vetor soma: S = U + V") Para j De 1 Ate n Faca S[j] <- U[j] + V[j] Escreva(S[j], " ") FimPara Escreval("") FimAlgoritmo //fim do programa "SomaDoisVetores" A figura 5.4 mostra a saída do programa "SomaDoisVetores" com as leituras dos elementos dos dois vetores (U e V) e o resultado da soma no vetor S. 208 Figura 5.4 - Soma de dois vetores: uma saída do programa "SomaDoisVetores" 5.8.2 - Subtração de Vetores A operação de subtração entre dois vetores funciona quase que exatamente como na operação de soma. A única diferença é o operador aplicado na operação; em vez de + (adição) será - (subtração); apenas isto! E ainda considerando os vetores U e V do item anterior, o resultado da subtração do vetor V do vetor U é mostrado na figura 5.5. O resultado é o vetor-diferença D, de mesmo tamanho n. 209 Figura 5.5 - Subtração entre dois vetores uma saída do programa "SubtraiVetores " 210 Algoritmo "SubtraiVetores" //Subtrai um vetor de outro, elemento a elemento. //Autor: Mário Leite //------------------------------------------------------- Const MAXELE=100 //define tamanho máximo dos vetores Var U, V, D: vetor[1..MAXELE] de inteiro j, n: inteiro Inicio Repita Escreva("Digite o número de elementos {min 2 - max",MAXELE,"]:") Leia(n) n <- Abs(Int(n)) //garante n inteiro e não negativo Ate((n>=2) e (n<=MAXELE)) Escreval("") Escreval("") {Leitura do vetor U} Para j De 1 Ate n Faca Escreva("Digite elemento",j,"do primeiro vetor: ") Leia(U[j]) FimPara Escreval("") {Leitura do vetor V} Para j De 1 Ate n Faca Escreva("Digite elemento",j," do segundo vetor: ") Leia(V[j]) FimPara Escreval("") {Subtrai o vetor V do vetor U para obter o vetor D} Escreval("Vetor diferença: D = U - V") Para j De 1 Ate n Faca D[j] <- U[j] - V[j] Escreva(D[j], " ") FimPara Escreval("") FimAlgoritmo 211 5.9 - Aplicações de Vetores 5.9.1 - Ordenação Uma lista de valores de tipos numéricos e/ou caracteres pode ser classificada em ordem crescente ou decrescente, com a utilização de vetores. Cada um desses valores são representados por elementos de um vetor, definido como do tipo correspondente. Para isto existem várias técnicas, ou métodos, de classificação. Segundo Azeredo (1996), existem diversos métodos de classificação (ordenação) de elementos, formando as chamadas “famílias de classificações”;aqui neste livro, para não fugir ao escopo didático a que se propõe, trataremos apenas da técnica mais utilizada pelos programadores: o “Método da Bolha”. Este método, conhecido academicamente como “Bubble Sort”, é o mais popular entre os programadores iniciantes, devido à sua simplicidade e facilidade de aprender, embora não seja o mais eficiente. Em resumo, consiste em percorrer a estrutura de um vetor, trocando um elemento de posição quando este estiver fora de sua posição de acordo com o modo de classificação desejado. Então, se o que se deseja é uma ordenação crescente - do menor valor para o maior valor - a troca será feita quando um elemento de posição j tiver menor valor que um elemento da posição j-1. Caso contrário, se a classificação for na ordem decrescente - do maior para o menor - a troca ocorrerá quando um elemento de posição j for maior que o elemento da posição j-1. Então, é necessário utilizar uma estrutura de repetição com dois loops aninhados, de modo que o mais externo controle as posições dos elementos antecessores e o segundo (mais interno) os elementos sucessores, fazendo comparações ente eles. No caso da ordenação crescente, se o antecessor for maior que seu sucessor então faz-se a troca de posições entre eles; caso contrário suas posições 212 permanecem como estão. O quadro 5.1 mostra o esquema do “Método da Bolha” para ordenar os elementos 17, 15, 94, 30 e 12 de um vetor de inteiros. 17 15 94 30 12 15 17 94 30 99 1/2: Troca 1/3: Não Troca 15 17 94 30 12 1/4: Não Troca 15 17 94 30 121/5: Troca 12 17 94 30 152/3: Não Troca 12 17 94 30 152/4: Não Troca 12 17 94 30 152/5: Troca 12 15 94 30 173/4: Troca 12 15 30 94 173/5: Troca 12 15 17 94 304/5: Troca 12 15 17 30 94Vetor Ordenado Quadro 5.1 - Esquema de ordenação pelo Método da Bolha 213 O programa “OrdenaBolha”, a seguir, mostra como fazer a ordenação crescente com uma lista de n elementos digitados pelo usuário. Algoritmo "OrdenaBolha" //Ordena um vetor lido, de n elementos pelo "Método Bolha". //Autor: Mário Leite //------------------------------------------------------- Const MAXELE=100 //define o máximo de elementos Var VetNum: vetor[1.. MAXELE] de inteiro i, j, n, Aux: inteiro Num: real Inicio Repita Escreva("Digite o número de elementos min 2 – max",MAXELE,"]: ") Leia(n) n <- Int(n) //garante número inteiro Ate((n>=2) e (n<=MAXELE)) Escreval("") {Loop para a leitura dos elementos do vetor} Para j De 1 Ate n Faca Escreva("Digite um número inteiro: ") Leia(Num) VetNum[j] <- Int(Num) FimPara //fim da leitura dos elementos do vetor LimpaTela {Loop para exibir os elementos do vetor na ordem lida} Escreval("Elementos do vetor na ordem lida:") Para j De 1 Ate n Faca Escreva(VetNum[j], " ") FimPara Escreval("") Escreval("") {Loops aninhados para ordenar pelo "Método da Bolha"} Para i De 1 Ate (n-1) Faca 214 Para j De (i+1) Ate n Faca {Faz as trocas, se for necessário} Se(VetNum[i] > VetNum[j]) Entao //crescente Aux <- VetNum[i] VetNum[i] <- VetNum[j] VetNum[j] <- Aux FimSe FimPara FimPara {Exibe os elementos do vetor ordenados crescentemente} Escreval("Elementos do vetor depois de ordenados:") Para j De 1 Ate n Faca Escreva(VetNum[j], " ") FimPara FimAlgoritmo //fim do programa "OrdenaBolha" Nota: O código do programa "OrdenaBolha" faz a classificação de um vetor de inteiros em ordem crescente. Para fazer a classificação em ordem decrescente basta, apenas, inverter o operador na expressão que faz a comparação de > para < A figura 5.7 mostra uma saída do programa “OrdenaBolha”, para um vetor de onze elementos lidos. 215 Figura 5.7 - Ordenação do vetor pelo “Método da Bolha” 5.9.2 - Pesquisas Existem vários métodos e técnicas de fazer pesquisas em vetores; mas, de um modo geral, a base para se pesquisar (procurar) um determinado elemento num vetor é o que se chama de chave, que requer duas informações básicas: campo e valor. campo chave valor A informação do campo é referenciada num vetor por seu índice, e valor é o conteúdo do campo (valor do elemento) que é o objetivo da pesquisa. Aqui serão mostrados apenas dois métodos de pesquisa: Sequencial e Binário. 216 5.9.2.1 - Pesquisa Sequencial Este método de pesquisa, também conhecido como “busca linear”, apesar de ser o mais lento entre todos os outros, é o mais simples de entender, uma vez que o processo é tal como nós raciocinamos: começar a procurar o valor, fazendo comparações com os elementos do vetor, do primeiro para o último elemento. A pesquisa terá sucesso se o valor procurado coincidir com o valor de algum elemento (campo) do vetor; é simples, porém muito demorada. Deste modo, se o vetor possuir muitos elementos e o valor procurado estiver contido no último elemento, o tempo de busca pode exceder a dezenas de minutos (dependendo do conjunto software/hardware utilizado). O pseudocódigo a seguir implementa o algoritmo desse método de pesquisa, de um valor inteiro. O programa “PesquisaSequencial” é um exemplo que ilustra a aplicação desse método de pesquisa. Algoritmo “PesquisaSequencial” //Exemplos de pesquisa de elemento em vetor através de //“Pesquisa Sequencial” //Autor: Mário Leite //------------------------------------------------------- Const MAXELE=100 //define máximo de elementos do vetor Var VetNum: vetor[1..MAXELE] de inteiro Valor, j, n, Posicao: inteiro Msg1, Msg2: caractere Achou: logico Inicio {Leitura dos elementos do vetor} Repita Escreva(“Digite o número de elementos [min 2- max”,MAXELE,”]: “) Leia(n) n<-Abs(Int(n)) Ate((n>=2) e (n<=MAXELE)) Escreval(“”) 217 Para j De 1 Ate n Faca Escreva(“Entre com o elemento [“, j, “] do vetor: “) Leia(VetNum[j]) FimPara Escreval(“”) Escreva(“Digite o valor a ser pesquisado: “) Leia(Valor) Valor <- Int(Valor) //garante número inteiro Msg1 <- “Valor encontrado na posição: “ Msg2 <- “Valor não encontrado.” {Executa a pesquisa} Achou <- Falso j <- 1 Enquanto ((Achou=Falso) e (j<=n)) Faca Se(valor=VetNum[j]) Entao Posicao <- j Achou <- Verdadeiro FimSe j <- j + 1 FimEnquanto Escreval(“”) Escreval(“”) {Verifica se a pesquisa teve sucesso} Se(Achou) Entao Escreval(Msg1, Posicao) Senao Escreval(Msg2) FimSe FimAlgoritmo A figura 5.8a mostra uma saída do programa “PesquisaSequencial”. 218 Figura 5.8a - Pesquisando elemento “Pesquisa Sequencial” A figura 5.8b mostra outra saída do programa “PesquisaSequencial”, considerando o mesmo vetor; agora, no caso em que a elemento procurado não pertence ao vetor dado. 219 Figura 5.8b - Pesquisando elemento com “Pesquisa Sequencial” 5.9.2.2 - Pesquisa Binária O método de “Pesquisa Binária” é muito mais rápido e mais eficiente do que o da “Pesquisa Sequencial”, pois utiliza um sistema de particionamento recursivo do vetor em dois subsegmentos. Em termos práticos o método consiste na busca de determinado valor numa lista previamente ordenada A cada comparação, caso o valor não seja encontrado um novo intervalo de pesquisa é criado, e a partir de então é estabelecido um novo local de início e fim da pesquisa. Este procedimento é repetido até que o início de pesquisa coincidacom o fim e o intervalo pesquisado reduzido a um único elemento. Vamos considerar um vetor com quinze elementos de inteiros, no qual se deseja pesquisar o valor 31, como mostrado no esquema do quadro 5.2a. 220 Quadro 5.2a - Primeira partição do seguimento Fazendo a primeira partição o elemento central é o 52; e como 52 é maior que 31 conclui-se que o elemento procurado deve estar à esquerda de 52. Portanto, uma segunda partição deve ser feita. E considerando agora o segmento da esquerda, o novo valor central é o 21; isto pode ser visto no esquema do quadro 5.2b. Quadro 5.2b - Segunda partição do seguimento Repetindo o processo chegaremos ao resultado apresentado no quadro 5.2c em que o elemento central 31 coincide com o valor procurado. O programa “PesquisaBinaria”, em pseudocódigo, mostra como funciona esse tipo de pesquisa. 221 Quadro 5.2c - Fim do processo: valor encontrado Programa "PesquisaBinaria" //Procura um valor através do método de "Pesquisa //Binária" //------------------------------------------------------- {Vet: Vetor de elementos onde será feita a pesquisa. PosIni: Posição inicial do intervalo de pesquisa. PosFim: Posição final do intervalo de pesquisa. PosCent: Posição do elemento central do intervalo. NumPesq: Número a ser pesquisado. Achou: Variável lógica que verifica a pesquisa } //------------------------------------------------------- Declare j, n, NumPesq, Local, PosIni: inteiro PosFim, PosCent: inteiro Achou: lógico Vet: array[1..n] de inteiro Início Escreva("Digite o número a ser pesquisado: ") Leia(NumPesq) {Lê os elementos do vetor - n conhecido previamente} Para j De 1 Até n Faça Escreva("Entre com o elemento[",j,"]do vetor:") Leia(Vet[j]) FimPara {ATENÇÃO: Depois de lido o vetor deve ser ordenado} EscrevaLn("") Local 0 PosIni 1 PosFim n 222 Achou .F. Enquanto((PosIni<=PosFim) e (Achou=.F.)) Faça PosCent Int(PosIni+PosFim)/2 //posição central Se(Vet[PosCent]=NumPesq) Então Achou .V. Local PosCent Senão Se(Vet[PosCent]>NumPesq) Então PosFim PosCent – 1 Senão PosIni PosCent + 1 FimSe FimSe FimEnquanto Se(Local<>0) Então EscrevaLn("Valor encontrado na posição: ", Local) Senão EscrevaLn("Valor não encontrado") FimSe FimPrograma 5.9.3 - Verificando Maior e Menor elemento Neste caso uma boa técnica de programação é começar considerando o primeiro elemento do vetor como sendo o maior e menor, simultaneamente, já que ele é o primeiro e ainda não foi comparado com nenhum outro da lista. O programa “VerifMaiorMenor” é uma solução para isto. A figura 5.9a mostra o programa no editor do Visualg, e a figura 5.9b a saída do programa. 223 Figura 5.9a - Código-fonte do programa “VerifMaiorMenor” no editor 224 Figura 5.9b - Uma saída do programa “VerifMaiorMenor” Uma outra solução para encontrar o maior e o menor elemento de um vetor de inteiros, seria: primeiro ordenar (crescentemente) o vetor, e depois, simplesmente, escrever o maior (último elemento) e o menor (primeiro elemento). Uma solução, logicamente, bem simples. 5.9.4 - Soma e Média dos elementos Tal como saber qual é o maior e o menor elemento de um vetor, esta é uma ação que poderá ser solicitada em algum momento, num programa mais geral: “a soma dos elementos de um vetor e sua média”. Uma solução bem simples é a apresentada no programa “Soma-MediaElementos”, exibindo a média com apenas uma decimal. 225 Figura 5.10a - Uma saída do programa “Soma-MediaElementos” 226 Figura 5.10b - Código-fonte de “Soma-MediaElementos” no editor 227 5.9.5 - Invertendo a Ordem dos elementos A inversão da ordem dos elementos de um vetor, às vezes, é importante em diversas situações; e existe uma forma bem simples de fazer isto: mostrar o vetor num loop decrescente de 1, após a leitura original. Outra técnica, mais elegante é, à medida que for lendo os elementos do vetor original, criar outro vetor com os elementos “de trás para a frente”, usando a fórmula:. VetInv[n-j+1] = VetOrig[j] Onde VetInv[ ] é o vetor inverso e VetOrig[ ] o vetor lido originalmente, com n elementos. Os programas “InverteVetor1” e InverteVetor2” (figuras 5.11a e 5.11b, respectivamente) mostram as duas maneiras citadas de inverter um vetor de dez elementos inteiros. Figura 5.11a - Código-fonte do programa “InverteVetor1” no editor 228 Figura 5.11b - Uma saída do programa “InverteVetor1” Figura 5.12a - Código-fonte do programa “InverteVetor2” no editor 229 Figura 5.12b - Uma saída do programa “InverteVetor2” 5.9.6 - Verificando Característica de elemento 5.9.6.1- Verificando elemento Múltiplo Esta é uma situação que pode ocorrer: percorrer os elementos do vetor e ver qual (ou quais) elemento(s) é múltiplo de um número dado. Por exemplo, seja o vetor de inteiros: 14 12 25 4 6 32 27 34 22 15 Vamos verificar qual (s) elemento(s) desse vetor é múltiplo de 3. Neste caso vemos que os elementos que correspondem a esta questão são: 12, 6, 27 e 15. 230 O programa “VerifEleMultiplo”, mostrado na figura 5.13a, é uma solução para este problema. A figura 5.13b mostra a saída do programa para o vetor de elementos sugeridos. Figura 5.13a - Código-fonte do programa “VerifEleMultiplo” no editor 231 Figura 5.13b - Uma saída do programa “VerifEleMultiplo” 5.9.6.2- Verificando elemento Divisor Neste caso, a solução é bem parecida com a do item anterior; agora temos que verificar se um elemento (ou quais) do vetor divide o número dado. As figuras 5.14a e 5.14b mostram duas saídas do programa “VerifEleDivisor”, e a figura 5.14c o código- fonte do programa que implementa a solução, digitado no editor do Visualg. 232 Figura 5.14a - Uma saída do programa “VerifEleDivisor” Figura 5.14b - uma saída do programa “VerifEleDivisor” 233 Figura 5.14c - Código-fonte do programa “VerifEleDivisor” no editor 5.9.6.3 - Verificando Paridade e Posição Neste caso, o que se deseja é mostrar os elementos pares e os ímpares do vetor e suas posições na lista, O programa “VerifParidade” da figura 5.15a é uma solução bem simples, e uma saída é mostrada na figura 5.15b.. 234 Figura 5.15a - Código-fonte do programa “VerifParidade” no editor Figura 5.15b - Uma saída do programa “VeriParidade” 235 5.9.7 - Incluindo, Excluindo e Alterando elemento Pode acontecer que depois de criar um vetor (através de leitura ou de atribuições diretas) haja necessidade de incluir, excluir ou alterar um elemento no vetor. Nestes casos, estes tipos de ações, através de nova leitura dos elementos fica muito trabalhoso, e para atribuição direta mais ainda. 5.9.7.1- Incluindo um novo elemento Neste caso, o que se deseja é fazer a inserção de novo elemento em algum local do vetor, entre dois elementos, ou mesmo nas suas extremidades. Por exemplo: seja o vetor de inteiros: 3 5 0 1 9 7 6 4 2 ; e se deseja incluir o elemento 8 na posição 4, isto e: na posição atualmente do elemento 1. Deste modo o elemento 1 vai passar a ser o quinto elemento do vetor, depois de feita a inserção do número 8. Os dois esquemas abaixo esclarece. Situação antes da inserção: 3 5 0 1 9 7 6 4 2 Situação depois da inseçsão: 3 5 0 8 1 9 7 6 4 2 A figura 5.16 mostra a saída do programa, considerando o vetor mostrado acima. O programa “IncluiElementoNoVetor” é uma solução em Visualg que implementa uma solução bem didática e eficiente, pois, além de fazer a inserção, o vetoré reorganizado com esse novo elemento na posição desejada. 236 Figura 5.16 - Uma saída do programa “IncluiElementoNoVetor” Algoritmo "IncluiElementoNoVetor" //Inclui um novo elementos num vetor de inteiros, e //em seguida o rearranja. //Autor: Mário Leite //------------------------------------------------------- Var VetOrig, VetAtu: vetor[1..100] de inteiro j, N, Posi, Num, NovoElem: inteiro Inicio LimpaTela N <- 0 Enquanto ((N<=2) ou (N>100)) Faca Escreva("Digite o número de elementos do vetor? [mínimo 2 - max 100]: ") Leia(N) FimEnquanto 237 Escreval("") {Lê e vai mostrando os elementos do vetor} Para j De 1 Ate N Faca Escreva("Digite número inteiro e positivo: ") Leia(Num) VetOrig[j] <- Abs(Int(Num)) VetAtu[j] <- VetOrig[j] FimPara Escreval("") {Inclui novo elemento no vetor} Repita Escreva("Em qual posição deseja incluir o elemento? [min 1"," - max",N,"]: ") Leia(Posi) Ate((Posi>=1) e (Posi<=N)) Escreval("") Escreva("Digite o valor do novo elemento: ") Leia(NovoElem) NovoElem <- Int(NovoElem) LimpaTela {Vetor original} Escreval("Vetor com os elementos lidos") Para j De 1 Ate N Faca Escreva(VetOrig[j], " ") FimPara Para j De 1 Ate (N+1) Faca Se(j<Posi) Entao VetAtu[j] <- VetOrig[j] FimSe Se(j=Posi) Entao VetAtu[j] <- NovoElem FimSe Se(j>Posi) Entao VetAtu[j] <- VetOrig[j-1] FimSe 238 FimPara Escreval("") Escreval("") {Vetor com o novo elemento} Escreval("Vetor com o novo elemento incluido") Para j De 1 Ate (N+1) Faca Escreva(VetAtu[j], " ") FimPara Escreval("") FimAlgoritmo 5.9.7.2 - Excluindo um elemento Agora, o que se deseja é excluir um determinado elemento do vetor. Assim, considerando o vetor do item anterior, suponha que se deseja excluir o sexto elemento (9) do vetor da figura 5.16, resultado da inserção do elemento 8. O programa "ExcluiElementoDoVetor" é uma boa solução com o Visualg, como na figura 5.17. Algoritmo "ExcluiElementoDoVetor" //Exclui um elementos de um vetor de inteiros, e em seguida o rearranja. //Autor: Mário Leite //------------------------------------------------------- Var VetOrig, VetAtu: vetor[1..100] de inteiro j, N, Posi, Num, NovoElem: inteiro Inicio LimpaTela N <- 0 Enquanto ((N<=2) ou (N>100)) Faca Escreva("Digite o número de elementos do vetor? [mínimo 2 - max 100]: ") Leia(N) FimEnquanto Escreval("") {Lê e vai mostrando os elementos do vetor} Para j De 1 Ate N Faca Escreva("Digite um número inteiro e positivo: ") 239 Leia(Num) VetOrig[j] <- Abs(Int(Num)) VetAtu[j] <- VetOrig[j] FimPara Escreval("") {Exclui o elemento do vetor} Repita Escreva("Deseja excluir o elemento de qual posição? [min 1", " - max",N,"]: ") Leia(Posi) Ate(Posi>=1) e (Posi<=N)) Escreval("") LimpaTela {Vetor original} Escreval("Vetor com os elementos lidos") Para j De 1 Ate N Faca Escreva(VetOrig[j], " ") FimPara {Exclui o elemento do vetor} Para j De 1 Ate N Faca Se(j<Posi) Entao VetAtu[j] <- VetOrig[j] FimSe Se(j>=Posi) Entao VetAtu[j] <- VetOrig[j+1] FimSe FimPara Escreval("") Escreval("") Escreval("Elemento excluido na posição", Posi,":", VetOrig[posi]) Escreval("") {Vetor sem o elemento excluido} Escreval("Vetor sem o elemento exluido") Para j De 1 Ate (N-1) Faca Escreva(VetAtu[j], " ") FimPara FimAlgoritmo 240 Figura 5.17 - Uma saída do programa “ExcluiElementoDoVetor” 5.9.7.3 - Alterando o valor do elemento Nesta terceira situação, deseja-se alterar o valor de um determinado elemento do vetor já constituído. Vamos considerar que a alteração do vetor da figura 5.17, alterando o valor do penúltimo elemento (4) para o novo valor 5. A figura 5.18 mostra o resultado dessa alteração; e a seguir é mostrado o programa que implementa essa ação: o programa “AlteraElementoDoVetor”. 241 Figura 5.18 - Uma saída do programa “AlteraElementoDoVetor” Algoritmo "AlteraElementoDoVetor" //Altera o valor de um elemento de um vetor de inteiros, //e o rearranja. //------------------------------------------------------- Var VetOrig, VetAtu: vetor[1..100] de inteiro //limita o tamanho do vetor j, N, Posi, Num, NovoValor: inteiro Inicio LimpaTela N <- 0 Enquanto ((N<=2) ou (N>100)) Faca Escreva("Digite o número de elementos do vetor? [mínimo 2 -max 100]: ") Leia(N) FimEnquanto Escreval("") 242 {Lê e vai mostrando os elementos do vetor} Para j De 1 Ate N Faca Escreva("Digite o elemento da posição",j,":") Leia(Num) VetOrig[j] <- Abs(Int(Num)) VetAtu[j] <- VetOrig[j] FimPara Escreval("") {Altera elemento do vetor} Repita Escreva("Deseja alterar o elemento de qual posição? [min 1", " - max",N,"]: ") Leia(Posi) Ate(Posi>=1) e (Posi<=N)) Escreval("") Escreva("Digite o novo valor do elemento da posição", Posi, ": ") Leia(NovoValor) Escreval("") {Vetor original} Escreval("Vetor com os elementos lidos") Para j De 1 Ate N Faca Escreva(VetOrig[j], " ") FimPara Escreval("") Escreval("") VetAtu[Posi] <- NovoValor //faz a alteração {Vetor com o elemento alterado} Escreval("Vetor com o elemento alterado") Para j De 1 Ate N Faca Escreva(VetAtu[j], " ") FimPara FimAlgoritmo 243 ❖ Exemplo 5.1 - Calcular o MDC de vários números solicitados. No Exemplo 1.5, do Capítulo 1, foram apresentados esquemas de como calcular o MDC de dois números: 36 e 98, formalizado em pseudocódigo, o qual poderia ser codificado em qualquer das diversas linguagens de programação. Aquele exemplo foi para indicar que o importante é a programação (algoritmo da solução do problema) e não, especificamente. a codificação. Aqui, vamos mostraremos uma solução mais geral com o Visualg: em vez de apenas dois números, vamos calcular o MDC de n números (2<=n<=10), com o programa “CalculaMDCVariosNumeros”. Algoritmo "CalculaMDCVariosNumeros" //Calcula o MDC de vários números. //Autor: Mário Leite //------------------------------------------------------- Var VetNum: vetor[1..10] de inteiro //limita vetor j, n, Aux, MDC, MDCx, Num1, Num2: inteiro Inicio Repita Escreva("De quantos números será calculado o MDC? ") Leia(n) Ate((n>=2) e (n<=10)) Escreval("") Para j De 1 Ate n Faca Escreva("Digite o número #",j, ": ") Leia(VetNum[j]) FimPara Escreval("") Para j De 1 Ate (n-1) Faca Se(j=1) Entao {Utiliza o "Algoritmo de Euclides" Num1 <- VetNum[1] Num2 <- VetNum[2] Senao {Considera o segundo número incrementado de 2 Num2 <- VetNum[j+2] 244 FimSe Enquanto (Num2<>0) Faca Aux <- Num1 Num1 <- Num2 Num2 <- (Aux Mod Num2) FimEnquanto MDCx <- Num1 //MDCx é o VetNum[j,(j+1)] FimPara MDC <- MDCx Escreval("") Escreval("") Escreva("MDC(") Para j De 1 Ate n Faca Se(j<n) Entao Escreva(VetNum[j], ",") Senao Escreva(VetNum[j], ") =", MDC) FimSe FimPara Escreval("") FimAlgoritmoFigura 5.19 - Uma saída do programa “CalculaMDCVariosNumeros” 245 5.10 - Erros na utilização de Vetores Tal como acontece com variáveis simples, erros podem ocorrer, também. com vetores. Além de incompatibilidade de tipos, um dos erros mais comuns é sobre a dimensão do vetor; neste caso, tenta-se acessar um elemento que está fora da faixa definida. Por exemplo, define-se um vetor de n elementos [1..n], mas, em alguma linha de código o programa está tentando acessar o elemento n+1, ou de índice menor que 1. Observe o programa “AcessaVetor” mostrado na figura 5.20a. Figura 5.20a - Código-fonte do programa “AcessaVetor” no editor A figura 5.20b exibe a saída do programa “AcessaVetor”, mostrando que existe um erro quando se tenta acessar um elemento que não pertence ao vetor: problema no índice que não foi definido. Observe que a leitura dos oito elementos ocorre sem problema dentro do loop, mas, quando é interpretada a linha de instrução para escrever o nono elemento um erro acontece, pois, esse elemento não existe (não foi definido dentro da faixa de índices). O mesmo tipo de erro ocorreria se fosse pedido para mostrar um elemento de índice j<1. 246 Figura 5.20b - O código-fonte do programa “AcessaVetor” 247 5.11 - Exercícios Propostos 1 - Explique com suas palavras: o que são vetores, e como se atribui valores a eles no Visualg 2 - Que tipos de dados os elementos de um vetor pode ter no Visualg? Por quê? 3 - Mostre um exemplo de vantagem do uso de vetores. 4 - Escreva um programa em Visualg para criar um vetor de dez números pares (menores que 100), gerados aleatoriamente. 5 - Crie um programa que monte um vetor cujos elementos são os divisores de um número lido N (N>=10). Esse vetor deverá ser exibido com seus elementos ordenados. 6 - Observe o programa “XXX” abaixo, e explique o que ele faz... Algoritmo "XXX" Const MAXELE=1000 Var VetNum: vetor[1..MAXELE] de inteiro j, n, Col, Cont, Num, RInt: inteiro RRea: real Inicio Repita Escreva("Digite o número de elementos do vetor [min 2-max",MAXELE,"]: ") Leia(N) Ate((n>=2) e (n<=MAXELE)) Escreval("") Cont <- 0 Num <- 0 Enquanto (Cont<=n) Faca Num <- Num + 1 RRea <- RaizQ(Num) RInt <- Int(RRea) Se(RRea=RInt) Entao 248 Cont <- Cont + 1 VetNum[Cont] <- Num FimSe FimEnquanto Col <- 0 Escreval("") Escreval("") Para j De 1 Ate n Faca Col <- Col + 1 Se(Col>10) Entao Escreval("") Col <- 1 FimSe Escreva(VetNum[j], " ") FimPara Escreval("") FimAlgoritmo 7 - Crie um programa que leia n valores inteiros e monte um vetor só com elementos ímpares. Caso não exista nenhum valor ímpar lido o programa deverá emitir uma mensagem alertando o usuário para esse fato. 8 - Repita o problema do exercício anterior; agora, porém, os elementos do vetor criado deverão ser todos primos. 9 - Observe o programa “YYY” abaixo. Marque a alternativa correta que indica porque o programa não vai rodar. Algoritmo "YYY" Const TamMax=100 Var VetRand: vetor[0..TamMax] de inteiro j, ContEle, TamVet: inteiro PI: real Inicio LimpaTela Repita Escreva("Digite o número de elementos que o vetor terá: ") Leia(TamVet) 249 TamVet <- Int(TamVet) Ate((((TamVet>=2) e (TamVet<=TamMax)))) PI <- 3.14159265 Escreval("") ContEle <- 0 Para j De 1 Ate TamVet Faca VetRand[j] <- (Randi(1001))*Int(PI) Escreva(VetRand[j], " ") ContEle <- ContEle + 1 Se(ContEle>10) Entao ContEle <- 0 Escreval("") FimSe FimPara Escreval("") FimAlgoritmo A ( ) O índice inicial do vetor não pode ser 0, B ( ) Tem excesso de parênteses na estrutura Repita..Ate, C ( ) Na estrutura Para..FimPara a variável j deveria começar com 0. D ( ) A constante PI não pode ser declarada no Visualg. E ( ) As declarações das constantes deveriam estar depois do comando Var. 10 - Rodando o programa “MostraMedia” abaixo, obteve-se o resultado de 12.4 para a média do aluno, o que é um resultado inválido, pois deveria ser, de no máximo 10.0. O que faltou no programa para que o valor da média sempre seja um valor válido? 250 Algoritmo "MostraMedia" Var VetNotas: vetor[1..4] de real j: inteiro Soma, Media: real Inicio Para j De 1 Ate 4 Faca Escreva("Digite a nota",j," do aluno: ") Leia(VetNotas[j]) Soma <- Soma + VetNotas[j] FimPara Escreval("") Media <- Soma/4 Escreval("Média das notas: ", Media) FimAlgoritmo A ( ) O índice inicial do vetor de notas deveria ser 0 (zero). B ( ) Cada nota deveria ser validada do segu8inte modo: 0<=VetNotas[j]<=10. C ( ) Cada nota deveria ser validada assim: 0<VetNotas[j]<10. D ( ) Cada nota deveria ser validada assim: VetNotas[j]<=10. E ( ) A variável Soma tinha que ser inicializada com valor 0. 11 - O objetivo do programa "MostraDifPrimos" é mostrar os números primos num intervalo dado, as diferenças entre dois primos consecutivos, a maior diferença e a quantidade desses números nesse intervalo. Entretanto, existe um pequeno bug que inviabiliza o seu funcionamento correto. Mostre onde está esse bug. 251 Algoritmo "MostraDifPrimos" //Analisa os primos num determinado intervalo. //Autor : Mário Leite //------------------------------------------------------- Var VetPrimos: vetor[1..1000] de inteiro j, k, Lim1, Lim2, Num, Cont, Rdiv, IntRaiz: inteiro Dif, MaiorDif, PriAnt, PriPrx: inteiro Cond, TemDiv: logico Inicio Escreva("Digite o limite inferior: [maior ou igual a 1]: ") Leia(Lim1) Escreva("Digite o limite superior: [maior que ",Lim1,"]: ") Leia(Lim2) Se(Cond) Entao Escreval("Intervalo inválido!") Senao Cont <- 0 Para j De Lim1 Ate Lim2 Faca PriPrx <- j + 1 //pega o primeiro após j IntRaiz <- Int(RaizQ(PriPrx)) TemDiv <- Falso Para k De 2 Ate (IntRaiz) Faca //divisões RDiv <- (PriPrx Mod k) Se(RDiv = 0) Entao TemDiv <- Verdadeiro Interrompa //abandona loop FimSe FimPara Se(Nao(TemDiv)) Entao //checa se é primo Cont <- Cont + 1 VetPrimos[Cont] <- PriPrx Escreval(PriPrx) FimSe FimPara //fim do loop para detectar primos 252 Escreval("Quantidade de primos encontrada: ",Cont) Escreval("") MaiorDif <- 0 Escreval("Diferenças entre os primos consecutivos:") Para j De 2 Ate Cont Faca Dif <- VetPrimos[j] - VetPrimos[j-1] Se(Dif>MaiorDif) Entao MaiorDif <- Dif PriAnt <- VetPrimos[j-1] PriPrx <- VetPrimos[j] FimSe Escreval(VetPrimos[j],"-",VetPrimos[j- 1],": ",Dif) FimPara Escreval("Maior diferença entre dois primos consecutivos[",PriPrx," – ",PriAnt,"]:",MaiorDif) FimSe FimAlgoritmo 253 Capítulo 6 - Trabalhando com Matrizes 6.1 - Introdução ao Capítulo Matrizes podem ser consideradas como uma generalização de vetores, uma vez que permitem armazenar e manipular valores em várias direções, enquanto que nos vetores só é permitido uma lista de valores em apenas uma direção. Isto quer dizer que,enquanto um elemento de um vetor é identificado por apenas um único índice inteiro, um elemento de uma matriz é identificado por mais de um índice inteiro. Se a matriz é bidimensional cada elemento tem dois índice, funcionando como uma tabela de um banco de dados. Este capítulo apresenta um estudo básico sobre o uso de matrizes em programas implementados em Visualg, com exemplos e aplicações bem interessantes para os iniciantes, e também para aqueles que já possuem algum conhecimento de programação. São mostrados exemplos práticos que podem ser aproveitados em situações do dia a dia dos profissionais em desenvolvimento de sistemas: operações com matrizes, matrizes especiais e cálculos de determinantes. 6.2 - Conceitos Básicos Tecnicamente, pode-se dizer que um vetor é um caso particular de matriz: uma matriz unidimensional. Matriz é um array multidimensional que se constitui, também, numa estrutura homogênea pois, tal como os vetores, seus elementos têm que ser todos de um mesmo tipo de dado. Portanto, as matrizes também são consideradas variáreis indexadas, compostas ou subscritas. 254 E, embora a quantidade máxima de dimensões de uma matriz seja definida apenas pela memória RAM disponível, o máximo utilizado é três; mas, na prática utiliza-se duas dimensões (que o Visualg suporta), tratando uma matriz como se fosse uma tabela do ambiente de banco de dados. Para matrizes bidimensionais a primeira dimensão é sempre considerada a LINHA, e a segunda dimensão a COLUNA (rigorosamente, nesta ordem). A figura 6.1 mostra um esquema representativo, teórico, de uma matriz de m linhas e n colunas. Figura 6.1 - Esquema de representação de uma matriz mxn Na prática, uma matriz bidimensional pode ser considerada um arranjo retangular de mxn elementos de um mesmo tipo; e de acordo com o esquema da figura 6.1 cada par ordenado (aij) é um elemento da matriz, onde i é o índice da linha e j o índice da coluna; e se m=n então a matriz é dita quadrada. Então, segundo o esquema da figura 6.1 a53 é o elemento que ocupa a linha 5 e coluna 3. Os esquemas das figuras 6.2a e 6.2b mostram o exemplo de uma matriz de inteiros com dimensões 4x6 (4 linhas e 6 colunas) 255 2 4 5 8 1 3 0 6 9 5 3 7 5 8 9 0 3 4 4 3 4 1 6 5 Figura 6.2a- Esquema de representação de uma matriz 4x6 A figura 6.2b mostra um esquema da matriz bidimensional. Observe que é como se tivesse vários vetores horizontais e verticais compondo a matriz M 4x6. Figura 6.2b - Representação da matriz M bidimensional L i n h a s C o l u n a s 256 A tabela 6.1 mostra um exemplo de notas médias obtidas por quatro turmas (diurnas e noturnas) de Análise e Desenvolvimento de Sistema em cinco disciplinas diferentes. Turma/Disc Matemática Português Programação História OSPB ADS1-N 8.3 9.1 8.7 9.2 6.5 ADS1-D 7.8 5.9 6.8 6.6 6.7 ADS2-D 8.7 7.4 7.5 7.1 7.3 ADS2-N 7.6 8.2 8.0 9.3 7.6 Tabela 6.1 - Tabela matricial de notas de quatro turmas 6.3 - Declaração de Matrizes no Visualg Embora existam linguagens de programação que consideram o índice do primeiro elemento de uma matriz como sendo 0 (zero), o Visualg, e muitos outros ambientes de programação iniciam de 1 (um) - tal como é considerado o início da contagem dos seres humanos -. E para acessar um dos elementos de uma matriz bidimensional basta digitar o nome da matriz e colocar seus índices: [linha,coluna] entre colchetes. No caso do esquema da tabela 6.1, se for considerada a matriz Notas[ ], então Notas[3,2] é a nota média obtida em Português pela turma ADS2-D, cujo valor é 6.4. O esquema abaixo indica como seria definida a matriz Notas[ ] da tabela 6.1. 257 Var Notas: vetor[1..4, 1..5] de real Declara matriz Nome da matriz Comando de declaração Faixa da primeira dimensão Tipo de dado da matriz Faixa da segunda dimensão [1..4] significa que na primeira dimensão (linha) os elementos têm índices de 1 a 4. [1..5] significa que na segunda dimensão (coluna) os elementos têm índices de 1 a 5. O que resulta em 4*5 = 20 notas médias. E tal como no caso dos vetores, só é possível manipular matrizes elemento a elemento, e nas operações matemáticas e lógicas, desde que essas operações sejam possíveis com os tipos de matrizes envolvidas. O trecho de programa abaixo calcula e mostra a média das notas médias em “Português” da tabela 6.1. ... Var Notas: vetor[1..4, 1..5] de real Soma, Media: real j: inteiro ... Turma Soma 0 Português Para j De 1 Ate 4 Faca Soma Soma + Notas[j,2] FimPara Media Soma/4 EscrevaLn("Média das notas médias em Português: ", Media) ... 258 Agora, suponha que seja interessante para a coordenadora do curso de ADS saber a média da turma ADS2-D nas cinco disciplinas. O fragmento de código abaixo é uma solução, em Visualg. ... Var Notas: vetor[1..4, 1..5] de real Soma, Media: real j: inteiro ... ADS2-D Soma 0 Disciplina Para j De 1 Ate 5 Faca Soma Soma + Notas[3,j] FimPara Media Soma/5 EscrevaLn("Média das notas médias da turma ADS2- D: ", Media) ... 6.4 - Leitura e Escrita de uma Matriz No caso de vetor basta um loop para ler/escrever seus elementos; já, para uma matriz, o número de loops será igual ao número de dimensões que ela possui; para matrizes bidimensionais (suportadas pelo Visualg) serão dois loops. Por exemplo, considerando as notas da matriz Notas[ ] esquematizada na tabela 6.1, a leitura e escrita das notas poderiam ser feitas de acordo com o programa “LeEscreveMatriz1”, com solução de atribuição direta dos valores daquela tabela, que pode ser visto na figura 6.3. 259 Figura 6.3 - O programa “LeEscreveMatriz1” no editor do Visualg O programa “LeEscreveMatriz2” da figura 6.4, lê os elementos de uma matriz com dimensões mxn, com m linhas e n coluna, determinadas pelo usuário. 260 Figura 6.4 - Código-fonte do programa “LeEscreveMatriz2” no editor Nota: Observe a instrução Escreval("") - para saltar linha - depois do loop j na exibição da matriz no programa “LeEscreveMatriz2”. Ela é fundamental para que cada linha da matriz seja individualmente impressa, mostrando os elementos na forma de tabela. Se não houvesse essa instrução nesse local todos os elementos da matriz seriam exibidos sequencialmente, um atrás do outro e numa mesma linha. 261 6.5 - Operações com Matrizes Em princípio, as quatro operações aritméticas podem ser executadas usando matrizes; entretanto, por se tratar de um arranjo de elementos com certa lógica, algumas restrições são impostas, já que os resultados nem sempre são números puros. 6.5.1 - Adição de Matrizes Para que seja possível somar duas matrizes é necessário que ambas sejam da mesma ordem: mesmo número de linhas (m) e o mesmo número de colunas (n). O resultado dessa operação é uma matriz que também terá as mesmas dimensões (mxn) das duas matrizes. A operação de adição é feita elemento a elemento: A(mxn) + B(mxn) = C(mxn) de modo que: a(11) + b(11) = c(11) a(21) + b(21) = c(21) a(31) + b(31) = c(31) - - - + - - - = - - - a(mn) + b(mn) = c(mn) Generalizando para a sintaxe do Visualg fica do seguinte modo: A[i,j] + B[i,j] = C[i,j] com i=1,m e j=1,n Observe o esquema abaixo na soma de uma matriz A 3x4 com uma matriz B 3x4, resultando numa matriz C, também 3x4. A B C 6 7 5 4 2 2 0 3 8 9 5 7 43 6 8 + 3 1 3 1 = 7 4 9 9 6 5 4 1 2 1 4 2 8 6 8 3 262 Nota: Para somar duas ou mais matrizes, não é necessário que todas sejam quadradas, mas sim que todas tenham as mesmas dimensões. O programa “SomaDuasMatrizes” mostra como somar duas matrizes a partir da leitura de seus elementos. O resultado da soma é armazenado em uma outra matriz. Todas as três matrizes são mostradas nas suas formas tabelares. Algoritmo "SomaDuasMatrizes" //Faz a soma de duas matrizes mxn lidas pelo teclado fazendo //validações. //Autor: Mário Leite //------------------------------------------------------- Const MAXLIN=20 //define o número máximo de linhas MAXCOL=20 //define o número máximo de colunas Var MatA, MatB, MatC: vetor[1..MAXLIN,1..MAXCOL] de inteiro i, j, LinMat, ColMat: inteiro Inicio Repita Escreva("Digite o número de linhas da matriz [min 2-máx",MAXLIN,": ") Leia(LinMat) LinMat <- Int(LinMat) Ate((LinMat>=2) e (LinMat<=MAXLIN)) Repita Escreva("Digite o número de colunas da matriz [min 2-máx",MAXCOL,":") Leia(ColMat) ColMat <- Int(ColMat) Ate((ColMat>=2) e (ColMat<=MAXCOL)) Escreval("") Escreval("") LimpaTela 263 {Leitura da matriz A} Para i De 1 Ate LinMat Faca Para j De 1 Ate ColMat Faca Escreva("Entre com o elemento [",i,j,"] da matriz A: ") Leia(MatA[i,j]) FimPara Escreval("") FimPara Escreval("") {Leitura da matriz B} Para i De 1 Ate LinMat Faca Para j De 1 Ate ColMat Faca Escreva("Entre com o elemento [",i,j,"] da matriz B: ") Leia(MatB[i,j]) FimPara Escreval("") FimPara LimpaTela Escreval("Matriz A na forma tabelar") Para i De 1 Ate LinMat Faca Para j De 1 Ate ColMat Faca Escreva(MatA[i,j], " ") FimPara Escreval("") FimPara Escreval("") Escreval("Matriz B na forma tabelar") Para i De 1 Ate LinMat Faca Para j De 1 Ate ColMat Faca Escreva(MatB[i,j]," ") FimPara Escreval("") FimPara Escreval("") {Soma a matriz A com a matriz B para obter a matriz C} Para i De 1 Ate LinMat Faca 264 Para j De 1 Ate ColMat Faca MatC[i,j] <- MatA[i,j]+MatB[i,j] //soma elemento a elemento FimPara FimPara Escreval("") {Exibe a matriz C na forma tabelar} Escreval("Matriz C=A+B") Para i De 1 Ate LinMat Faca Para j De 1 Ate ColMat Faca Escreva(MatC[i,j], " ") FimPara Escreval("") FimPara Escreval("") FimAlgoritmo //fim do programa "SomaDuasMatrizes" A figura 6.5 mostra um exemplo de saída do programa "SomaDuasMatrizes". Figura 6.5 - Exemplo de saída do programa "SomaDuasMatrizes" 265 6.5.2 - Subtração de Matrizes Tal como no caso de adição, para subtrair uma matriz de outra é necessário que ambas tenham as mesmas dimensões. O programa “SubtraiMatrizes” a seguir, mostra um exemplo de como fazer esta operação. Algoritmo "SubtraiMatrizes" //Faz a subtração de uma matriz de outra, lidas pelo //teclado. //Autor: Mário Leite //------------------------------------------------------ Const MAXLIN=20 //define o número máximo de linhas da matriz MAXCOL=20 //define o número máximo de colunas da matriz Var MatA, MatB, MatC: vetor[1..MAXLIN,1..MAXCOL] de inteiro i, j, LinMat, ColMat: inteiro Inicio Repita Escreva("Digite o número de linhas da matriz [min 2-máx",MAXLIN,": ") Leia(LinMat) LinMat <- Int(LinMat) Ate((LinMat>=2) e (LinMat<=MAXLIN)) Repita Escreva("Digite o número de colunas da matriz [min 2 - máx",MAXCOL,":") Leia(ColMat) ColMat <- Int(ColMat) Ate((ColMat>=2) e (ColMat<=MAXCOL)) Escreval("") Escreval("") LimpaTela {Leitura da matriz A} Para i De 1 Ate LinMat Faca 266 Para j De 1 Ate ColMat Faca Escreva("Entre com o elemento [",i,j,"] da matriz A: ") Leia(MatA[i,j]) FimPara Escreval("") FimPara Escreval("") {Leitura da matriz B} Para i De 1 Ate LinMat Faca Para j De 1 Ate ColMat Faca Escreva("Entre com o elemento [",i,j,"] da matriz B: ") Leia(MatB[i,j]) FimPara Escreval("") FimPara LimpaTela Escreval("Matriz A na forma tabelar") Para i De 1 Ate LinMat Faca Para j De 1 Ate ColMat Faca Escreva(MatA[i,j], " ") FimPara Escreval("") FimPara Escreval("") Escreval("Matriz B na forma tabelar") Para i De 1 Ate LinMat Faca Para j De 1 Ate ColMat Faca Escreva(MatB[i,j]," ") FimPara Escreval("") FimPara Escreval("") {Subtrai matriz B da matriz A para obter a matriz C} Para i De 1 Ate LinMat Faca Para j De 1 Ate ColMat Faca 267 MatC[i,j] <- MatA[i,j] - MatB[i,j] //soma elemento a elemento FimPara FimPara Escreval("") {Exibe a matriz C na forma tabelar} Escreval("Matriz C=A-B") Para i De 1 Ate LinMat Faca Para j De 1 Ate ColMat Faca Escreva(MatC[i,j], " ") FimPara Escreval("") FimPara Escreval("") FimAlgoritmo //fim do programa "SubtraiMatrizes" Figura 6.6 - Exemplo de saída do programa "SubtraiMatrizes" 268 6.5.3 - Multiplicação de Matriz por Escalar Um escalar é um número inteiro; e neste caso, o escalar deve ser multiplicado por cada elemento da matriz, num processo bem fácil de entender. Veja esquema na figura 6.7a, onde a matriz M deve ser multiplicada por um escalar de valor 3. Figura 6.7a - Esquema do produto de uma matriz por um escalar O programa "MultiplicaMatrizPorEscalar" mostra como pode ser feita a multiplicação de uma matriz 3x3 de inteiros por um escalar, e a figura 6.7b exibe um exemplo de saída deste programa. 269 Algoritmo "MultiplicaMatrizPorEscalar" //Multiplica uma matriz por um escalar e exibe o //resultado na forma tabelar. //Autor: Mário Leite //----------------------------------------------------- Var M, R: vetor[1..3,1..3] de inteiro i, j, Num: inteiro Inicio {Leitura do escalar} Escreva("Digite o valor do escalar: ") Leia(Num) Num = Int(Num) //garante um escalar inteiro Escreval("") {Leitura da matriz M[]} Para i De 1 Ate 3 Faca Para j De 1 Ate 3 Faca Escreva("Digite o elemento [",i,j,"] da matriz M: ") Leia(M[i,j]) FimPara FimPara Escreval("") {Exibe a matriz M} Escreval("Matriz lida") Para i De 1 Ate 3 Faca Para j De 1 Ate 3 Faca Escreva(M[i,j], " ") FimPara Escreval("") FimPara {Faz a multiplicação do escalar Num pela matriz M} Para i De 1 Ate 3 Faca Para j De 1 Ate 3 Faca R[i,j] <- Num*M[i,j] FimPara FimPara Escreval("") {Exibe a matriz R} Escreval("Matriz resultante") Para i De 1 Ate 3 Faca 270 Para j De 1 Ate 3 Faca Se(R[i,j]<10) Entao //apenas para tabular melhor a saída Escreva(R[i,j], " ") Senao Escreva(R[i,j], " ") FimSe FimPara Escreval("") FimPara Escreval("") FimAlgoritmo //fim do programa Figura 6.7b - Saída do programa "MultiplicaMatrizPorEscalar" 2716.5.4 - Multiplicação de Matriz por Vetor A multiplicação de uma matriz por outra matriz não é feita, exatamente, elemento a elemento, correspondentes, como no caso da adição e subtração; para que a multiplicação seja possível é necessário que o número de colunas da primeira seja igual ao número de linhas da segunda. Deste modo, sendo os vetores casos particulares de matrizes, então também é possível multiplicar matriz por vetor, e vice-versa, observando esse detalhe. Observe o esquema da figura 6.8a, mostrando a matriz M do item anterior sendo multiplicada pelo vetor V, resultando numa matriz R.. 1 2 3 1 14 4 5 6 * 2 = 32 7 8 9 3 50 Matriz M Vetor V Matriz R Figura 6.8a - Multiplicação de uma matriz por um vetor O produto é feito [linha*coluna] e somando os resultados de cada produto obtido; observe o esquema abaixo. Matriz A Vetor V Resultado Linha1 → Coluna1: 1*1 + 2*2 + 3*3 = 14 Linha2 → Coluna1: 4*1 + 5*2 + 6*3 = 32 Linha3 → Coluna1: 7*1 + 8*2 + 9*3 = 50 272 Note que a matriz resultando R tem o mesmo número de linhas da primeira (3) e o mesmo número de colunas da segunda (1). Algoritmo "MultiplicaMatrizPorVetor" //Lê uma matriz 3x3 e um vetor de 3 elementos; multiplica //a matriz pelo //vetor. //Autor: Mário Leite //------------------------------------------------------- Var Mat: vetor[1..3,1..3] de inteiro Vet, Resultados: vetor[1..3] de inteiro i, j, Soma: inteiro Inicio Para i De 1 Ate 3 Faca Para j De 1 Ate 3 Faca Escreva("Digite o elemento [",i,",",j,"] da matriz: ") Leia(Mat[i,j]) FimPara FimPara Escreval("") Para i De 1 Ate 3 Faca Escreva("Digite o elemento [",i,"] do vetor: ") Leia(Vet[i]) FimPara Para i De 1 Ate 3 Faca Soma <- 0 Para j De 1 Ate 3 Faca Soma <- Soma + Mat[i,j] * Vet[j] FimPara Resultados[i] <- Soma FimPara Escreval("") Escreval("") Escreval("Matriz resultante") Para i De 1 Ate 3 Faca Escreval(Resultados[i]) FimPara Escreval("") FimAlgoritmo 273 A figura 6.8b mostra a saída do programa "MultiplicaMatrizPorVetor Figura 6.8b - Saída do programa “MultiplicaMatrizPorVetor” 6.5.5 - Multiplicação de Matriz por Matriz Neste caso, uma regra fundamental tem que ser respeitada: “o número de colunas da primeira tem que ser o igual ao número de linhas da segunda”. Por exemplo: para multiplicar uma matriz M1 por outra matriz M2 (M1*M2) o número de colunas de M1 tem que ser igual ao número de linhas de M2. E como o produto de duas matrizes não é comutativo, então, para fazer o produto de M2*M1 o número de colunas de M2 tem que ser igual ao número de linhas de M1. Supondo que M1[L1,C1] seja a primeira matriz e M2[(L2,C2] a segunda; então, o produto M1*M2 só será válido se C1=L2. O resultado será uma matriz M[L1,C2]. 274 O produto entre duas matrizes só será comutativo no caso em que ambas forem quadradas e de mesma dimensão. Para duas matrizes genéricas, A e B, é válida a expressão: (AB)ij = Σ(airbrj) = ai1b1j + ai2b2j + ai3b3j + ... + ainbnj O esquema da figura 6.9a mostra um esquema para obter o produto de duas matrizes A e B, sendo: A com dimensões 3x4 e B com dimensões 4x4, resultando na matriz C(3x4). Figura 6.9a - Esquema de multiplicação de uma matriz por outra Por exemplo, para obter C[1,1], pelo esquema mostrado acima, teremos: C[1,1]= a11b11 + a12b21 +a13b31 + a14b41= 1*1+2*2+ 3*2+4*1 = 15 Então, o resultado para C = A*B será o seguinte: 15 36 51 57 30 72 102 114 24 59 83 92 O programa “MultiplicaMatrizes” é uma solução desse tipo de produto, considerando uma situação em que o número máximo de linhas e de colunas seja 10 (sendo possível alterar esse valor das constantes). 275 Nota: Observe que, devido à restrição de produto de matrizes, a matriz A é a primeira e B a segunda (tal como mostra a figura 6.9a). Assim, o programa faz o produto A*B e não B*A (não faz a validação da possibilidade deste segundo produto). Algoritmo "MultiplicaMatrizes" //Faz o produto de duas matrizes. //Autor: Mário Leite //------------------------------------------------------- Const MAXLIN=10 MAXCOL=10 Var A, B, C: vetor[1.. MAXLIN,1..MAXLIN] de real SomaProd: real i, j, k, LinMatA, ColMatA: inteiro LinMatB, ColMatB: inteiro Inicio {Leitura e validação da matriz A} Repita Escreva("Digite o número de linhas da matriz A [min2-máx",MAXLIN,"]:") Leia(LinMatA) LinMatA <- Int(LinMatA) Ate((LinMatA>=2) e (LinMatA<=MAXLIN)) Repita Escreva("Digite número de colunas da matriz A[min 2-máx",MAXCOL,"]:") Leia(ColMatA) ColMatA <- Int(ColMatA) Ate((ColMatA>=2) e (ColMatA<=MAXCOL)) Escreval("") {Leitura e validação da matriz B} Repita Escreva("Digite número de linhas da matriz B [min 2-máx",MAXLIN,"]:") Leia(LinMatB) LinMatB <- Int(LinMatB) 276 Ate((LinMatB>=2) e (LinMatB<=MAXLIN)) Repita Escreva("Digite número de colunas da B[min 2 máx",MAXCOL,"]:") Leia(ColMatB) ColMatB <- Int(ColMatB) Ate((ColMatB>=2) e (ColMatB<=MAXCOL)) Escreval("") LimpaTela {Leitura da matriz A} Para i De 1 Ate LinMatA Faca Para j De 1 Ate ColMatA Faca Escreva("Entre com o elemento [",i,j,"] da matriz A: ") Leia(A[i,j]) FimPara FimPara Escreval("") {Leitura da matriz B} Para i De 1 Ate LinMatB Faca Para j De 1 Ate ColMatB Faca Escreva("Entre com o elemento [",i,j,"] da matriz B: ") Leia(B[i,j]) FimPara FimPara LimpaTela Escreval("Matriz A na forma tabelar") Para i De 1 Ate LinMatA Faca Para j De 1 Ate ColMatA Faca Escreva(A[i,j], " ") FimPara Escreval("") FimPara Escreval("") Escreval("Matriz B na forma tabelar") Para i De 1 Ate LinMatB Faca Para j De 1 Ate ColMatB Faca Escreva(B[i,j]," ") FimPara Escreval("") FimPara 277 Escreval("") {Faz o produto de A por B} Escreval("") Para i De 1 Ate LinMatA Faca Para j De 1 Ate ColMatB Faca SomaProd <- 0 Para k De 1 Ate ColMatA Faca SomaProd <- SomaProd + A[i,k]*B[k,j] FimPara {Arredonda para duas decimais} Se(SomaProd>=0) Entao C[i,j] <- Int(SomaProd*100+0.50)/100 Senao C[i,j] <- Int(SomaProd*100-0.50)/100 FimSe FimPara FimPara {Exibe a matriz C=A*B na forma tabelar} Escreval("Matriz C=A*B na forma tabelar") Para i De 1 Ate LinMatA Faca Para j De 1 Ate ColMatB Faca Escreva(C[i,j]," ") FimPara Escreval("") FimPara. Escreval("") FimAlgoritmo //fim do programa "MultiplicaMatrizes" A figura 6.9b mostra a saída do programa "MultiplicaMatrizes", baseando nos dados do esquema da figura 6.9a. 278 Figura 6.9b - Saída do programa “MultiplicaMatrizes” 6.6 - Determinantes de Matrizes O determinante de uma matriz é definido como sendo “um número real associado a uma matriz quadrada”. Portanto, o determinante não é o valor de uma matriz; é um valor numérico associado a ela. E para calcular o determinante de uma matriz, o processo utilizado vai depender da ordem (dimensões) dela. 6.6.1 - Determinante de Matrizes de Ordem 2 Para matrizes 2x2 o processo é bem fácil,e a rotina para fazer isto também é simples. Por exemplo, seja a matriz A abaixo na sua forma matricial. 1 2 A = 3 4 279 O programa "Determinante2x2" mostra como esse determinante pode ser calculado. Algoritmo "Determinante2x2" //Calcula o determinante de uma matriz 2x2. //Autor: Mário Leite //------------------------------------------------------ Var MatA: vetor[1..2,1..2] de real SomaPos, SomaNeg, detA: real i, j: inteiro Inicio {Leitura da matriz} Para i De 1 Ate 2 Faca Para j De 1 Ate 2 Faca Escreva("Entre com o elemento [",i,j,"] da matriz: ") Leia(MatA[i,j]) FimPara FimPara LimpaTela {Exibe a matriz lida na forma tabelar} Escreval("Matriz Lida:") Para i De 1 Ate 2 Faca Para j De 1 Ate 2 Faca Escreva(MatA[i,j], " ") FimPara Escreval("") FimPara {Calcula o determinante} SomaPos <- MatA[1,1]*MatA[2,2] SomaNeg <- MatA[2,1]*MatA[1,2] detA <- SomaPos - SomaNeg Escreval("") Escreval("") Escreval("Determinante da matriz lida: ", detA) Escreval("") FimAlgoritmo 280 A figura 6.10 exibe a saída do programa "Determinante2x2" para a matriz A comentada anteriormente. Figura 6.10 - Saída do programa "Determinante2x2" 6.6.2 - Determinante de Matrizes de Ordem 3 Neste caso, a solução mais implementada é através da clássica “Regra de Sarrus”[15],, como indicado no esquema da figura 6.11, onde uma matriz original 3x3 teve suas duas primeiras colunas repetidas para formar um arranjo 3x5. Figura 6.11 - Dispositivo para aplicação da “Regra de Sarrus” 281 As setas apontadas para a direita geram fatores do produto positivo (+) e as apontadas para a esquerda geram fatores do produto negativo (-). O determinante dessa matriz pode ser dado pela seguinte expressão algébrica: det= (a11a22a33+a12a23a31+a13a21a32) - (a13a22a31+a11a23a32+a12a21a33) O programa "Determinante3x3" mostra como esse determinante pode ser calculado, e e o resultado pode ser visto na figura 6.12 para uma matriz 3x3 . Algoritmo "Determinante3x3" //Calcula o determinante de uma matriz de 3x3. //Autor: Mário Leite //------------------------------------------------------- Var MatA: vetor[1..3,1..3] de real SomaPos, SomaNeg, detA: real i, j: inteiro Inicio {Leitura da matriz} Para i De 1 Ate 3 Faca Para j De 1 Ate 3 Faca Escreva("Entre com o elemento [",i,j,"] da matriz: ") Leia(MatA[i,j]) FimPara FimPara LimpaTela {Exibe a matriz lida na forma tabelar} Escreval("Matriz Lida:") Para i De 1 Ate 3 Faca Para j De 1 Ate 3 Faca Escreva(MatA[i,j], " ") FimPara Escreval("") FimPara {Calcula o determinante através da "Regra de Sarrus"} 282 SomaPos <- MatA[1,1]*MatA[2,2]*MatA[3,3] + MatA[1,2]*MatA[2,3]*MatA[3,1] SomaPos <- SomaPos + MatA[1,3]*MatA[2,1]*MatA[3,2] SomaNeg <- MatA[1,3]*MatA[2,2]*MatA[3,1] + MatA[1,1]*MatA[2,3]*MatA[3,2] SomaNeg <- SomaNeg + MatA[1,2]*MatA[2,1]*MatA[3,3] detA <- SomaPos - SomaNeg Escreval("") Escreval("") Escreval("Determinante da matriz lida: ", detA) Escreval("") FimAlgoritmo Figura 6.12 - Saída do programa "Determinante3x3" 6.6.3 - Determinante de Matrizes de Ordem Superior a 3 O programa “CalculaDeterminante”, em Visualg, é uma generalização dos cálculos de determinantes apresentados nos itens anteriores, calculando o determinante de uma matriz mxm de qualquer ordem (m>=2). No caso deste programa, as 283 dimensões da matriz lida foi limitada em 10, mas pode ser generalizado para qualquer número de linhas. Algoritmo "CalculaDeterminante" //Calcula o determinante de uma matriz mxm (m>=2) //Autor: Mário Leite //------------------------------------------------------- Const MAXLIN=10 //limita número de linhas da matriz Var MatA,MatAx:vetor[0..MAXLIN,0..MAXLIN] de real MatOrig: vetor[0..MAXLIN,0..MAXLIN] de real i, j, k, m, Trocas, LinMat, mLin, p, q: inteiro Detmxm, Aux, Fator: real Inicio {Validação e leitura da matriz} Repita Escreva("Digite número de linhas da matriz: ") Leia(LinMat) LinMat <- Int(Abs(LinMat)) Ate((LinMat>=2) e (LinMat<=MAXLIN)) Escreval("") Escreval("") Para p De 1 Ate LinMat Faca Para q De 1 Ate LinMat Faca Escreva("Entre com o elemento [",p,q,"]: ") Leia(MatOrig[p,q]) //matriz original mLin <- LinMat //preserva o número de linhas MatA[p,q] <- MatOrig[p,q] FimPara Escreval("") FimPara {Faz uma cópia da matriz lida para o processamento} Para i De 0 Ate (LinMat-1) Faca Para j De 0 Ate (LinMat-1) Faca MatAx[i,j] <- MatA[i+1,j+1] FimPara FimPara 284 Trocas <- 0 //número de permutas de linhas da matriz {Transforma matriz em triangulo para a "Regra de Chió"} m <- LinMat Para i De 0 Ate (m-2) Faca Se(MatAx[i,i]=0) Entao//detectou elemento [1,1]=0 Para k De i Ate (m-1) Faca //procura um elemento [1,1]<> 0 Se(MatAx[k,i]<>0) Entao Para j De 0 Ate (m-1) Faca //permuta linhas Aux <- MatAx[i,j] MatAx[i,j] <- MatAx[k,j] MatAx[k,j] <- Aux FimPara k <- m FimSe FimPara Trocas <- Trocas + 1 //acumula permutas FimSe Se(MatAx[i,i]<>0) Entao {Converte o elemento [1,1] para 1} Para k De (i+1) Ate (m-1) Faca Fator <- -1*MatAx[k,i]/MatAx[i,i] Para j De i Ate (m-1) Faca MatAx[k,j] <- MatAx[k,j] + (Fator*MatAx[i,j]) FimPara FimPara FimSe FimPara Detmxm <- 1.0 {Calcula o determinante} Para i De 0 Ate (m-1) Faca Detmxm <- Detmxm*MatAx[i,i] FimPara Escreval("") Escreval("") 285 Se(Trocas Mod 2 <> 0) Entao //permuta ímpar de linhas Detmxm <- -Detmxm FimSe LimpaTela {Mostra a matriz na forma tabelar} Escreval(" Matriz original lida:") Para p De 1 Ate mLin Faca Para q De 1 Ate mLin Faca Escreva(MatOrig[p,q], " ") FimPara Escreval("") FimPara Escreval("") Escreval("") Escreval("Determinante da matriz:", Detmxm) FimAlgoritmo //fim do programa "CalculaDeterminante" Figura 6.13 - Saída do programa "CalculaDeterminante" 286 6.7 - Matriz Transposta Dada uma matriz M mxn sua transposta é denotada por MT, tal que M[m,n] é igual a MT[n,m]; isto é, as linhas da matriz M tornam-se colunas na matriz MT e as colunas tornam-se linhas na matriz MT. Matrizes Transpostas são muito importantes na Álgebra Linear, na resolução de cálculos matriciais. O programa “MatrizTransposta” que cria e mostra uma matriz transposta a partir da leitura de uma matriz original. A figura 6.14 mostra a matriz transposta criada a partir da matriz original lida. Em seguida é mostrado o código-fonte do programa, em Visualg Figura 6.14 - Saída do programa "MatrizTransposta" 287 Algoritmo "MatrizTranposta" //Cria a matriz transposta de uma matriz digitada. //Autor: Mário Leite //------------------------------------------------------- Const MaxLin=10 //limita as dimensões da matriz MaxCol=10 Var MatO,MatT:vetor[1..MaxLin,1..MaxCol]de inteiroi, j, LinMat, ColMat: inteiro Inicio Repita Escreva("Digite o número de linhas da matriz [min 2-máx 10]: ") Leia(LinMat) LinMat <- Int((Abs(LinMat)) Ate((LinMat>=2) e (LinMat<=MaxLin)) Repita Escreva("Digite o número de colunas da matriz [min 2 - máx 10]: ") Leia(ColMat) ColMat <- Int(Abs(ColMat)) Ate((ColMat>=2) e (ColMat<=MaxCol)) Escreval("") {Lê a matriz original} Para i De 1 Ate LinMat Faca Para j De 1 Ate ColMat Faca Escreva("Digite o elemento [",i,",",j,"] da matriz: ") Leia(MatO[i,j]) FimPara FimPara Escreval("") {Exibe a matriz original na forma tabelar} Escreval(" Matriz original") Para i De 1 Ate LinMat Faca Para j De 1 Ate ColMat Faca Escreva(MatO[i,j], " ") FimPara Escreval("") FimPara 288 Escreval("") {Cria a matriz transposta} Para i De 1 Ate ColMat Faca Para j De 1 Ate LinMat Faca MatT[i,j] <- MatO[j,i] FimPara FimPara {Exibe a matriz transposta na forma tabelar} Escreval(" Matriz transposta") Para i De 1 Ate LinMat Faca Para j De 1 Ate ColMat Faca Escreva(MatT[i,j], " ") FimPara Escreval("") FimPara Escreval("") FimAlgoritmo 6.8 - Matriz Identidade Matriz identidade é uma matriz quadrada em que todos os elementos da diagonal principal têm valor 1 e o restante dos elementos são todos zeros. Sendo assim, vamos elaborar um programa para criar uma matriz identidade 3x3. O programa “MatrizIdentidade”, da figura 6.15a, mostrado no editor do Visualg, é uma solução para criar uma matriz desse tipo, e a figura 6.15b o resultado da execução deste programa.. 289 Figura 6.15a - Código-fonte do programa "MatrizIdentidade" no editor 290 Figura 6.15b - Matriz Identidade 4x4: Saída de “MatrizIdentidade" 6.9 - Elementos das Diagonais de uma Matriz Os elementos das diagonais de uma matriz são muito importante em algumas situações. O programa “MostrafElementosDasDiagonais" cria uma matriz 4x4 e mostra os elementos das duas diagonais. A figura 6.16 mostra uma saída desse programa, e em seguida seu código-fonte em Visualg, em texto livre. 291 Figura 6.16 - Saída do programa "MostraElementos das Diagonais" 292 Algoritmo "MostraElementoDasDiagonais" //Cria uma matriz quadrada mostra os elementos das //diagonais. //Autor: Mário Leite //------------------------------------------------------- Const MaxLin=10 //limita as dimensões da matriz Var MatNum: vetor[1..MaxLin,1..MaxLin] de inteiro VetPrinc,VetSecun:vetor[1..MaxLin] de inteiro i, j, k, LinMat: inteiro Inicio Repita Escreva("Digite o número de linhas da matriz [min 2 - máx 10]: ") Leia(LinMat) LinMat <- Int(LinMat) Ate((LinMat>=2) e (LinMat<=MaxLin)) Escreval("") {Lê/exibe a matriz} Para i De 1 Ate LinMat Faca Para j De 1 Ate LinMat Faca Escreva("Digite o elemento [",i,",",j,"] da matriz: ") Leia(MatNum[i,j]) FimPara FimPara Escreval("") Escreval(" Matriz original") Para i De 1 Ate LinMat Faca Para j De 1 Ate LinMat Faca Escreva(MatNum[i,j], " ") FimPara Escreval("") FimPara Escreval("") {Cria vetores com elementos das diagonais} k <- 0 Para i De 1 Ate LinMat Faca Para j De 1 Ate LinMat Faca Se(i=j) Entao //elemento da diagonal principal k <- k + 1 293 VetPrinc[k] <- MatNum[i,j] FimSe FimPara FimPara k <- 0 Para i De 1 Ate LinMat Faca Para j De 1 Ate LinMat Faca Se((i+j)=(LinMat+1)) Então //elemento da diagonal secundária k <- k + 1 VetSecun[k] <- MatNum[i,j] FimSe FimPara FimPara {Exibe os elementos das diagonais} Escreval("Elementos da Diagonal Principal:") Para k De 1 Ate LinMat Faca Escreva(VetPrinc[k], " ") FimPara Escreval("") Escreval("") Escreval("Elementos da Diagonal Secundária:") Para k De 1 Ate LinMat Faca Escreva(VetSecun[k], " ") FimPara FimAlgoritmo ❖ Exemplo 6.1 - Ler uma matriz mxn de inteiros e exibir os pares, os ímpares e os primos com suas respectivas posições. 294 Algoritmo "MostraParesImparesPrimosPosicoes" //Lê uma matriz mxn de inteiros e exibe os pares, os ímpares //e os primos com suas respectivas posições. //Autor: Mário Leite //------------------------------------------------------- Const MAXLIN=20 //limita dimensões da matriz MAXCOL=20 Var MatNum: vetor[1..MAXLIN,1..MAXCOL] de inteiro i, j, k, NLin, NCol, TotDiv: inteiro Inicio Repita Escreva("Digite o número de linhas da matriz [min 2 - max",MAXLIN,"]:") Leia(NLin) NLin Int(NLin) Escreva("Digite o número de colunas da matriz [min 2-max",MAXCOL,"]:") Leia(NCol) NCol Int(NCol) Escreva("") Ate((NLin<=MAXLIN) e (NCol<=MAXCOL)) Para i De 1 Ate Nlin Faca Para j De 1 Ate NCol Faca Escreva("Digite o elemento [",i,",",j,"] da matriz: ") Leia(MatNum[i,j]) MatNum[i,j] Int(MatNum[i,j]) FimPara FimPara LimpaTela {Exibe a matriz lida} Escreva("Matriz lida:") Para i De 1 Ate NLin Faca Para j De 1 Ate NCol Faca Escreva(MatNum[i,j], " ") FimPara Escreval("") FimPara 295 Escreval("") Escreval("") Escreval("Tipo do elemento com sua posição:") {Acha e exibir os Pares, os Ímpares e os Primos com suas posições" } Para i De 1 Ate NLin Faca Para j De 1 Ate NCol Faca Se(MatNum[i,j] Mod 2=0) Entao //elemento par Se(MatNum[i,j]=2) Entao Escreval(MatNum[i,j]," ","Par/Primo ","Posição: ","[",i,j,"]") Senao Escreval(MatNum[i,j]," ", "Par ", "Posição: ","[",i,j,"]") FimSe Senao {Verifica se o elemento é primo} TotDiv 0 Para k De 1 Ate MatNum[i,j] Faca Se(MatNum[i,j] Mod k = 0) Entao TotDiv TotDiv + 1 FimSe FimPara Se((TotDiv<3)e(MatNum[i,j]<>1))Entao //O elemento é primo Escreval(MatNum[i,j]," ","Primo ","Posição: ","[",i,j,"]") Senao Escreval(MatNum[i,j]," ","Ímpar ","Posição: ","[",i,j,"]") FimSe FimSe FimPara FimPara Escreval("") FimAlgoritmo //fim do programa 296 A figura 6.17 mostra uma saída do programa "MostraParesImparesPrimosPosicoes". Figura 6.17 - Saída do "MostraParesImparesPrimosPosicoes" ❖ Exemplo 6.2 - Criar uma matriz quadrada com as diagonais (principal e secundária) formadas pela letra "X". O programa "CriaMatrizX" é uma solução para o Exemplo 6.2. Observe que, de acordo com a matemática, os elementos da diagonal da matriz sempre terão índices i,j iguais (i=j); então, é através dessa lógica que a solução do problema se desenvolve. 297 Algoritmo "CriaMatrizX" //Cria uma matriz quadrada apenas com as diagonais formadas //pela letra "X". //Autor: Mário Leite //-------------------------------------------------------Var MatX: vetor[1..20,1..20] de caractere i, j, NLin: inteiro m: real Inicio m <- 1 Enquanto ((m<5) ou (m>20)) Faca Escreva("Digite o número de linhas da matriz:") Leia(m) FimEnquanto Escreval("") Se(NLin Mod 2 = 0) Entao //procura o próximo ímpar NLin <- NLin + 1 FimSe {Criação/impressão da matriz de "X"} Para i De 1 Ate NLin Faca Para j De 1 Ate NLin Faca Se((i=j) ou (i+j=NLin+1)) Entao MatX[i,j] <- "X" Senao MatX[i,j] <- " " FimSe Escreva(MatX[i,j], " ") FimPara Escreval("") FimPara Escreval("") Escreval("") FimAlgoritmo 298 A figura 6.18 mostra uma saída do programa "CriaMatrizX" para matriz 12x12 Figura 6.18 - Saída do programa "CriaMatrizX" 6.10 - Exercícios Propostos 1 - O que são matrizes? Qual é a diferença entre matrizes e vetores? 2 - Como se declara uma matriz no Visualg? 3 - As matrizes podem ter algum elemento de tipo diferente dos demais? Explique. 4 - Dê um exemplo de uma matriz quadrada. 5 - Leia dois vetores de inteiros de tamanho dez e crie uma matriz, de modo que as colunas dessa matriz seja formada por esses dois vetores. 299 6 - Observe as alternativas de declarações de uma matriz Mat[ ] abaixo, e marque qual delas está correta na sintaxe do Visualg. A ( ) Var Mat: vetor[1..5,1..4] de inteiro B ( ) Var Mat: mat[1..5,1..4] de inteiro C ( ) Var Mat: vetor[5,4] de logico D ( ) Var Mat: vetor[1..5:1..4] de caractere E ( ) Var Mat: mat[1..5:1..4] de real 7 - Observe o programa “ZZZ” abaixo e explique qual é o objetivo da estrutura de decisão composta, em destaque no código-fonte. Algoritmo "ZZZ" Var MatD: vetor[1..7,1..7] de caractere i, j: inteiro Inicio Para i De 1 Ate 7 Faca Para j De 1 Ate 7 Faca Se((i=j) ou (i+j=8)) Entao MatD[i,j] <- "X" Senao MatD[i,j] <- " " FimSe Escreva(MatD[i,j], " ") FimPara Escreval("") FimPara FimAlgoritmo 8 - O programa abaixo foi feito para criar a matiz transposta de uma matriz quadrada lida pelo teclado, de no máximo cinco linhas. Complete o código nas linhas tracejadas. 300 Algoritmo "MatrizTranposta" //Cria a matriz transposta de uma matriz digitada. //------------------------------------------------------- Var MatO, MatT: vetor[1..5,1..5] de inteiro i, j, LinMat, ColMat: inteiro Inicio Repita Escreva("Digite o número de linhas da matriz [min 2-máx 5]: ") Leia(LinMat) LinMat <- Int(LinMat) Ate((LinMat>=2) e (LinMat<=5)) Escreval("") LimpaTela {Lê a matriz original MatO} Para i De 1 Ate LinMat Faca Para j De 1 Ate LinMat Faca Escreva("Digite o elemento [",i,",",j,"] da matriz: ") Leia(MatO[i,j]) FimPara FimPara Escreval("") {Exibe a matriz original na forma tabelar} Escreval(" Matriz original") Para i De 1 Ate LinMat Faca Para j De 1 Ate LinMat Faca Escreva(MatO[i,j], " ") FimPara Escreval("") FimPara Escreval("") {Cria a matriz transposta MatT} ------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------ 301 {Exibe a matriz transposta na forma tabelar} Escreval(" Matriz transposta") Para i De 1 Ate LinMat Faca Para j De 1 Ate LinMat Faca Escreva(MatT[i,j], " ") FimPara Escreval("") FimPara Escreval("") FimAlgoritmo 9 - Observe a tabela abaixo, que mostra as notas obtidas por um aluno em três disciplinas ao longo de oito meses. Crie um programa que mostre as médias desse aluno em cada disciplina, para esses valores de notas. Disciplina/Mês Mar Abr Mai Jun Ago Set Out Nov Português 8.3 7.8 7.0 6.9 8.0 7.5 7.0 8.8 Matemática 7.5 7.8 7.9 7.2 8.2 7.2 8.5 8.4 Informática 9.0 8.7 8.8 8.6 8.4 9.3 9.0 8.7 Tabela Disciplina x Mês com as respectivas notas 10 - Crie um programa que exiba uma matriz quadrada de dez colunas, tal que as linhas ímpares sejam formadas pela letra “X”, e as linhas pares pela letra “Y”. 11 - Observe o código-fonte do programa abaixo, e explique o que ele faz. 302 Algoritmo "CriaMatriz" Var i, j, k, m, x, y: inteiro Matriz: vetor[1..10,1..10] de inteiro a: logico Inicio LimpaTela Repita Escreva("Digite um valor inteiro e positivo: ") Leia(m) Ate((m>=2) e (m<=10)) Para j De 1 Ate m Faca Para k De 1 Ate m Faca a <- Falso Enquanto (Nao(a)) Faca Repita Escreva("Digite um número inteiro e positivo: ") Leia(x) Ate(x<>0) x <- Abs(Int(x)) y <- 0 Para i De 1 Ate x Faca Se(x Mod i = 0) Entao y <- y + 1 FimSe FimPara Se(y=2) Entao Matriz[j,k] <- x a <- Verdadeiro FimSe FimEnquanto FimPara FimPara Para j De 1 Ate m Faca Para k De 1 Ate m Faca Escreva(Matriz[j,k], " ") FimPara Escreval("") FimPara FimAlgoritmo 303 Capítulo 7 - Trabalhando com Registros 7.1 - Introdução ao Capítulo Embora o termo “registro” seja considerado, por alguns, como um assunto avançado de “estrutura de dados” em cursos de Sistemas de Informações e Ciência da Computação, aqui ele será mostrado como uma extensão e complemento de vetores e matrizes, para mostrar que vários tipos de dados podem ser reunidos em um cadastro, representado por uma variável especial: variável-registro. O Visualg oferece recursos para trabalhar com com esse tipo de dado heterogêneo, tal como uma linguagem de programação real. Neste capítulo serão mostrados vários exemplos de como utilizar um registro. 7.2 - Conceitos Básicos Os dois capítulos anteriores focalizaram elementos que definem uma estrutura de dados homogênea (vetores e matrizes). Naqueles casos, embora a variável pudesse armazenar muitos valores ao mesmo tempo, todos os valores tinham que ser de um mesmo tipo de dado. Entretanto, existem situações em que há necessidade de trabalhar com valores de tipos de dados diferentes numa mesma variável; nesses casos as estruturas homogêneas não podem ser empregadas; utiliza-se estruturas heterogêneas, definidas pelos registros. Um registro define as especificações de uma variável composta de “campos” que podem ser de diferentes tipos de dados. Assim, um conjunto de registro define uma tabela, tal como acontece num ambiente de banco de dados, com valores de tipos diferentes. Por exemplo, seja uma turma de alunos em que cada um deles 304 tenha, obrigatoriamente, os seis seguintes dados cadastrais, com os respectivos tipos de dados: • Matricula (inteiro) • Nome (caractere) • Sexo (caractere) • Data de nascimento (caractere) • Renda Familiar (real) • Transferido (logico) Deste modo, observe que uma variável do tipo array (vetor ou matriz) não poderia ser utilizada para manipular o cadastro de um aluno, pois os dados são de tipos diversas; mas, utilizando um registro isto é perfeitamente possível. A criação de um registro é conhecida no ambiente de desenvolvimento como “criação de um novo tipo de dado”, pois, é isto o que efetivamente é feito. O esquema a seguir mostra como deve ser criada uma estrutura do tipo registro no Visualg. Palavra-chave que define um novo tipo de dadoIndica que é um registro Tipo NomeRegistro = registro campo1: tipo campo2: tipo campo3: tipo - - - campos com seus tipos - - - campoN: tipo FimRegistro fim da estrutura do registro NomeRegistro é o identificador (nome) do registro, tal como o de uma variável simples. 305 7.3 - Manipulação de Registros Para trabalhar com registros são necessários dois passos: 1) Criar o registro; 2) Cria uma variável do tipo-registro. Só DEPOIS de executar esses dois passos é que se pode trabalhar com o registro, manipulando uma variável-registro. Como exemplo, será criado o registro de um aluno com os dados sugeridos anteriormente: Matrícula, Nome, Sexo, Data de Nascimento, Renda familiar e Transferido; estes dados são chamados campos do registro. 1 - Criação do registro: Tipo TAluno = registro matric: inteiro nome: caractere sexo: caractere nasc: caractere renda: real transf: logico FimRegistro 2 - Criação da variável-registro Var Aluno: TAluno Portanto, só DEPOIS desses dois passos é que o registro poderá ser utilizado no programa, com a inicialização dos campos da variável-registro através de atribuições diretas ou de leituras de seus campos. 306 Nota: Observe que para o identificador da variável-registro foi usado o termo “Aluno”, retirando apenas o “T” do identificador do registro. Este será o estilo empregado aqui neste livro (estilo dos autores) e não uma regra geral. Os identificadores, tanto do registro quanto da variável-registro, podem ser quaisquer, desde que diferentes um do outro e obedecendo as regras de identificação de variáveis. Por exemplo, poderia ser “CadastroGeral” para o identificador do registro e simplesmente “Aluno” para a variável-registro. Entretanto, como regra de boa programação e estilo, é melhor que o identificador da variável-registro fique ligada ao identificador do registro, tornando a manutenção e percepção do programa muito mais fácil para o programador. Para o identificador do registro foi considerado o estilo Pascal/Delphi, onde o T (maiúsculo) indica Tipo, oriundo das linguagens da linha turbo: Turbo Pascal, Turbo C, Turbo Basic, etc. Outro detalhe, muito importante a ser observado é como os dados devem ser atribuídos para serem armazenados na variável- registro. variável-registro.campo ← valor ponto de ligação O ponto de ligação (.) vincula o campo à variável-registro em questão. O valor tem que ser do mesmo tipo de dado do respectivo campo que o está “recebendo”; se não dará erro de “incompatibilidade de dado”. Por exemplo, para atribuir, ou ler o sexo de um aluno: 307 Aluno.sexo ← "F" //atribuição direta Leia(Aluno.sexo) //leitura pelo teclado O programa "CadastroAlunos", na figura 7.1, mostra um exemplo básico e bem simples (sem validações) de como fazer o cadastro de 25 alunos, baseado no registro sugerido anteriormente. Figura 7.1 - Código-fonte do programa “CadastroAlunos” no editor 308 Observem que, por não ser um tipo de dado primitivo, o tipo de dado da variável-registro não aparece sublinhado no editor do Visualg. E conforme foi dito anteriormente, o programa “CadastroAlunos”, não faz nenhuma validação dos dados entrados; mas, na prática, essas validações são muito importantes para evitar erros drásticos nos resultados esperados. Por exemplo, se não for validado o “sexo” do aluno o usuário poderia entrar com qualquer letra (“X”, “Y”, “Z”, etc), e na hora de listar os alunos de um dos sexos (“M” ou “F”) a listagem sairia incompleta, pois não seriam considerados alunos com sexo diferente de “M” e “F”. Também, a data de nascimento esta deve ser SEMPRE validada para evitar um “dia” com valor inferior a 28 ou superior a 31, um “mês” com valor inferior a 1 ou superior a 12, e assim por diante. O mesmo vale para os outros campos. Deve ficar bem claro que pode ser criado um registro agregando vários tipos de dados nos seus campos, inclusive arrays[16]. Fazendo uma comparação: enquanto nas matrizes cada elemento é individualizado através de seus índices, num registro cada campo é individualizado pela referência ao nome de uma variável do tipo registro, como na figura 7.2 mostra uma representação “física” dos dados de um empregado. Figura 7.2 - Exemplo de uma ficha de um empregado como um registro 309 7.4 - Conjunto de Registros A figura 7.2 representa uma fica com os dados de apenas 1 (um) empregado; portanto, UM registro de uma entidade. Para vários empregados (equivalente a uma tabela no ambiente de Banco de Dados) é necessário que a variável-registro seja um array, como foi feito no programa “CadastroAlunos”. Por exemplo, suponhamos um conjunto de 300 empregados; então a variável registro deverá ser um vetor com 300 elementos. Tipo TEmpregado = registro nome: caractere matr: inteiro sexo: caractere situa: caractere ende: caractere cidade: caractere estado: caractere cep: caractere func: caractere sala: real admis: caractere setor: caractere FimRegistro Var: Empregado: vetor[1..300] de TEmpregado O conceito de registro pode ser aplicado para fazer pesquisa de valores. Os “campos” de um registro se comportam tal como os campos de uma tabela, fisicamente representados por colunas, enquanto cada registro representa uma linha dessa tabela. A tabela 7.1 ilustra um exemplo de tabela dos dados de quatorze funcionários. 310 Matrícula Nome Setor Salário 1235-20 Cremilda Martins de Souza Contabilidade 1.985,50 1236-19 Creuza da Conceição Dias Pessoal 1.990,35 1237-20 Expedito Cassim de Oliveira Vendas 3.100,32 1238-20 Jefferson de Oliveira Santos Produção 2.875,34 1239-19 Juvino Pereira Alves Almoxarifado 2.860,45 1240-19 Lucycleide Pereira da Costa Pessoal 3.210,54 1241-20 Marinete Correa de Castro Vendas 3.350,40 1242-18 Marlene Figueira Alves Perucci Almoxarifado 2.880,29 1243-19 Ronilson Marques Pereira Contabilidade 1.950,47 1244-18 Rosicleide Maria de Jesus Pessoal 1.954,75 1245-18 Sidnelson Correa de Castro Produção 2.982,75 1246-20 Jucimário Correa de Castro Pessoal 2.150,48 1247-19 Cleonice Romão Santana Vendas 3.420,45 1248-19 Dioney P. dos Santos Pacheco Produção 2.874,42 Tabela 7.1 - Exemplo de uma tabela com dados de funcionários Assim, de acordo com a tabela 7.1, a definição de um (apenas um) registro que representará TODOS com as mesmas características, é definido, assim, no Visualg: 311 Tipo TFuncionarios: registro matricula: caractere nome: caractere setor: caractere salario: real FimRegistro A estrutura acima define um registro; e uma variável do tipo registro, que alocará valores na memória, por exemplo, Func, será assim definida: Var Func: TFuncionarios E para trabalhar com vários registros, na prática (tal como a tabela 7.1), a variável-registro deverá se um vetor, assim:: Var VetFunc: vetor[1..14] de TFuncionarios Nota: O identificador VetFunc foi assim definido, apenas para diferenciar da variável de um registro simples, como o anterior, (para apenas um registro); mas, poderia ser Func também, desde que definida como vetor. 7.5 - Leitura de um Conjunto de Registros A leitura de um conjunto de registros é feita mediante um loop que varre todos os registros do conjunto, campo a campo. O programa “LeEmpregados” mostra como pode ser feito. dentro de um loop com o seguinte formato: 312 Algoritmo "LeEmpregados" //Lê um conjunto de registros sem validações. //Autor: Mário Leite //------------------------------------------------------- Tipo TEmpregado = registro nome: caractere matr: inteiro sexo: caractere situa: caractere ende:caractere cida: caractere uf: caractere cep: caractere func: caractere sala: real admis: caractere setor: caractere FimRegistro Var Empregado: vetor[1..300] de TEmpregado j: inteiro Inicio {Loop de leitura dos dados dos empregados} Para j De 1 Ate 300 Faca Escreva("Entre a matrícula do empregado: ") Leia(Empregado[j].matr) Escreva("Entre o nome do empregado: ") Leia(Empregado[j].nome) Escreva("Entre o sexo do empregado: ") Leia(Empregado[j].sexo) Escreva("Entre a situação atual do empregado [Efetivo/Temporário: ") Leia(Empregado[j].situa) Escreva("Entre com endereço do empregado: ") Leia(Empregado[j].ende) Escreva("Entre com a cidade do empregado: ") Leia(Empregado[j].cida) Escreva("Entre com o estado: ") Leia(Empregado[j].uf) Escreva("Entre com o CEP do endereço: ") Leia(Empregado[j].cep) 313 Escreva("Entre com a função do empregado: ") Leia(Empregado[j].func) Escreva("Entre com o salário bruto: ") Leia(Empregado[j].sala) Escreva("Entre com a data de admissão: ") Leia(Empregado[j].admis) Escreva("Entre com o nome do setor: ") Leia(Empregado[j].setor) Escreval("") //salta linha para um novo registro FimPara //fim do loop de leitura dos dados dos Escreval("") FimAlgoritmo ❖ Exemplo 7.1 - O programa "ControleEmpregados" faz o registro de cinco empregados e calcula: Valor da folha de pagamento, maior salário, menor salário e salário médio. Algoritmo "ControleEmpregados" //Faz o registro de vários empregados e calcula: valor //da folha de pagamento maior salário, menor salário e //salário médio. //Autor: Mário Leite //----------------------------------------------------- Tipo TEmpregado = registro Matr: inteiro Nome: caractere Salario: real FimRegistro Var Empregado: TEmpregado j,k, n: inteiro SalMedio, Maior, Menor, Soma: real NomeMa, NomeMe: caractere Inicio Escreva("Entre com o número de empregados: ") Leia(n) //considere n válido Escreval("") Soma <- 0 Para j De 1 Ate n Faca 314 Escreva("Entre com o nome do empregado: ") Leia(Empregado.Nome) Escreva("Entre com a matrícula de ", Empregado.Nome, ": ") Leia(Empregado.Matr) Repita Escreva("Entre com o salário de ", Empregado.Nome, ": ") Leia(Empregado.Salario) Ate(Empregado.Salario>0) Soma <- Soma + Empregado.Salario Se(j=1) Entao //é o primeiro empregado!? Maior <- Empregado.Salario Menor <- Empregado.Salario NomeMa <- Empregado.Nome NomeMe <- Empregado.Nome FimSe Se(Empregado.Salario>Maior) Entao Maior <- Empregado.Salario NomeMa <- Empregado.nome FimSe Se(Empregado.Salario<Menor) Entao Menor <- Empregado.Salario; NomeMe <- Empregado.Nome FimSe Escreval("") FimPara //salta linha para ler um novo registro SalMedio <- Soma/n LimpaTela Escreval("Relatório final sobre a Folha Salarial") Escreval("----------------------------------") Escreval("Maior salário: ",Maior,"==>", NomeMa) Escreval("Menor salário:",Menor,"==>", NomeMe) Escreval("Folha de pagamento: ", Soma:4:2) Escreval("Salário médio: ", SalMedio:4:2) Escreval("") FimAlgoritmo 315 As figuras 7.3a e 7.3b mostram, respectivamente, as entradas para cinco empregados e a saída do programa Figura 7.3a - Entradas para o programa "ControleEmpregados" 316 Figura 7.3b - Saída do programa "ControleEmpregados" ❖ Exemplo 7.2 - Considerar cinco alunos, cada um cadastrado com os seguintes dados: • nome (caractere) • nota1 (real) • nota2 (real) • nota3 (real) • nota4 (real) O programa terá que ler os dados de cinco alunos, calcular a média aritmética das notas de cada um deles, e verificar se foi “Aprovado” (média maior ou igual de 7) ou “Reprovado” (média 317 menor que 7). O programa “MediaRegistro”, mostrado na figura 7.4, é uma solução para o problema do Exemplo 7.2. Figura 7.4 - Código-fonte do programa “MediaRegistro” no editor 318 7.6 - Pesquisa em Conjunto de Registros A pesquisa num conjunto de registro pode ser feita em função de algum campo, semelhantemente ao caso de arrays. É claro que a pesquisa deve ser feita por um campo que tenha um valor único; na maioria dos casos uma chave. Considere uma empresa com 200 funcionários, onde cada um tem uma ficha com os dados: • Matrícula (inteiro) • Nome (caractere) • Setor (caractere) • Salario (real) O programa “PesqFuncionario” faz a leitura, ordena os registros e faz pesquisa de um determinado funcionário. Algoritmo "PesqFuncionario" //Pesquisa um funcionário pela sua matrícula no cadastro //de uma empresa. //Autor: Mário Leite //------------------------------------------------------- Tipo TFunc = registro matric: inteiro nome: caractere setor: caractere salario: real FimRegistro Var Func: vetor[1..100] de TFunc //define variável- vetor de registro i, j, Local, Mat, PosIni, PosFim, PosCent, AuxMatric: inteiro AuxNome, AuxSetor: caractere AuxSalario: real Achou: logico Inicio {Loop para leitura dos dados dos funcionários} Para j De 1 Ate 5 Faca //considera 5 funcionários Escreva("Digite a matrícula do funcionário: ") Leia(Func[j].matric) 319 Repita //valida matricula Escreva("Digite a matrícula do funcionário: ") Leia(Func[j].matric) Ate(Func[j].matric)>0) Escreva("Digite o nome do funcionário: ") Leia(Func[j].nome) Escreva("Digite o setor do funcionário: ") Leia(Func[j].setor) Repita Escreva("Digite o salário do funcionário: ") Leia(Func[j].salario) Ate((Func[j].salario)>0) Escreval("") //salta linha para um novo funcionário FimPara //fim do loop para leitura dos dados Escreval("") Escreva("Entre com a matrícula a ser pesquisada:") Leia(Mat) {Ordena funcionários pela matr para "Pesquisa Binária"} Para i De 1 Ate 4 Faca Para j De (i+1) Ate 5 Faca Se(Func[i].matric>Func[j].matric) Entao {Salva dados em variáveis auxiliares antes AuxMatric <- Func[i].matric AuxNome <- Func[i].nome AuxSetor <- Func[i].setor AuxSalario <- Func[i].salario {Faz a trocas} Func[i].matric <- Func[j].matric Func[j].matric <- AuxMatric Func[i].nome <- Func[j].nome Func[j].nome <- AuxNome Func[i].setor <- Func[j].setor Func[j].setor <- AuxSetor Func[i].salario <- Func[j].salario Func[j].salario <- AuxSalario FimSe FimPara FimPara Escreval("") Local <- 0 PosIni <- 1 320 PosFim <- 5 //número de funcionários Achou <- Falso {Loop para fazer a pesquisa} Enquanto ((PosIni<=PosFim) ou (Achou=Falso)) Faca PosCent <- Int((PosIni+PosFim)/2) Se(Func[PosCent].matric=Mat) Entao Achou <- Verdadeiro Local <- PosCent Interrompa Senao Se(Func[PosCent].matric>Mat) Entao PosFim <- PosCent - 1 Senao PosIni <- PosCent + 1 FimSe FimSe FimEnquanto //fim do loop de pesquisa} {Verifica o funcionário pesquisado} Se(Local<>0) Entao Escreval("Funcionário ",Func[PosCent].nome," já cadastrado") Escreval("Matrícula: ",Func[PosCent].matric) Escreval("Setor: ",Func[PosCent].setor) Escreval("salário:",Func[PosCent].salario) Senao Escreval("Funcionário matrícula ", Mat, " NÃO está cadastrado") FimSe Escreval("") FimAlgoritmo //fim do programa "PesqFuncionario" Nota: No programa "PesqFuncionario" a pesquisa de um funcionário foi feita através do método de “Pesquisa Binária”; e por imposição desse método, o conjunto de registros teve que ser previamente ordenado em ordem crescente, que nesse caso foi utilizado o método “Bubble Sort” Também é importante observar que para fazer a ordenação foram empregadas variáveis auxiliares antes de fazer as trocas exigidas por esse método de ordenação pois, caso contrário, os campos dos registros ficariam “bagunçados” e sem sincronia com o nome. 321 Figura 7.5 - Saída do programa "PesqFuncionario” ❖ Exemplo 7.3 - Ler os dados de cinco alunos (matrícula, nome, sexo, turma) e listar seus nomes e suas médias em ordem decrescente de médias. 322 Algoritmo "OrdenaMedias" //Lê alunos de uma turma, calcula suas médias, e exibe os //nome com suas respectivas médias em ordem decrescente. //Autor: Mário Leite //------------------------------------------------------- Tipo TAluno = registro matr: inteiro nome: caractere sexo: caractere turma: caractere nota1: real nota2: real nota3: real nota4: real media: real FimRegistro Var i, j, k , Cont: inteiro Aluno: vetor[1..5] de TAluno Medias: vetor[1..5] de real Aux2, SomaNotaAlu: real Aux1: caractere Inicio Para i De 1 Ate 5 Faca //teste com apenas 5 alunos Repita Escreva("Digite a matrícula do aluno: ") Leia(Aluno[i].matr) Ate(Aluno[i].matr>0) Repita Escreva("Digite o nome do aluno: ") Leia(Aluno[i].nome) Ate(Aluno[i].nome<>"") //evita nome em branco Repita Escreva("Digite o sexo do aluno [M/F]: ") Leia(Aluno[i].sexo) Aluno[i].sexo <- Maiusc((Aluno[i].sexo)) Ate((Aluno[i].sexo="M") ou (Aluno[i].sexo="F")) Repita Escreva("Digite a turma do aluno: ") Leia(Aluno[i].turma) Ate(Aluno[i].turma<>"") 323 SomaNotaAlu <- 0.00 Repita Escreva("Digite a primeira nota de ",Aluno[i].nome,": ") Leia(Aluno[i].nota1) Ate((Aluno[i].nota1>=0) e (Aluno[i].nota1<=10)) Repita Escreva("Digite a segunda nota de ",Aluno[i].nome,": ") Leia(Aluno[i].nota2) Ate((Aluno[i].nota2>=0) e (Aluno[i].nota2<=10)) Repita Escreva("Digite a terceira nota de ",Aluno[i].nome,": ") Leia(Aluno[i].nota3) Ate((Aluno[i].nota3>=0) e (Aluno[i].nota3<=10)) Repita Escreva("Digite a quarta nota de ",Aluno[i].nome,": ") Leia(Aluno[i].nota4) Ate((Aluno[i].nota4>=0) e (Aluno[i].nota4<=10)) SomaNotaAlu <- SomaNotaAlu + Aluno[i].nota1 + Aluno[i].nota2 SomaNotaAlu <- SomaNotaAlu + Aluno[i].nota3 + Aluno[i].nota4 Medias[i] <- (SomaNotaAlu/4) Aluno[i].media <- Medias[i] Escreval("") //salta linha para ler novos dados FimPara {Classifica médias em ordem decrescente com nomes} Para j De 1 Ate 5 Faca Para k De (j+1) Ate 4 Faca Se(Aluno[j].media < Aluno[k].media) Entao {Preserva os campos antes das trocas} Aux1 <- Aluno[j].nome Aux2 <- Aluno[j].media {Faz as trocas para ordenar} Aluno[j].nome <- Aluno[k].nome Aluno[k].nome <- Aux1 Aluno[j].media <- Aluno[k].media Aluno[k].media <- Aux2 FimSe 324 FimPara FimPara Escreval("") Escreval("Nomes e médias:") Para i De 1 Ate 5 Faca Escreval(Aluno[i].nome," ",Aluno[i].media:4:1) //com uma decimal FimPara Escreval("") FimAlgoritmo //fim do programa "OrdenaMedias" A figura 7.6 mostra um exemplo de saída do programa “OrdenaMedias”. 325 Figura 7.6 - Saída do programa “OrdenaMedias” 326 7.7 - Exercícios Propostos 1 - O que é são estruturas Heterogêneas e Homogêneas no Visualg? 2 - Qual é a maior vantagem de se usar uma Estrutura Heterogênea? 3 - Depois de definir um registro, ainda é necessário usar vetores individuais no Visualg? Explique! 4 - Monte um programa que calcule a média aritmética usando um registro para até 10 alunos diferentes e com quatro notas. 5 - Sabendo que TProduto é o nome de um registro que controla os dados de um produto, marque a instrução correta, em Visualg, para definir uma variável desse tipo. A ( ) Var Produto: vetor[1..5:1..4] de real B ( ) Var Produto: inteiro C ( ) Var Mat: vetor[5,4] de TProduto D ( ) Var: vetor[1..5] de TProduto E ( ) Var Produto: TProduto 6 - Sabendo que TFuncionario é uma estrutura de registros para os funcionários de uma empresa, então marque a alternativa correta que pode indicar atribuição de um valor ao salário do décimo primeiro funcionário da empresa. A ( ) Salario <- Funcionario[11] B ( ) Salario[11] <- TFuncionario C ( ) Func[11].salario <- valor D ( ) Salario <- Func.salario[11] E ( ) Func.Salario[11] <- TFuncionario 7 - Crie uma estrutura heterogênea para cadastro de um professor, e que contenha seis campos. 327 Capítulo 8 - Modularização 8.1 - Introdução ao Capítulo O objetivo da Programação Modular é criar pequenos módulos e agregá-los de maneira lógica, até conseguir compor a aplicação como um todo. É como construir a fachada de uma casa com azulejos; cada azulejo seria um módulo, e a agregação de todos eles resultaria na fachada da casa. O mesmo raciocínio pode ser aplicado na construção de um software a partir de pequenos módulos funcionais, que por sua vez podem ser construídos a partir de outros módulos menores. A essência desse tipo de programação é conseguir criar unidades independentes, funcionais e o mais genéricas possíveis para serem empregados em sistemas maiores. Esta técnica facilidade muito as manutenções dos programas, além de oferecer diversos tipos de benefícios e vantagens no desenvolvimento de grandes sistemas: Permite o reaproveitamento de códigos já construídos; o trabalho seria apenas o de “encaixá-los” no programa. • Evita que um bloco de código seja repetido várias vezes num mesmo programa. • Permite alterações no programa de forma mais rápida, localizando o erro pontual e isolando-o de outros blocos. • Limita o tamanho dos blocos de instruções melhorando, consideravelmente, a legibilidade e, por conseguinte, a manutenção do sistema. • Permite separar o programa em partes que podem ser logicamente compreendidas de forma encapsulada. 328 8.2 - Conceitos Básicos Todos os programas em Visualg apresentados anteriormente formavam um bloco único de linhas de códigos, começando com a instrução Algoritmo “NomeDoPrograma” e terminando com FimAlgoritmo. Este é o modelo básico de um programa do tipo stand-alone no Visualg, indicando um único módulo (o principal), identificado em “NomeDoPrograma”. Um programa desse tipo é aquele em que só existe um bloco com várias linhas de instruções; o programa principal (obrigatório). Assim, ao carregar (rodar) o programa, o Visualg começa a ler/interpretar/executar cada linha de código desde a palavra- chave Algoritmo até FimAlgoritmo. Um programa, assim concebido, pode se tornar tão complexo e com tantas linhas de códigos, que sua manutenção (devido à algum bug) pode ficar muito difícil e trabalhosa para o programador. A ideia, então, é a de “quebrar” o programa em partes, de modo que elas possam se comportarcomo “programinhas” independentes mas, ligados ao programa principal de maneira lógica e funcional, executando linhas de código para cumprir tarefas específicas. Por exemplo, se o programa, em geral, é para somar os n primeiros números primos, então pode existir um “programinha” específico, dentro do programa geral só para verificar se um desses n números é primo; se for, ele será somado; se não for, não será somado. Deste modo, todas as vezes que precisar verificar se um determinado número é primo, esse “programinha” será chamado para fazer essa verificação e reportar ao “programa principal”, ou a qualquer outro “programinha” que o chamou. Essa técnica é chamada de “Modularização”, obrigatória em todos os sistemas que envolvam mais de uma rotina (programa), como é o caso da maioria dos sistemas comerciais. 329 8.3 - Dividir para Unificar De acordo com a Enciclopédia Livre Wikipédia “Em política e sociologia, dividir para conquistar (ou dividir para reinar), consiste em ganhar o controle de um lugar através da fragmentação das maiores concentrações de poder, impedindo que se mantenham individualmente. O conceito refere-se a uma estratégia que tenta romper as estruturas de poder existentes e não deixar que grupos menores se juntem” No ambiente de desenvolvimento de programas também é muito importante dividir (fragmentar) um programa grande, que possui muitas linhas de código, em fragmentos (partes) menores com especificidades individuais, porém, mantendo o objetivo final do programa, para o bem comum. Fundamentalmente, isto significa observar um dos quatro pilares do Método Cartesiano[17] que diz: “Analisar, ou seja, dividir ao máximo as coisas, em suas unidades de composição, fundamentais, e estudar essas coisas mais simples que aparecem”. Em outras palavras, essas “coisas mais simples” devem trabalhar individualmente, com suas tarefas particulares, mas, integrada ao programa como um TODO. 8.4 - Programação Modular Programação Modular, baseada no método bottom-up (de baixo para cima), é uma técnica de escrita de código em que o desenho do software é feito a partir de módulos independentes; em outras palavras, na Programação Modular é aplicada a abordagem cartesiana em vez da abordagem sistêmica. O objetivo da Programação Modular é criar pequenos módulos e agregá-los de maneira lógica para criar módulos cada vez maiores até conseguir compor o programa como um TODO. É como construir uma parede com tijolos; cada tijolo seria um módulo, e a agregação de https://pt.wikipedia.org/wiki/Pol%C3%ADtica https://pt.wikipedia.org/wiki/Sociologia 330 todos eles resultaria na parede desejada. O mesmo raciocínio pode ser aplicado na construção de um software a partir de pequenos módulos funcionais, que por sua vez podem ser construídos a partir de outros, menores ainda. Em resumo, a Programação Modular começa com as partes para se conseguir o TODO; sua essência é criar módulos independentes, funcionais, e o mais genéricos possíveis para serem empregados em sistemas maiores. Isto tem um preço: o tempo de desenvolvimento é maior do que em outros paradigmas de programação, mas, por outro lado, uma vez criados esses módulos podem ser reutilizados. Nota: Um tipo de programação modular é a chamada “Programação Orientada a Objetos” (OOP, na sigla em Inglês), onde os módulos são entes chamados de “objetos” que herdam características (atributos) e operações(métodos) definidas por uma classe. A construção de uma casa pode ser usada para explicar a importância da modularização no desenvolvimento dos programas de computador. Observe as figuras 8.1a e 8.1b; elas mostram o esquema de uma casa com apenas um cômodo, e a mesma constituída de cômodos, respectivamente. Figura 8.1a - Casa com apenas um cômodo Fonte: “Curso Básico de Programação-Teoria e Prática”, 2017, Mário Leite 331 Figura 8.1b - Casa com vários cômodos separados Fonte: “Curso Básico de Programação-Teoria e Prática”, 2017, Mário Leite Observando as duas figuras acima, fica evidente que uma casa construída em cômodos (módulos) é bem mais agradável e mais funcional que aquela do tipo “tudo junto”, pois, cada cômodo funciona como um módulo funcional e independente permitindo, entre outras coisas, a privacidade. Por exemplo, se for preciso reparar algum vazamento no Lavabo basta isolá-lo de outros cômodos e fazer o reparo lá mesmo; não haveria necessidade de interditar toda a casa para executar o serviço. Assim, tal como no exemplo da casa em cômodos (figura 8.1b), um programa pode ser “quebrado” em vários módulos funcionais que se comunicam logicamente por via de um “módulo principal”. A figura 8.2 mostra que um “programa de controle comercial” pode ser dividido em vários “programinhas” que executam tarefas específicas para compor o sistema com um TODO. 332 Figura 8.2 - Um programa feito em módulos Fonte: “Curso Básico de Programação-Teoria e Prática”, 2017, Mário Leite Na figura 8.2 “Cadastros”, “Relatórios”, “Controle Bancário”, “Pagamentos”, “Contas a Pagar”, “Contas a Receber”, “Compras”, “Vendas”, “Movimentação” e “Saída” são os módulos que compõem o programa. Cada um deles é executado para executar uma tarefa específica; até o “Saída”, que pode conter apenas uma linha de código. Então, por exemplo, se “Relatórios” estiver com algum problema o programador só terá o trabalho de verificar esse módulo, particularmente, pois o sistema não pode ser interrompido por algum erro em um dos seus módulos. Já pensou se, para se para consertar o módulo “Relatórios” fosse preciso parar o cadastramento de novo clientes!? Seria como abandonar a casa só para o encanador resolver um problema de vazamento no Lavado! Os tais “programinha” (módulos) são, tecnicamente, considerados sub- rotinas (ou, simplesmente rotinas) que são ligadas, logicamente, à uma rotina principal (programa principal) mas, executando tarefas autônomas, bem específicas. Um programa pode ser entendido como um conjunto de linhas de instruções contendo ordens precisas para serem executadas pelo computador. E dependendo do tipo de problema a ser resolvido, 333 da qualidade e da quantidade de informações a ser extraída, o programa pode ter desde dezenas até milhões de linhas de instruções. Mas, como já explicado, um programa não deve ser um bloco único - como uma casa com apenas um grande espaço único -, pelo contrário, para que seja modular e de fácil manutenção ele deve ser composto de vários subprogramas (sub- rotinas) que se “encaixam” logicamente formando o todo. Esta metodologia de modularizar um programa é feita através de técnicas formais: uma delas é a Programação Procedural, que é o caso deste livro. Em qualquer tipo de linguagem, sob qualquer tipo de técnica de programação, um bloco de instruções previamente identificado e que tenha o objetivo de executar uma tarefa específica dentro de um programa é denominado “rotina”. Se o programa é um sistema mais amplo e desenvolvido para executar vários módulos específicos, normalmente ele possui uma “rotina principal” que comanda todas as outras que, então, passam a ser denominadas “sub-rotinas”. Assim, um conjunto de sub-rotinas comandadas por uma rotina principal, se constitui num programa, sob a técnica da Programação Modular. 8.5 - Sub-rotinas Na grande maioria das linguagens de programação - com raras exceções - os módulos dos programas são implementados por dois tipos distintos de sub-rotinas: • Procedimentos • Funções Ambos cumprem o papel de tratar um subconjunto específico (módulo) do programa: executar um bloco de instruções quando solicitado. Entretanto, existe uma diferença entre eles: enquanto a função executa o bloco de instruções e retorna um valor específico para a rotina que a chamou, o procedimento não retorna nada! Portanto,se for invocada uma função e o valor do 334 retorno tiver que ser publicado, isto pode ser feito na rotina que a chamou; mas se for invocado um procedimento, esse valor só será conhecido localmente: no próprio procedimento pois, neste caso, a rotina chamadora não terá acesso a ele. Uma das exceções aludidas acima é o caso da linguagem C que não contempla procedimentos; apenas funções. De qualquer forma, uma sub- rotina sempre é carregada, inicialmente, pelo programa principal, e só DEPOIS disto é que poderá chamar e/ou ser chamada. 8.5.1 - Procedimentos Um procedimento pode ser definido como sendo uma sub-rotina capaz de executar uma tarefa bem determinada, mas sem retornar valor para a rotina que o chamou. O formato geral de um procedimento em Visualg é mostrado na sintaxe a seguir, onde a primeira linha define o nome do procedimento; logo abaixo vem a área de declarações (arquivos, constantes, registros e variáveis - nesta ordem) e, finalmente, entre as palavras-chave Início e FimProcedimento são escritas as linhas de código, contendo as instruções. O esquema a seguir mostra um modelo em Visualg. Procedimento NomeProcedimento[(parâmetros) {Declarações de elementos locais} Declarações de arquivos Declarações de constantes Declarações de registros Declarações de variáveis Inicio Linha1 Linha2 Linha2 ... LinhaN FimProcedimento 335 Como pode ser observado, o formato de um procedimento no Visualg é quase igual ao formato geral de um programa único; a diferença indicada aqui é entre os termos Algoritmo e Procedimento. Outro detalhe a ser notado é a inclusão do termo “parâmetros”; valores recebidos pelo procedimento para serem utilizados no processamento, e que podem ser necessários ou não, dependendo do que o procedimento faz ao ser chamado. ❖ Exemplo 8.1 - Calcular a quantidade de números primos que existe desde 1 até 100. Procedimento ProCalculaQuantPrimos //Calcula a quantidade de primos de 1 a 100. //Autor: Mário Leite //------------------------------------------------------- var j, k, TotDiv, ContPrimos: inteiro Inicio ContPrimos <- 0 Para j De 1 Ate 100 Faca TotDiv <- 0 Para k De 1 Ate j Faca Se(j Mod k = 0) Entao TotDiv <- TotDiv + 1 FimSe FimPara {Verifica se o número j é primo} Se(TotDiv=2) Entao //o número é primo ContPrimos <- ContPrimos + 1 FimSe FimPara Escreval("Número de primos de 1 a 100: ",ContPrimos) FimProcedimento 336 8.5.2 - Funções Uma função executa um módulo de programa tal como faz um procedimento; mas, existe uma diferença bem marcante entre esses dois tipos de sub-rotinas: enquanto o procedimento não retorna nenhum valor para o módulo que o chamou, a função sempre retorna algum valor. Observe abaixo o formato de uma função no Visualg. Funcao Nomefunção [(parâmetros)]: tipo {Declarações de elementos locais} Declarações de arquivos Declarações de constantes Declarações de registros Declarações de variáveis Inicio Linha1 Linha2 Linha3 ... LinhaN Retorne valor //retorno da função FimFuncao Nota: Embora nos dois tipos de sub-rotinas tenha sido colocado como sendo possível a declaração de registros e constantes, tanto nos procedimentos como para as funções, a criação de registros e constantes é normalmente feita no programa principal para que possam ser utilizados em todas as sub-rotinas do programa. Um registro ou uma constante são, normalmente, elementos do programa com visibilidade global, e não apenas local a uma determinada sub-rotina. 337 O esquema de modelo de uma função no Visualg apresenta três novidades em relação ao modelo para procedimento: 1ª) A palavra-chave Funcao em vez de procedimento para informar que se trata de uma sub-rotina (módulo) do tipo função. 2ª) tipo - informa que tipo de dado terá o valor encontrado pela função; isto é, qual será o tipo de dado do seu retorno. O procedimento não tem isto. 3ª) Retorne valor - é uma instrução (com o comando Retorne) que define o retorno da função; o valor que calculado deve ser informado ao módulo que a chamou; e é obrigatório nas funções, embora a instrução possa variar de acordo com a linguagem de programação. A seguir, observe uma segunda situação com o mesmo problema do Exemplo 8.1: calcular a quantidade de números primos em uma faixa”. Neste segundo caso foi empregado uma função em vez de procedimento; e o valor (quantidade de primos na faixa determinada) NÃO FOI EXIBIDO na função, mas retornada para o módulo que chamou a função. E é nesse módulo (chamador) que esse valor poderá ser utilizado (exibido ou usado em algum cálculo...); não interessa o emprego desse valor na própria função chamada: sua tarefa é apenas calculá-lo e retorná-lo! Outro detalhe a ser observado é que no Exemplo 8.1 com procedimento a faixa de pesquisa dos números primos foi previamente estabelecida: de 1 a 100; e o resultado foi, e será SEMPRE 25. Já no segundo caso, com função, essa faixa (início e fim) foi passada como PARÂMETRO para a função pesquisar os números primos. Deste modo, o usuário poderá escolher qualquer faixa de valores para calcular a quantidade de números primos num intervalo qualquer; e essa quantidade vai variar de acordo com o intervalo desejado. Isto torna a sub-rotina mais flexível, mais genérica e bem mais interativa com o usuário. Por exemplo, para os números primos na faixa de 10 a 131 a quantidade encontrada seria 28, já 338 que existem vinte e oito números primos desde 10 até 131. Por outro lado, observe que no caso de uso do procedimento o valor (quantidade de primos na faixa de 1 a 100) teve que ser exibida no próprio procedimento, pois, não retorna valor para o módulo chamador. Funcao FunCalculaQuantPrimos(Ini,Fim:inteiro): inteiro //Função para calcular a quantidade de primos numa faixa. //Autor: Mário Leite //------------------------------------------------------- var j, k, TotDiv, ContPrimos: inteiro Inicio ContPrimos <- 0 Para j De Ini Ate Fim Faca {Loop para fazer as divisões de um número} TotDiv <- 0 Para k De 1 Ate j Faca Se(j Mod k = 0) Entao TotDiv <- TotDiv + 1 FimSe FimPara //fim do loop das divisões Se(TotDiv=2) Entao //o número é primo ContPrimos <- ContPrimos + 1 FimSe FimPara FimPara Retorne ContPrimos //valor obtido: retorno da função FimFuncao ProCalculaQuantPrimos : calcula a quantidade de primos de 1 a 100. FunCalculaQuantPrimos(Ini,Fim): calcula a quantidade de primos em uma faixa definida pelo usuário, começando em Ini e terminando em Fim. 339 Na função “FunCalculaQuantPrimos” apareceram dois parâmetros: Ini e Fim. O primeiro indica o início da faixa numérica desejada, e o segundo o fim dessa faixa. Fazendo uma comparação “física” pode-se considerar uma função como uma “máquina” que executa uma operação bem definida: os parâmetros representam a matéria prima que ela precisa para trabalhar, e o retorno o produto final. Por exemplo, uma garapeira (função) necessita de cana (parâmetro) para produzir o caldo (retorno). A garapeira pode receber uma, duas ou três fieiras de canas (parâmetros), mas produz (retorna) apenas um produto: o caldo; e esse produto (caldo) pode ser colocado num copo (variável) da pessoa (rotina) que a solicitou. É claro que, se a garapeira (função) requer cana (tipo de dado) ela não poderá trabalhar (processar) se nela for introduzido (passado) um tubo de aço (tipo de dado inválido); ela quebraria; falharia! Nota: Embora as duas sub-rotinas mostradas anteriormente (função e procedimento) tenham sido apresentadas fora de um programa, isto foi feito apenas como exemplos de tipos de módulos;entretanto, numa situação real elas SEMPRE terão que estar integrada a um programa, ou “guardadas” como arquivos numa biblioteca. à espera de serem requisitadas. O esquema da figura 8.3 mostra um exemplo de programa com várias sub-rotinas, integradas à rotina (programa) principal. 340 Programa principal Figura 8.3 - Escopos de variáveis num programa Fonte: Leite, (2006, p. 153) 341 Os elementos mais básicos num programa são as variáveis e as constantes; o escopo (visibilidade, abrangência) destes elementos pode ser: Global ou Local. Nas áreas de declarações tem-se o seguinte: ▪ Declarações globais (ente os termos Inicio e FimAlgoritmo): todas as constantes e variáveis declaradas nesta área serão vistas em todas as sub-rotinas, pois terão escopo global; são elementos públicos. ▪ Declarações locais (instruções colocadas entre Procedimento/Funcao e FimProcedimento/FimFuncao): Todas as constantes e variáveis declaradas nessas áreas só podem ser vistas na sub-rotina onde foram declaradas; são elementos com escopo local. Então, por exemplo, se uma variável x for declarada numa sub-rotina1 ela só pode ser vista (manipulada, acessada) nessa sub-rotina, pois nenhuma outra rotina terá acesso a essa variável. O esquema da figura 8.3 mostra como funcionam as visibilidades das variáveis num programa composto de várias sub-rotinas, e informa o seguinte: ✓ Variáveis A, B: Escopo global; são visíveis em todas as rotinas e sub-rotinas do programa; qualquer unidade do programa poderá acessá-las. ✓ Variáveis C, D: Escopo local à rotina 1; são visíveis nas sub- rotinas 1.1 e 1.2. ✓ Variável E: Escopo local à sub-rotina 1.1 (visível apenas nesta sub-rotina). ✓ Variáveis F, G: Escopo local à sub-rotina 1.2 (visíveis só nesta sub-rotina). ✓ Variáveis H, I: Escopo local à rotina 2, e são visíveis nas suas três sub-rotinas 2.1, 2.2 e 2.3. ✓ Variáveis J, K, L: Visíveis apenas na sub-rotina 2.1; 342 ✓ Variáveis L, M, N: Escopo local à sub-rotina 2.2 (só serão visíveis nesta sub-rotina); mas, a variável L desta sub-rotina não tem nada a ver com a variável L da sub-rotina 2.1, pois ambas são locais a sub-rotinas diferentes. ✓ Variáveis M, N, O, P, Q: Escopo local à sub-rotina 2.3; mas, as variáveis M e N desta sub-rotina não têm nada a ver com suas homônimas da sub-rotina 2.2. Nota: Se por acaso, uma variável local for declarada com o mesmo identificador de outra variável global a preferência é sempre da variável local. Isto quer dizer que, se por exemplo, alguma sub-rotina do programa do esquema da figura 8.3 tivesse uma variável A o valor considerado desta variável dentro desta sub-rotina seria o local e não o global. A preferência de uso de variáveis deve ser sempre pelas locais e não globais, pois as globais tornam o programa mais lento, além de sofrer interferências de todas as sub-rotinas do programa; só as use em casos de registros e constantes. 8.6 - Parâmetros A sub-rotina “FunCalculaQuantPrimos”, trabalhou com parâmetros que indicavam o início e o fim, respectivamente, da faixa numérica, De um modo bem geral, pode-se definir parâmetros como sendo “valores passados a uma rotina para que ela possa executar sua tarefa”. No caso da função “FunCalculaQtePrimos” a linha de código de definição dessa sub-rotina é explicada no esquema a seguir... 343 Nome da função tipo de dado dos dois parâmetros Funcao FunCalculaQtePrimos(Ini,Fim:inteiro): inteiro Primeiro parâmetro (recebe início da faixa) tipo de retorno da função Segundo parâmetro (recebe fim da faixa) De um modo geral, qualquer sub-rotina pode receber parâmetros de acordo com o esquema da figura 8.4 que define procedimento e função, respectivamente, no Visualg. Figura 8.4 - Esquema de um Procedimento e de uma Função 344 Nota1: Analisando o esquema da figura 8.4, pode ser notado que além da diferença entre as palavras-chave que definem o tipo de sub-rotina (procedimento e função), existe uma outra diferença FUNDAMENTAL entre elas: o termo “Tipo” que aparece logo depois dos parênteses, imediatamente após dois pontos (:). Os procedimentos não os possuem, mas as funções têm, por obrigação de sempre indicar o tipo de dado do retorno. Nota2: Nos casos em que dois ou mais parâmetros possuem um mesmo tipo de dados, então eles devem ser separados por vírgulas e no final da lista colocar : e o tipo. Por exemplo, se os parâmetros P1 e P2 fossem do tipo inteiro e o T3 do tipo caractere, ficaria assim: (p1, p2:inteiro; p3:caractere) A vírgula (,) separa os parâmetros de um mesmo tipo e o ponto-e- vírgula (;) separa os tipos. 8.6.1 - Passagem de Parâmetros Passagem de parâmetros pode ser definida como sendo “o mecanismo pelo qual valores externos são entregues a uma sub- rotina, com os quais ela deve operar para executar a tarefa que lhe foi atribuída”. No esquema da figura 8.5a, o programa principal chama a função FunCalculaRaiz() para calcular a raiz k-ésima de N. Depois de calculada essa raiz a função retorna (devolve) ao programa principal o valor calculado. 345 Figura 8.5a - Exemplo de passagem de parâmetros para uma função A seta sólida, indicada esquematicamente na figura 8.5a, mostra como é feita a passagem de parâmetros; no caso estão sendo passados os parâmetros N e k (parâmetros reais, ou argumentos; nesta ordem) que representam o número do qual se deseja extrair a raiz e o índice dessa raiz, respectivamente. O programa “Principal” chama a função FunCalculaRaiz() passando-lhe esses dois parâmetros reais (ou argumentos) que são recebidos como parâmetros formais em num e pot, respectivamente. A função calcula a raiz, armazena-a na variável local raiz e retorna esse valor para o programa que a chamou (indicado pela seta tracejada). Esse retorno (valor da raiz k-ésima de N) é armazenado na variável global R do programa “Principal” e posteriormente exibido. Por exemplo, se o número para calcular a raiz cúbica fosse 64, então os valores seriam: 346 N = 64 k = 3 Esses dois valores seriam passados para a função FunCalculaRaiz() que os receberia formalmente assim: 64 em num e 3 em pot. Em seguida, essa função executaria a linha de código raiz <- (num^(1/pot)) cujo resultado seria 4 (raiz cúbica de 64); e finalmente, esse valor calculado pela função (o seu retorno) seria devolvido ao programa principal que o colocaria na variável R, para depois exibi-lo. No esquema da figura 8.5b o programa principal chama o procedimento ProCalculaRaiz() para calcular a raiz k-ésima do de N. Depois de calculada a raiz esse valor é exibido lá mesmo (no procedimento), já que esse tipo de sub-rotina não tem retorno; não pode retornar o valor da raiz para o programa “Principal” que que o chamou. 347 Figura 8.5b -Exemplo passagem de parâmetros para um procedimento 348 Notas: 1) N, k e R são variáveis globais (declaradas no programa principal) e normais, entretanto N e k ganham status de parâmetros reais quando são envolvidas na interação com a sub-rotina. 2) Os parâmetros formais num e pot poderiam ter os mesmos identificadores dos parâmetros reais (N e k, respetivamente), sem qualquer problema, mas nesta ordem! Os parâmetros passados (reais) não precisam ter, necessariamente, os mesmos identificadores que os dos parâmetros recebidos (formais), ou vice-versa. 3) Os parâmetros formais num e pot (da função) não podem ser declarados, pois já são considerados variáveis locais à função; ao contrário dos parâmetros reais N e k (do programa principal) que têm que ser declarados, pois não são parâmetros formais. 4) As variáveis R (do programaprincipal) e raiz (da função) não são parâmetros; são variáveis normais, pois não estão envolvidos na passagem de parâmetros. 5) O retorno de uma função não é, normalmente, exibido na própria função, e sim na rotina que a chamou. Já no caso de procedimento, como não existe retorno, o resultado de seu processamento deve ser exibido lá mesmo! 6) Quando se utiliza procedimento a rotina chamadora (seja o programa principal ou outra sub-rotina qualquer) não pode acessar o valor calculado pelo procedimento porque ele não retorna nada. Então, na figura 8.5b ficou bem claro que após calculada a raiz k- ésima do número N esse valor teve que ser exibido no próprio procedimento, já que o programa “Principal” não pode “ver” esse valor que é encapsulado (protegido) na sub-rotina chamada. É importante observar, também, as duas formas bem distintas de chamar (invocar) uma função e um procedimento. Para chamar uma função a rotina chamadora (no caso o programa “Principal”) pode “pegar” o retorno e atribui-lo a uma variável; como aconteceu no caso do esquema da figura 8.5a: 349 R ← FunCalculaRaiz(N,k) Já no caso de procedimentos a linha de código se resume à apenas uma instrução: a chamada; e pronto! Não se pode pegar o retorno, já que procedimentos não retornam nada. Assim, no caso do esquema da figura 8.5b, ficou simplesmente assim: ProCalculaRaiz(N,k). Deste modo, as chamadas de funções e procedimentos são bem diferentes. 1) Para chamar uma função é assim: R ← NomeFuncao([parâmetros]) //R é variável local da rotina Para chamar um procedimento é assim: NomeProcedimento([parâmetros]) Nota: Formalmente, os valores passados a sub-rotina são chamados de “argumentos” (ou parâmetros reais), e esses valores quando recebidos pela sub-rotina é que são os “parâmetros” (ou parâmetros formais). Embora esta formalidade não altere a essência da passagem de parâmetros, é bom que fique registrada esta diferença, muito considerada, academicamente. 8.6.1.1 - Passagem Por Valor Quando é feita a passagem de um parâmetro Por Valor, o que é passado, na verdade, é uma cópia do valor dessa variável; e a ligação estabelecida entre elas pode ser considerada fraca. Isto quer dizer que a rotina chamada (a que recebe o parâmetro) pode alterar esse parâmetro, mas, o seu valor na rotina chamadora não é alterado. Este modo de passar parâmetros é o padrão na maioria dos processamentos. Nos esquemas das figuras 8.5a e 8.5b para calcular a raiz de índice k de um número N, a passagem de parâmetros para as sub-rotinas foi feita “Por Valor”. Observe o esquema da figura 8.6a, explicando esse tipo de passagem, quando N é passado como 64 e k como 3 para a função. 350 Figura 8.6a - Exemplo de passagem de parâmetros “Por Valor” A figura 8.6a mostra que mesmo que a função chamada FunCalculaRaiz() altere o valor recebido: de 64 para 999, o parâmetro N continuará valendo 64 na rotina “Principal”. 8.6.1.2 - Passagem Por Referência Neste caso o que é recebido pela rotina chamada não é apenas o valor da variável, mas também o endereço de memória dessa variável. Deste modo, a ligação que se estabelece entre elas é forte. Por isto, se a rotina chamada fizer alguma alteração nesse parâmetro isto será refletido na rotina chamadora. Considerando, ainda, o exemplo para calcular a raiz de índice k de um número N, observe o esquema da figura 8.6b, sendo a passagem do parâmetro N sendo feita “Por Referência”. 351 Figura 8.6b - Exemplo de passagem de parâmetros “Por Referência” O esquema da figura 8.6b mostra que o valor da variável N do programa “Principal “ se alterou: de 64 (valor passado para a função) para 999, devido à alteração promovida no parâmetro formal num na função FunCalculaRaiz(). Observe que a indicação de que o parâmetro N foi passado (ou recebido) “Por Referência” é a presença da palavra-chave var (de variável) na frente do parâmetro formal num. Por sua vez, o parâmetro k continua sendo passado “Por Valor”. E embora os exemplos de passagem de parâmetros (“Por Valor” e “Por Referência”) mostrados nas figuras 8.6a e 8.6b tenham sido feitos com função, 352 as passagens de parâmetros também podem ser feitas com procedimento, mesmo estes não tendo retorno; entretanto, na maioria das vezes a passagem é sempre feita “Por Valor”. Por isto, quando se cria uma sub-rotina esta deve receber parâmetros “Por Valor”, sempre que possível, por ser o modo seguro. De qualquer forma, em qualquer situação, quando o processamento de uma sub-rotina gerar algum valor mensurável como resultado, deve-se optar por função; pois se optar por procedimento a variável que armazena o resultado dos cálculos terá que ter abrangência global para que o programa principal a “enxergue”; mas neste caso, TODAS as outras sub-rotinas também poderão acessar essa variável, o que é extremamente perigoso, ferindo a segurança de dados. Nota: Seguindo o padrão do Pascal, a indicação de que uma sub-rotina recebe um parâmetro “Por Referência” é o termo var antes desse parâmetros; mas isto pode variar de linguagem para linguagem; como no Clipper/xHarbour que @. Em alguns casos, esse tipo de indicação pode nem existir, explicitamente, como no caso do Python. ❖ Exemplo 8.2 - Criar uma sub-rotina que calcula o MMC (Mínimo Múltiplo Comum) de dois números. Neste caso, como o objetivo é obter um valor bem determinado, a solução mais indicada é uma função. A função “FunMMC1( )” é uma solução. 353 Funcao FunMMC1(Num1,Num2:inteiro): inteiro //Função que retorna o MMC de dois números. //Autor: Mário Leite //------------------------------------------------------- var i, j, k, m, M1, M2, MMC: inteiro VetMult1,VetMult2: vetor[1..MAX] de inteiro Verdade: logico //MAX deve ser maior número dos recebidos como parâmetros Inicio Para j De 1 Ate MAX Faca VetMult1[j] <- Num1*j VetMult2[j] <- Num2*j FimPara Verdade <- Falso Para i De 1 Ate MAX Faca Para j De 1 Ate MAX Faca Se(VetMult1[i]=VetMult2[j])Entao //achou MMC <- VetMult1[i] Verdade <- Verdadeiro //encontrou o MMC Interrompa //sai do loop mais interno FimSe FimPara Se(Verdade) Entao Interrompa //sai do loop mais externo FimSe FimPara Retorne MMC //retorno da função FimFuncao A função “FunMMC2( )” a seguir, é uma outra solução mais refinada e mais enxuta do problema do Exemplo 8.2 em que não há necessidade de se ter um valor MAX e nem vetores para calcular o MMC. 354 Funcao FunMMC2(Num1,Num2: inteiro): real //Função que retorna o MMC de dois números. //Autor: Mário Leite //------------------------------------------- var R, N1, N2: inteiro Inicio N1 <- Num1 N2 <- Num2 Repita R <- (N1 Mod N2) N1 <- N2 N2 <- R Ate(R=0) Retorne Int(Num1*Num2)/N1) FimFuncao 8.7 - Programas com Sub-rotinas As figuras 8.7a, 8.7b, 8.8a e 8.8b mostraram, esquematicamente, um programa modular contendo exemplos de processamento para ilustrar passagens de parâmetros. Na prática, entretanto, é um pouco diferente: no Visualg as sub-rotinas podem ser “encaixadas” no programa de duas formas: 1) “dentro” do programa principal 2) antes do programa principal A primeira forma é a mais tradicional, mostrada no programa “Principal1”: entre as instruções Algoritmo "Principal1" e “FimAlgoritmo”, como mostra a figura 8.7a, com as variáveis globais do programa definidas ANTES das sub-rotinas. 355 Figura 8.7a - Código-fonte do programa “Prinipal1” no editor A figura 8.7b mostra a saída do programa “Principal1”, quando se deseja calcular a raiz cúbica de 64. 356 Figura 8.7b- Exemplo de saída do programa “Principal1” A segunda forma de “encaixar” sub-rotinas num programa em Visual é mostrada no programa “Principal2”. Neste caso, as sub- rotina permanecem ANTES das instruções Algoritmo "Principal2" e “FimAlgoritmo, porém as variáveis globais, também são definidas dentro dessa área, e não antes das funções. 357 Figura 8.8a - Código-fonte do programa “Prinipal2” no editor A figura 8.8b mostra a saída do programa “Principal2”, com o mesmo propósito: calcular e exibir raiz cúbica de 64. 358 Figura 8.8b- Exemplo de saída do programa “Principal2” Nota: Observe que tanto no layout do programa “Principal1” quanto no “Principal2”, a ÚLTIMA linha de código é FimAlgoritmo, pois, é esta instrução que determina o FIM DO PROGRAMA. Não pode existir NADA depois desta instrução; é como o comando End. em programas codificados em Pascal. As linhas tracejadas são apenas para mostrar os limites das rotinas, nada mais que isto; apenas um estilo de programação, e não é obrigatório; mas com elas o programa fica mais legível Outra informação importante a respeito de programas em Visualg (seja modular ou não) é que o nome do programa NÃO TEM NADA A VER com o nome do arquivo no qual ele será gravado. 359 Deste modo, o nome do arquivo poderá ser qualquer um, desde que respeite as regras de identificação de arquivos exigidas pelo Sistema Operacional que o carregará para a memória; e deverá ter a extensão .alg (de algoritmo). Por outro lado, mesmo podendo ter qualquer nome válido, é uma boa atitude profissional gravar o arquivo com o MESMO NOME do programa. Então, neste caso, o arquivo que contém o programa “Principal1” poderia ser Pringipal1.alg. É assim que será feito neste livro: os arquivos que contém programas em Visualg terão o mesmo nome do programa contido nele. A figura 8.9 mostra alguns arquivos de uma pasta com programas deste livro, em Visualg. Figura 8.9 - Exemplo de arquivos de programas em Visualg 360 Nota: Embora o arquivo-fonte de um programa feito em Visualg possa ser editado em qualquer editor de texto (sem formatações), é fortemente aconselhável utilizar SEMPRE o seu próprio editor. Isto dá mais segurança e maior produtividade ao programador, uma vez que o editor do Visualg mostra possíveis erros de sintaxe com a indicação de cores no código à media que o programa vai sendo digitado. Além disto, o editor próprio da ferramenta é um IDE (Integrated Development Environment - Ambiente de Desenvolvimento Integrado) que oferece várias opções para a criação/teste/depuração/gravação do programa editado, de maneira bem interativa e customizável. Por exemplo, se ao tentar digitar a palavra-chave RaizQ para calcular a raiz quadrada de um número e digitar apenas Raiz, vai notar que essa palavra vai continuar com a cor preta em vez de azul, como o Editor do Visualg mostraria para indicar que se trata de uma função interna da ferramenta. Assim, o programador poderá, já nesse exato momento, corrigir o seu erro; mas, se utilizar um outro editor de texto como, por exemplo, o Bloco de Notas do Windows®, esse erro vai passar despercebido e a produtividade do programador cai. ❖ Exemplo 8.3 - Criar um programa modular que gera e exibe os n primeiros números pares ou ímpares para um vetor, exibindo-os na forma de tabela, e os números formatados com cinco dígitos. O programa "ProgGeraParesOuImpares", mostrado a seguir, em texto livre do editor, é uma boa solução para o problema do Exemplo 8.3. 361 Algoritmo "ProgGeraParesOuImpares" //Gera os primeiros n números pares ou ímpares para um //vetor, mostrando-os na forma de tabela de números //formatados com cinco dígitos. //Autor: Mário Leite //------------------------------------------------------- //Elementos globais Const MAXELE=1000 //limita a quantidade de números Var VetNum: vetor[1..MAXELE] de inteiro VetNumS: vetor[1..MAXELE] de caractere NOp, TamVet: inteiro Op: caractere //------------------------------------------------------- Funcao FunVerifOpcao(xp:caractere): inteiro //Retorna o tipo de número: 0=Par, -1=Ímpar var Ret: inteiro Inicio Se(xp="P") Entao Ret <- 0 Senao Ret <- -1 FimSe Retorne Ret FimFuncao //fim da função "FunVerifOpcao" //---------------------------------------------------- Procedimento ProCriaVetor(Num:inteiro) //Cria o vetor de números a serem exibidos var n: inteiro Inicio n <- 0 Enquanto (n<TamVet) Faca Num <- Num + 2 n <- n + 1 //incrementa o índice do vetor para VetNum[n] <- Num {Seleciona a formatação adequada do número} Escolha VetNum[n] Caso 1 Ate 9 VetNumS[n] <- "0000" + NumpCarac(VetNum[n]) Caso 10 Ate 99 VetNumS[n] <- "000" + NumpCarac(VetNum[n]) Caso 100 Ate 999 362 VetNumS[n] <- "00" + NumpCarac(VetNum[n]) Caso 1000 Ate 9999 VetNumS[n] <- "0" + NumpCarac(VetNum[n]) OutroCaso VetNumS[n] <- NumpCarac(VetNum[n]) FimEscolha FimEnquanto FimProcedimento //fim do procedimento "ProCriaVetor" //---------------------------------------------------- Procedimento ProExibeVetor //Exibe o vetor Var j, Col: inteiro Inicio Col <- 0 Para j De 1 Ate TamVet Faca Col <- Col + 1 Se(Col>9) Entao //máximo de nove blocos de elementos por linha Escreval("") //salta para uma nova linha Col <- 1 //recomeça na coluna 1 da nova linha FimSe Escreva(VetNumS[j], " ") FimPara FimProcedimento //fim do procedimento //======================================================= //Programa principal Inicio {Validação das dimensões da matriz} Repita Escreva("Digite o número de elementos [min 2"," – max",MAXELE,"]: ") Leia(TamVet) TamVet <- Int(TamVet) Ate((TamVet>=2) e (TamVet<=MAXELE)) Escreval("") Repita Escreva("Deseja elementos pares ou elementos ímpares?[P/I]: ") Leia(Op) Op <- Maiusc(Op) Ate((Op="P") ou (Op="I")) NOp <- FunVerifOpcao(Op) //verifica opção desejada 363 ProCriaVetor(NOp) //chama rotina: cria vetor LimpaTela ProExibeVetor //chama rotina: exibir números criados Escreval("") FimAlgoritmo //fim do programa "ProgGeraParesOuImpares" Observe que o programa "ProgGeraParesOuImpares" empregou três sub-rotinas: uma função e dois procedimentos; assim ele ficou bem mais explicativo. As figuras 8.10a e 8.10b mostram, respectivamente, os cento e vinte primeiros pares e ímpares formatados com cinco dígitos. Figura 8.10a - Cem primeiros números pares formatados 5 dígitos 364 Figura 8.10b-Cem primeiros números ímpares formatados com 5 dígitos Exemplo 8.4 - Tornar modular o programa para calcular o determinante de matrizes de ordem superior a 3, mostrado no item 6.6.3 do Capítulo 6. Naquela ocasião o problema de calcular o determinante de matrizes de ordem superior a 3 foi resolvido com um programa único (sem sub-rotinas). Entretanto, como pode ser notado, caso ocorra algum erro no programa, o programador terá que vascular todas as linhas de código, até encontrar o erro. Por isto, é importante separar o programa em módulos, e neste caso apresentamos soluções em três situações, e mais manutenível. 365 • Para determinantes de matrizes de ordem 2 • Para determinantes de matrizes de ordem3 • Para determinantes de matrizes de ordem qualquer “ProgCalculaDeterminante” é uma solução modular de programa em Visualg, com sub-rotinas que implementam a solução de forma mais profissional e elegante. Algoritmo "ProgCalculaDeterminante" //Calcula o determinante de uma matriz mxm de inteiros. //Autor: Mário Leite //------------------------------------------------------- //Elementos globais Const MAXLIN=10 //limita as dimensões da matriz Var MatOrig vetor[1..MaXLIN,1..MAXLIN] de real MatA: vetor[1..MaXLIN,1..MAXLIN] de real MatX: vetor[1..MaXLIN,1..MAXLIN] de real Mat3x3: vetor[1..MaXLIN,1..MAXLIN] de real p, q, mLin, LinMat: inteiro SomaPos, SomaNeg, DetA: real //---------------------------------------------------- Funcao FunCalculaDet2x2: real //Calcula determinante de ordem 2 na forma mais simples var Det2: real Inicio SomaPos <- MatA[1,1]*MatA[2,2] SomaNeg <- MatA[2,1]*MatA[1,2] Det2 <- SomaPos - SomaNeg Retorne Det2 FimFuncao //fim da função "FunCalculaDet2x2" //---------------------------------------------------- Funcao FunCalculaDet3x3: real //Calcula determinante de ordem 3 pela "Regra de Sarrus" var Det3: real Inicio SomaPos <- MatA[1,1]*MatA[2,2]*MatA[3,3] + MatA[1,2]*MatA[2,3]*MatA[3,1] 366 SomaPos <- SomaPos + MatA[1,3]*MatA[2,1]*MatA[3,2] SomaNeg <- MatA[1,3]*MatA[2,2]*MatA[3,1] + MatA[1,1]*MatA[2,3]*MatA[3,2] SomaNeg <- SomaNeg + MatA[1,2]*MatA[2,1]*MatA[3,3] Det3 <- SomaPos - SomaNeg Retorne Det3 FimFuncao //fim da função "FunCalculaDet3x3" //---------------------------------------------------- Funcao FunCalculaDetmxm: real //Calcula o determinante de ordem superior a 3 var MatAx: vetor[0..MAXLIN, 0..MAXLIN] de real i, j, k, m, Trocas: inteiro Detmxm, Aux, Fator: real Inicio {Faz uma cópia da matriz lida para o processamento} Para i De 0 Ate (LinMat-1) Faca Para j De 0 Ate (LinMat-1) Faca MatAx[i,j] <- MatA[i+1,j+1] FimPara FimPara Trocas <- 0 //número de permutas de linhas da {Transforma a matriz num triângulo para Regra Chió m <- LinMat Para i De 0 Ate (m-2) Faca Se(MatAx[i,i]=0) Entao //detectou o elemento [1,1] = 0 Para k De i Ate (m-1) Faca //procura um elemento [1,1] <> 0 Se(MatAx[k,i]<>0) Entao Para j De 0 Ate(m-1) Faca //permuta Aux <- MatAx[i,j] MatAx[i,j] <- MatAx[k,j] MatAx[k,j] <- Aux FimPara k <- m FimSe FimPara Trocas <- Trocas + 1 //acumula o número de permutas de linhas FimSe 367 Se(MatAx[i,i]<>0) Entao {Converte o elemento [1,1] para 1} Para k De (i+1) Ate (m-1) Faca Fator <- -1*MatAx[k,i]/MatAx[i,i] Para j De i Ate (m-1) Faca MatAx[k,j] <- MatAx[k,j] + (Fator*MatAx[i,j]) FimPara FimPara FimSe FimPara Detmxm <- 1.0 {Calcula o determinante} Para i De 0 Ate (m-1) Faca Detmxm <- Detmxm*MatAx[i,i] FimPara Escreval("") Escreval("") Se(Trocas Mod 2 <> 0) Entao //houve permuta ímpar Detmxm <- -Detmxm FimSe Retorne Detmxm FimFuncao //fim da função "FunCalculaDetmxm" //======================================================= //Programa principal Inicio {Validação e leitura da matriz} Repita Escreva("Digite o número de linhas da matriz: ") Leia(LinMat) LinMat <- Int(LinMat) Ate((LinMat>=2) e (LinMat<=MAXLIN)) Escreval("") Escreval("") Para p De 1 Ate LinMat Faca Para q De 1 Ate LinMat Faca Escreva("Entre com o elemento [",p,q,"]: ") Leia(MatOrig[p,q]) //matriz original lida mLin <- LinMat //preserva o número de linhas da matriz original MatA[p,q] <- MatOrig[p,q] //faz cópia da matriz para usar nos cálculos 368 FimPara Escreval("") FimPara {Seleciona o tipo de função a ser chamada para calcular o determinante} Escolha LinMat Caso 2 DetA <- FunCalculaDet2x2 //para matrizes de ordem 2x2 Caso 3 DetA <- FunCalculaDet3x3 //para matrizes de ordem 3x3 OutroCaso DetA <- FunCalculaDetmxm //para matrizes de ordem superior a 3 FimEscolha LimpaTela {Mostra a matriz na forma tabelar} Escreval(" Matriz orinal lida:") Para p De 1 Ate mLin Faca Para q De 1 Ate mLin Faca Escreva(MatOrig[p,q], " ") FimPara Escreval("") FimPara Escreval("") Escreval("") Escreval("Determinante da matriz:", DetA) Escreval("") FimAlgoritmo //fim do programa "ProgCalculaDeterminante" A figura 8.11 mostra uma saída do programa “ProgCalculadeterminante”,para uma matriz 5x5. 369 Figura 8.11 - Calculando o determinante de uma matriz 5x5 8.8 - Acesso a Arquivos Como já foi explicado no início deste livro, o Visualg NÃO É uma linguagem de programação, formalmente considerada; é uma pseudolinguagem para testar os algoritmos (em forma de pseudocódigos) que o programador cria para solucionar um problema. O Visualg é uma ferramenta baseada na escrita em portugol, criada para substituir os antigos “Testes de Mesa” que estavam os fluxogramas da solução do problema. Deste modo, embora consiga processar programas até bem complexos, esta ferramenta não tem muita flexibilidade na manipulação (leitura/escrita) de arquivos tal como as linguagens reais. Mas, mesmo com bastante limitações, o Visualg consegue ler/gravar em arquivos textos; mesmo que primitivamente. A instrução para criar um arquivo-texto identificado como “Arq1.txt” é a seguinte Arquivo "Arq1.txt" 370 Esta instrução, quando existir num programa, deverá ser a primeira na “Seção de Declarações” de uma rotina. A extensão do arquivo pode ser qualquer uma (txt, dat, arq, etc), mas deve estar presente para completar a identificação do arquivo, mas é aconselhável não usar a extensão alg para não confundir com algum programa-fonte do Visualg. O comando que acessa os caracteres do arquivo é Leia(x), onde x é um caractere do arquivo. Se o arquivo ainda não existir será criado; e cada valor de x deverá ser digitado para ser gravado no arquivo; se já existe, então Leia(x) lerá o valor contido nessa variável, um por um, sequencialmente, dentro de um loop. O programa “ProgAcessandoArquivo” cria/acessa um arquivo com n valores inteiros, e depois usa esses valores para criar um vetor. //----------------------------------------------------- Procedimento ProAcessaArquivo(n:inteiro) //Procedimento que acessa o arquivo com n caracteres Arquivo "Arq1.txt" //abre o arquivo var j, x: inteiro Inicio Escreval("Elementos gravados no arquivo: ") Para j De 1 Ate n Faca //loop para criar/ler valores do arquivo Escreva("Digite o elemento",j,": ") Leia(x) VetX[j] <- x*2 //cria cada elemento do vetor FimPara Escreval("") Escreval("Elementos do vetor:") Para j De 1 Ate n Faca Escreva(VetX[j]," ") //exibe elemento FimPara FimProcedimento //fim do procedimento 371 //===================================================== //Programa principal Algoritmo "ProgAcessandoArquivo" //Acessa um arquivo com cinco valores e cria um vetor //onde cada elemento é o dobro de cada valor gravado //nesse arquivo. Exibe os valores gravados no //arquivo //e os elementos do vetor criado. //Autor: Mário Leite //----------------------------------------------------- //Elementos globais Const MAXELE=50 //limita o número de caracteres no Var Vetx: vetor[1..MAXELE] de inteiro n: inteiro Inicio n <- 0 Repita Escreva("Digite o número de caracteres contidos no arquivo: ") Leia(n) Ate((n>=1) e (n<=MAXELE)) Escreval("") ProAcessaArquivo(n) //chama rotina/acessa o arquivo Escreval("") FimAlgoritmo //fim do programa "ProgAcessandoArquivo" ATENÇÃO: O programa “ProgAcessandoArquivo” CRIA/LÊ um novo arquivo chamado “Arq1.txt” e em seguida cria um vetor cujos elementos são o dobro de cada valor do arquivo. E uma vez criado, esse arquivo passa a conter, definitivamente, os elementos que foram digitados no procedimento “ProAcessaArquivo”. Se for necessário valores diferentes deve-se criar um novo arquivo, pois esses elementos gravados não poderão ser editados. Assim, só utilize valores gravados em arquivos com o Visualg se REALMENTE for muito necessário. Esta é uma limitação séria do Visualg, que poderá ser corrigida nas próxima versões. 372 A figura 8.12 mostra uma saída do programa “ProgAcessandoArquivo”. Figura 8.12 - Criação de arquivo: programa “ProgAcessandoArquivo” A figura 8.13 mostra o arquivo Arq1.txt gravado com o “Bloco de Notas”. Figura 8.13 - O arquivo “Arq1.txt “ 373 8.9 - Exercícios Propostos 1 - Observe o programa abaixo. O que está errado nele? Procedimento VerificaPrimo(num:inteiro): logico var Resp: logico j: inteiro Inicio j <- 1 Resp <- Verdadeiro Enquanto (j<=num) Faca Se(j<>1) e (j<>num) Entao Se(num Mod j = 0) Entao Resp <- Falso j <- num + 1 FimSe FimSe j <- j + 1 FimEnquanto Retorne Resp FimProcedimento //--------------------------------------------------- Funcao VerificaQuadrado(num:inteiro): logico var Resp: logico Raiz: real Inicio Raiz <- RaizQ(num) Se(Int(Raiz) = Raiz) Entao Resp <- Verdadeiro Senao Resp <- Falso FimSe Retorne Resp FimFuncao 374 //--------------------------------------------------- Funcao CalculaRaiz(num:real; k:inteiro): real Inicio Retorne <- num^(1/k) FimFuncao //==================================================== Var x,y: inteiro Algoritmo "ProgCalculos" Inicio Escreva("Digite um número: ") Leia(x) y <- VerificaPrimo(x) Se(y) Entao Escreval("O número",x,"é primo. ") Senao Escreval("O número",x,"não é primo.") FimSe FimAlgoritmo //fim do programa "ProgCalculos" 2 - Explique por que um programa com mil linhas de códigos deve ser “partido” em sub-rotinas. Qual seria a vantagem disso? 3 - Explique por que uma constante, tal como a aceleração da gravidade, deve ser declarada no programa principal e não nas sub-rotinas? 4 - Qual a diferença entre uma variável global e uma local? 5 - Para que servem os parâmetros? Qual é a vantagem de utilizá- los em uma sub-rotina? 6 - Explique o porquê das variáveis locais serem preferenciais, em vez das globais? 7 - Suponha que você tenha que criar uma sub-rotina que mostre todos os divisores de um número muto grande (acima de um milhão); por qual você optaria: função ou procedimento? Explique sua preferência. 375 8 - Suponha um programa em Visualg que possua quatro sub- rotinas: duas do tipo função e duas do tipo procedimento. Ao rodar (carregar) o programa, qual delas, CERTAMENTE, será chamada primeiro? A ( ) A primeira rotina dentro do programa. B ( ) A segunda rotina dentro do programa. C ( ) A terceira rotina dentro do programa. D ( ) A quarta rotina dentro do programa. E ( ) Nada pode ser afirmado. 9 - Observe as declarações abaixo, em Visualg. Explique por que vai dar erro ao tentar rodar o programa. Var Lado1, Lado2: inteiro Const G=9.80665 Arquivo "Candidatos.txt" Tipo TPolitico = registro nome: caractere sexo: inteiro idade: real partido: caractere reeleição: logico FimRegistro 10 - Por que quando ocorre uma passagem de parâmetros “Por Referência”, se a rotina chamada alterar um dos parâmetros essa alteração será sentida na rotina chamadora? 11 - O procedimento “ProListaBissextos” mostra todos os anos bissextos deste o ano 1583 até o ano 2099. Esse procedimento poderia ser substituído por uma função para fazer a mesma coisa? Explique a sua resposta. 376 Procedimento ProListaBissextos //Procedimento para listar os anos bissextos desde o ano //1583 até o ano 2099. //----------------------------------------------------- var Resp, Cond1, Cond2: logico Ano, Cont: inteiro Inicio Cont <- 0 Ano <- 1583 Escreval("Anos bissextos desde o ano 1583 até o ano 2099") Enquanto (Ano<=2099) Faca Cond1 <-((ano Mod 4=0) e (ano Mod 100 <>0)) Cond2 <-(ano Mod 400 = 0) Se(Cond1 ou Cond2) Entao EscrevaLn(Ano) //ano bissexto Cont <-Cont + 1 FimSe Ano <-Ano + 1 FimEnquanto Escreval("") Escreval("Existem",Cont," anos bissextos desde 1583 até 2099") FimProcedimento 12 - Observe o programa “MostraFatotrial”, abaixo. Esse código em Visualg é clássico para resolver um problema assim; e neste caso, o número tem que ser primo. Entretanto, ele pode ser melhorado; e como isto pode ser feita essa melhoria? Quais as melhorias poderiam ser introduzidas nele? 377 Algoritmo "MostraFatorial" //Calcula o fatorial de um número primo digitado. ------------------------------------------------------- Var VetNumS: vetor[1..2] de caractere //limita tamanho do número NumS: caractere j, TotDiv, NumN: inteiro Fat: real EhNumero, EhPrimo, Primo: logico Inicio Repita EhNumero <- Verdadeiro Escreva("Digite o número: ") Leia(NumS) Para j De 1 Ate Compr(NumS) Faca VetNumS[j] <- Copia(NumS,j,1) //Verifica se o caracter digitado é um dígito [0 a 9] Se((Asc(VetNumS[j]) < 48) ou (Asc(VetNumS[j])> 57)) Entao EhNumero <- Falso //não é digito Interrompa FimSe FimPara //Verifica se o número digitado é primo Se(EhNumero) Entao NumN <- CaracpNum(NumS) //Calcula o fatorial do núemro digitado TotDiv <- 0 Para j De 1 Ate NumN Faca Se(NumN Mod j = 0) Entao TotDiv <- TotDiv + 1 FimSe FimPara Se(TotDiv=2) Entao EhPrimo <- Verdadeiro Senao EhPrimo <- Falso 378 FimSe FimSe Ate((EhNumero) e (EhPrimo) e (NumN<=23 //Calcula fatorial do número primo digitado e o exibe Fat <- 1 Se(NumN<>0) Entao Para j De 1 Ate NumN Faca Fat <- Fat*j FimPara FimSe Escreval("") Escreva("Fatorial de", NumN, ":", Fat) FimAlgoritmo 379 Anexo - Solução dos Exercícios Propostos Capítulo 1 1 - Explique, com suas próprias palavras, o que é “Lógica de Programação”. Resposta: Lógica é a forma ordenada do pensamento. Então, para a lógica de programação, é aforma ordenada de colocar as ordens (instruções) nos programas para resolver um problema através da computação. 2 - Por que não se deve partir direto para a codificação de um programa sem, antes, criar o algoritmo/pseudocódigo. Resposta: Por que a solução de um problema é dada pelo algoritmo/pseudocódigo, e não pela linguagem de programação. A codificação apenas traduz a solução do problema para a sintaxe da linguagem. Codificar não é programar! 3 - Qual é a vantagem de se declarar um endereço de memória RAM como constante, em vez de variável? Dê um exemplo. Resposta: O conteúdo de uma variável pode ser alterado em qualquer momento do programa; mas, na constante o conteúdo não poderá ser alterado por atribuição e/ou leitura. Por exemplo: o número PI, que é sempre um valor usado em cálculos que envolvem áreas, seu valor é utilizado frequentemente com apenas duas decimais (3.14); assim, caso se desejar usar essa constante com mais decimais, basta alterar na declaração, que esse novo valor será alterado, automaticamente, em todo o programa. 380 4 - Qual é a vantagem de fazer o pseudocódigo depois do algoritmo de um programa?. Resposta: A solução de um problema é dada na fase de algoritmo/pseudocódigo do programa; não na codificação. Então, sem algoritmizar a solução do problema, a codificação ficará muito difícil de ser conseguida; além do mais, caso haja algum erro de lógica no programa, e tiver que rever a solução, isto deve ser feito antes da codificação. 5 - Explique por que o conceito de variável é fundamental na programação, Resposta: O endereço de memória é o local onde são guardados os dados/informações, temporariamente, antes de serem processados. Como o programador não sabe o endereço real na memória RAM, então uma variável é utilizada como endereço simbólico. Portanto, as variáveis representam o que é de mais importante para o programador; como se fossem locais de sua “mesa de trabalho”. 6 - Se você tivesse que nomear uma variável para armazenar o nome do Campeonato Mundial de Futebol da FIFA para 2024, qual dos identificadores é o mais apropriado? A ( ) CampeonatoMundialDeFutebol2024 B ( ) CampeonatoMundialFIFA2024 C (X) FIFA2024 D ( ) FutebolFIFA2024 E ( ) CampeonatoFIFA2024 7 - Explique, com um exemplo, a diferença entre Algoritmo e Pseudocódigo. Resposta: Um pseudocódigo é quase um algoritmo, e muitos autores o consideram assim; entretanto, em termos mais técnicos, 381 o algoritmo é uma “descrição informal da solução do problema”, enquanto que o pseudocódigo é uma “descrição formal da solução do problema”, utilizando recursos de programação e variáveis de memória. Por exemplo: “Somar dois números e mostrar o resultado”. Algoritmo: Pseudocódigo: 1) Pegar o primeiro número. Leia(N1) 2) Pegar o segundo número. Leia(N2) 3) Somar os dois números. S <- N1 + N2 4) Mostrar o resultado da soma. Escreva(S) Observe que o pseudocódigo já é quase um código pronto; uma descrição mais compacta da solução do problema. 8 - De acordo com as teorias de Mark A. Changizi[7], se os vulcanianos - planeta natal do Dr. Spock - tiverem três dedos em cada mão (tal como a criaturinha do filme ET - O Extraterrestre), então, provavelmente, o sistema de numeração deles seria o da base hexa (base 6). Considerando essa teoria, marque nas alternativas abaixo a que aparece um número (representado na Base Decimal) que jamais poderia ser escrito na Base Vulcaniana, considerando que a Matemática vale para todo o Universo. Explique, o porquê da sua resposta. A ( ) 31234 B (X) 4356 //base 6 não pode conter o dígito 6 C ( ) 234100 D ( ) -1 E ( ) 0 9 - Sabemos que para realizar uma tarefa é necessário executar alguns passos (poucos ou muitos, dependendo da solução adotada). Suponha que um cliente deseja que você resolva um 382 problema para ele, através de um programa; e, considerando o esquema abaixo, qual dos três caminhos você escolheria para solucionar esse problema? A ( ) O caminho de cima. B ( ) O caminho do meio. C ( ) O caminho de baixo. D (X) Aquele que produzisse uma solução mais eficaz. E ( ) Qualquer um serviria. 10 - Explique porque a instrução X = X + 1 escrita na linguagem C, por exemplo, não pode ser interpretada como uma equação matemática. Resposta: Matematicamente, a equação acima não tem solução, pois, não existe nenhum número X tal que o membro da esquerda fique idêntico ao membro da direita. Por isto, a interpretação em C, ou em qualquer outra linguagem que use = como operador de atribuição, seria: “X recebe X + 1” não “X é igual a X + 1” 11 - Crie um algoritmo para verificar se um determinando número é primo, ou não. 1) Leia um número inteiro. 2) Descubra os seus divisores. 3) Some a quantidade dos divisores 4) Se (o número de divisores for dois) Então é primo, Senão não é primo. 5) 383 Capítulo 2 1 - Qual é a vantagem de se usar a “Barra de Ícones” do Visualg para executar uma ação na criação de um programa, sabendo que essas mesmas ações podem ser obtidas na “Barra do Menu Principal”? Resposta: A vantagem de usar a Barra de Ícones é a maior agilidade na execução das opções oferecidas pela ferramenta. 2 - Qual é a diferença entre comandos e funções (internos) no Visualg? Dê exemplos. Resposta: As funções sempre retornam algum valor quando executadas; assim, podemos atribuir esse retorno (resultado) à uma variável; por exemplo, X <- RaizQ(16). Os comandos são ordens executadas, e o resultado não pode ser atribuído à uma variável; apenas observar, sentir, seu efeito; por exemplo, o comando LimpaTela apenas limpa a tela; não retorna nada. 3 - Se o Visualg não é uma linguagem real, qual é a sua importância no aprendizado de Linguagem de Programação? Resposta: Embora não seja uma linguagem real de programação, o Visualg é uma ferramenta poderosíssima para testar o algoritmo da solução do problema, traduzido em pseudocódigo (portugol), e o testa, o que auxilia muito no aprendizado de Programação. 4 - Existem erros no programa “AreaCirculo” escrito em Visualg. Mostre quais são esses erros. 384 Algoritmo "AreaCirculo" //Calcula a área de um círculo, dado o seu raio. //----------------------------------------------------- Var raio, area: inteiro Const: PI=3.14159265 Inicio Escreva("Digite o valor do raio do círculo: ") Leia(raio) area <- PI*raio^2 Escreva("Área do círculo: ", area) FimAlgoritmo Resposta: Existem dois erros: o primeiro é que a declaração da constante PI não pode ser feita, por ser uma palavra reserva do Visualg; e além disto, mesmo se pudesse, a declaração de constantes tem que vir ANTES das declarações de variáveis. O segundo erro está no tipo de dado declarado para a variável area, que deveria ser real e não inteiro, pois, seu cálculo resultará num valor não inteiro. 5 - Observe o programa abaixo, em Visualg: ele vai rodar?!. Explique! Algoritmo "AreaTriangulo" //Calcula a área de um triângulo dadas sua base e altura. //----------------------------------------------------- Var B, h, Area: real Início Escreva("Digite o valor da base: ") Leia(b) b <- Abs(b) Escreva("Digite o valor da altura: ") Leia(h) h <- Abs(h) area <- b*h EscrevaLn("Área do triângulo:", Area) FimAlgoritmo 385 Resposta: Sim, vai rodar (se os dados forem entrados corretamente); mas, o resultado para a área do triângulo seria exibido com valor incorreto, devido ao erro no seu cálculo. 6 - Marque com V os identificadores válidos para variáveis e com F para os não válidos. A ( V ) DevIR20 B ( V ) AmanhaDeManhaVouPedirOCafePraNosDois C ( F ) MédiaGeral D ( F ) QteMaçãs E ( F ) 2aNota F ( V )