Desenvolver algoritmos (UC00245)
- Introdução
- 1. Pensamento computacional e definição do problema
- 2. Planear as etapas de um algoritmo
- 3. O que é um algoritmo: ação, estado e propriedades
- 4. Tipos de dados: constantes e variáveis
- 5. Entrada e saída de dados
- 6. Estrutura sequencial
- 7. Estrutura alternativa
- 8. Estruturas repetitivas
- PARA: número de repetições conhecido
- ENQUANTO: pré-teste, número de repetições desconhecido
- REPETIR ATÉ: pós-teste, executa sempre pelo menos uma vez
- Exemplo resolvido · trace table de um ciclo PARA
- Ciclos aninhados
- Exemplo resolvido · tabuadas do 1 ao 3
- PARA com passo e contagem decrescente
- Exemplo resolvido · soma dos algarismos de um número com ENQUANTO
- Exemplo resolvido · número primo
- Converter entre tipos de ciclo
- Exemplo resolvido · menu com REPETIR ATÉ
- 9. Pseudocódigo
- 10. Fluxograma
- 11. Técnicas de construção: contadores, totalizadores, expressões e funções predefinidas
- Contadores e totalizadores
- Expressões aritméticas, relacionais e lógicas
- Funções predefinidas
- Exemplo resolvido · fatorial com acumulador-produto
- Padrões clássicos: média, máximo, mínimo e sentinela
- Exemplo resolvido · estatísticas de uma turma
- Exemplo resolvido · estatísticas com um vetor
- Exemplo resolvido · leitura com sentinela e média
- Funções predefinidas em ação
- Exemplo resolvido · distância entre dois pontos
- Exemplo resolvido · arredondar a duas casas decimais
- Precedência das operações
- 12. Validação, teste e depuração de algoritmos
- 13. Problemas integrados
- Erros comuns
- Glossário
- Síntese
- Exercícios resolvidos
Há um pacote premium desta unidade: um PowerPoint editável de 100 ou mais diapositivos, um manual em PDF e dois testes com correção. Esta sebenta continua gratuita.
Introdução
Esta sebenta ensina a pensar antes de programar: como definir um problema, planear a sua solução e construir um algoritmo correto, testado e legível, seja em pseudocódigo ou em fluxograma. É a base de toda a programação, independentemente da linguagem que vieres a aprender a seguir (Python, Java, C, JavaScript…): quem sabe construir um algoritmo bom no papel, aprende qualquer linguagem em poucas semanas.
O percurso segue sempre o mesmo ciclo: definir o problema, planear as etapas, estruturar em pseudocódigo, desenhar em fluxograma, testar e depurar. São as cinco realizações desta UC, e vamos percorrê-las por esta ordem ao longo dos capítulos seguintes.
Objetivos de aprendizagem (referencial): aplicar os princípios do pensamento computacional; definir problemas e planear as suas etapas de resolução; estruturar algoritmos em pseudocódigo e desenhá-los em fluxograma; usar constantes, variáveis e uma primeira estrutura de dados (o vetor), e as estruturas lógicas sequencial, alternativa e repetitiva; aplicar contadores, totalizadores, expressões aritméticas, funções predefinidas e validação de dados; testar, depurar e otimizar algoritmos.
1. Pensamento computacional e definição do problema
O pensamento computacional é a forma de raciocinar sobre um problema de modo a que a solução possa ser executada, passo a passo, por uma pessoa ou por uma máquina. Assenta em quatro princípios:
- Decomposição: dividir um problema grande em partes mais pequenas e mais simples.
- Reconhecimento de padrões: identificar semelhanças com problemas já resolvidos.
- Abstração: guardar só o que é essencial, ignorando o detalhe irrelevante.
- Algoritmia: desenhar a sequência de passos que resolve o problema.
Antes de desenhar qualquer algoritmo, é preciso definir o problema com rigor. Definir bem um problema significa responder a três perguntas:
- Que dados de entrada (inputs) estão disponíveis?
- Que resultado (output) se pretende obter?
- Que restrições e condições a solução tem de respeitar?
Exemplo resolvido · definir um problema mal formulado
Enunciado vago: "Calcular a média de um aluno."
Esta frase não é um problema bem definido, porque não diz quantas notas, nem de que tipo. Reformulando:
Ler três notas, cada uma entre 0 e 20 valores, e calcular a sua média aritmética, arredondada a uma casa decimal.
Agora já é possível identificar: entrada (três notas reais entre 0 e 20), saída (a média, arredondada), restrição (as notas têm de estar no intervalo 0-20). Só a partir daqui faz sentido planear o algoritmo.
Os quatro princípios na prática
Os princípios do pensamento computacional raramente aparecem sozinhos. Num problema real combinam-se, e vale a pena saber reconhecer cada um quando o usas.
| Princípio | Pergunta que o ativa | Exemplo do dia a dia |
|---|---|---|
| Decomposição | Que partes mais pequenas tem este problema? | Organizar uma viagem: transporte, alojamento, roteiro, orçamento |
| Reconhecimento de padrões | Já resolvi algo parecido? | Calcular o troco numa loja e num parque de estacionamento: pago menos custo |
| Abstração | Que informação posso ignorar sem alterar a resposta? | Um mapa do metro mostra ligações e estações, não a distância real nem os edifícios |
| Algoritmia | Qual é a sequência exata de passos? | Instruções para levantar dinheiro num multibanco |
A abstração merece atenção especial. Quando escreves um algoritmo para calcular o preço de uma pizza, o que interessa é o tamanho e os ingredientes extra, não a cor da caixa nem o nome do estafeta. Decidir o que fica de fora é metade do trabalho: um modelo com detalhe a mais é difícil de testar, e um modelo com detalhe a menos dá respostas erradas.
Exemplo resolvido · definir o problema do parque de estacionamento
Enunciado vago: "Calcular quanto se paga no parque."
O que não está dito: como se mede o tempo, qual é o preço, existe um valor máximo diário, o que acontece se o utilizador sair em menos de uns minutos? Para obter um problema bem definido, o professor, o cliente e o programador têm de acordar um enunciado fechado. Suponhamos o seguinte, com valores fictícios para o exercício:
Ler o número de horas completas de estacionamento (inteiro, de 0 a 24). Cada hora custa 1,50 €, mas o valor total nunca ultrapassa 9,00 € por dia. Mostrar o valor a pagar.
| Elemento | Definição |
|---|---|
| Entrada | horas (inteiro) |
| Saída | valor (real, em euros) |
| Restrições | horas entre 0 e 24; o valor nunca excede 9,00 € |
| Constantes | preço por hora 1.50, limite diário 9.00 |
Com esta tabela feita, o algoritmo quase se escreve sozinho. Testemos com três valores: 2 horas dão 2 * 1.50 = 3.00 €; 6 horas dão 9.00 €, que é exatamente o limite; 10 horas dariam 15.00 €, mas o teto limita a 9.00 €. Ter calculado estes casos antes de escrever o pseudocódigo permite, mais tarde, saber se o algoritmo está certo.
Exemplo resolvido · reconhecer um padrão
Considera estes três enunciados: (1) somar o preço de todos os artigos de um carrinho; (2) somar as horas trabalhadas em cada dia de uma semana; (3) somar as notas de uma turma para calcular a média. À superfície são problemas diferentes, mas o padrão é o mesmo: partir de zero, percorrer uma lista de valores e acumular a soma. Reconhecido o padrão, escreve-se um único esquema de algoritmo (um totalizador dentro de um ciclo, que vemos no capítulo 11) e aplica-se às três situações, trocando apenas o nome das variáveis. É este reaproveitamento que faz um programador tornar-se mais rápido com a experiência.
2. Planear as etapas de um algoritmo
Definido o problema, o passo seguinte é planear a solução: decompor em subproblemas e ordená-los.
- Cada subproblema deve ser mais pequeno e mais simples do que o problema original.
- Ordenar as etapas de forma lógica: o que tem de acontecer antes de quê.
- Para cada etapa, escolher a estrutura lógica mais adequada (capítulos 6 a 8).
- Rever o plano com um exemplo simples, ainda em papel, antes de escrever o pseudocódigo.
Exemplo resolvido · decompor um problema
Problema: calcular o valor a pagar numa loja, com desconto para clientes fidelizados.
Decomposição em subproblemas:
- Ler o valor total da compra.
- Ler se o cliente é fidelizado (sim/não).
- Se for fidelizado, calcular o desconto (10%; percentagem fictícia, só para o exercício).
- Calcular o valor final a pagar.
- Mostrar o resultado ao operador de caixa.
Cada subproblema corresponde a uma ou poucas linhas do algoritmo final. Planear desta forma evita esquecer passos e ajuda a identificar, desde já, que o subproblema 3 vai precisar de uma estrutura alternativa (capítulo 7).
Técnica de refinamentos sucessivos
Uma forma prática de decompor é partir de um enunciado geral e ir refinando em níveis. Cada nível detalha o anterior, até que cada passo seja tão simples que se escreva numa única linha de pseudocódigo. Chama-se abordagem de cima para baixo (top-down).
Um bom plano cumpre critérios simples:
| Critério | Pergunta de verificação |
|---|---|
| Completo | Se executar todos os passos pela ordem, obtenho o resultado pretendido? |
| Ordenado | Cada passo tem à disposição os dados de que precisa? |
| Sem sobreposição | Algum passo repete o trabalho de outro? |
| Testável | Consigo verificar o resultado de cada passo isoladamente? |
| Proporcionado | Os passos têm um tamanho semelhante, sem um gigante rodeado de minúsculos? |
Exemplo resolvido · decompor o tratamento das notas de uma turma
Problema: dadas as notas de 5 alunos, mostrar a média da turma, a nota mais alta e quantos alunos estão aprovados (nota igual ou superior a 10).
Nível 0: tratar as notas da turma.
Nível 1: 1. Ler as 5 notas. 2. Calcular a média. 3. Descobrir a nota mais alta. 4. Contar os aprovados. 5. Mostrar os três resultados.
Nível 2 (refinar os passos 1 a 4, que escondem ciclos): - 1.1 Repetir 5 vezes: pedir e ler uma nota. - 2.1 Somar cada nota lida a um total, que começa em 0. - 2.2 No fim, dividir o total por 5. - 3.1 Guardar a primeira nota como "maior até agora". - 3.2 A cada nota seguinte, se for maior do que a guardada, substituir. - 4.1 Começar um contador a 0 e somar 1 sempre que a nota for maior ou igual a 10.
Repara que os passos 1, 2, 3 e 4 podem partilhar um só ciclo: ler uma nota, somá-la ao total, comparar com o máximo e contar se aprovada. A decomposição serve para pensar com clareza; só depois decidimos como a juntar de forma eficiente. A solução completa deste problema aparece no capítulo 11.
Exemplo resolvido · da decomposição ao plano de testes
Ainda antes de escrever pseudocódigo, o plano pode incluir o que vamos testar. Para o problema acima, antecipamos as notas 12, 8, 15, 10 e 18. Calculamos à mão: o total é 63; a média é 12,6; a nota mais alta é 18; aprovados são 12, 15, 10 e 18, ou seja, 4. Este "gabarito" é o termo de comparação quando o algoritmo estiver escrito.
3. O que é um algoritmo: ação, estado e propriedades
Um algoritmo é uma sequência finita, ordenada e não ambígua de ações que resolve um problema. Cada ação transforma o estado do sistema: muda o valor de uma variável, lê um dado ou escreve um resultado. O estado da ação é a "fotografia" dos valores de todas as variáveis num dado momento da execução.
Todo o algoritmo cumpre quatro propriedades:
| Propriedade | Significa |
|---|---|
| Finito | tem de terminar ao fim de um número finito de passos |
| Definido | cada passo é claro, sem ambiguidade |
| Determinístico | a mesma entrada produz sempre a mesma saída |
| Eficaz | cada passo é realmente executável |
O desenvolvimento de um algoritmo segue sempre o mesmo ciclo, que estrutura o resto desta sebenta:
Definir o problema → Planear as etapas → Estruturar em pseudocódigo
→ Desenhar em fluxograma → Testar e depurar
Ação e estado: seguir o algoritmo passo a passo
Cada ação muda o estado, e é por isso que nos conseguimos convencer de que um algoritmo funciona: seguimos o estado de passo em passo. Escrevemos o estado como uma pequena tabela com uma linha por ação executada.
Exemplo resolvido · trocar o conteúdo de duas variáveis
Problema: a vale 5 e b vale 8. Trocar os valores, de modo a que a fique com 8 e b com 5.
Tentativa ingénua:
a ← b
b ← a
| Ação executada | a |
b |
|---|---|---|
| Estado inicial | 5 | 8 |
a ← b |
8 | 8 |
b ← a |
8 | 8 |
O primeiro valor de a perdeu-se antes de ser copiado. Solução: uma variável auxiliar que guarda temporariamente o valor.
aux ← a
a ← b
b ← aux
| Ação executada | a |
b |
aux |
|---|---|---|---|
| Estado inicial | 5 | 8 | (nenhuma) |
aux ← a |
5 | 8 | 5 |
a ← b |
8 | 8 | 5 |
b ← aux |
8 | 5 | 5 |
Este pequeno exemplo mostra duas lições. A ordem das ações é parte do significado do algoritmo, e uma atribuição substitui o valor anterior de forma irreversível.
As propriedades, com contraexemplos
Perceber uma propriedade é saber reconhecer quando falha.
| Propriedade | Contraexemplo | Porquê falha |
|---|---|---|
| Finito | "Repetir enquanto 1 for igual a 1" | nunca termina |
| Definido | "Juntar sal q.b." | "q.b." depende de quem executa |
| Determinístico | "Escolher um número qualquer" | a mesma entrada não garante a mesma saída |
| Eficaz | "Calcular a raiz quadrada de 2 com todas as casas decimais" | nenhuma máquina executa um número infinito de passos |
Os ciclos infinitos são o exemplo mais frequente de algoritmos que não são finitos e, na prática, bloqueiam o computador.
As etapas de desenvolvimento, uma a uma
| Etapa | Pergunta que responde | Produto |
|---|---|---|
| Definir o problema | O que entra, o que sai, que regras há? | Enunciado fechado |
| Planear | Em que partes se divide e por que ordem? | Lista de subproblemas |
| Estruturar em pseudocódigo | Como escrevo cada passo de forma exata? | Pseudocódigo |
| Desenhar em fluxograma | Consigo ver o fluxo e os desvios? | Fluxograma |
| Testar e depurar | Funciona com dados típicos, limite e inválidos? | Trace tables e correções |
O ciclo raramente é linear: ao testar descobre-se muitas vezes que o problema estava mal definido, e volta-se atrás. Isso não é falhar, é o processo normal de desenvolvimento.
4. Tipos de dados: constantes e variáveis
Um algoritmo manipula dados, guardados em constantes e variáveis:
- Variável: um espaço com nome que guarda um valor que pode mudar durante a execução (ex.:
idade,total). - Constante: um espaço com nome que guarda um valor que não muda (ex.:
IVA ← 0.23).
Toda a variável deve ser inicializada antes de ser usada; usar uma variável sem valor definido é um dos erros mais frequentes desta matéria. Nomes descritivos (preco_total, não x) tornam o algoritmo legível.
Cada dado tem um tipo, que determina as operações válidas:
| Tipo | Exemplos | Operações típicas |
|---|---|---|
| Inteiro | 5, -3, 120 |
+ - * DIV MOD |
| Real | 3.14, -0.5 |
+ - * / |
| Texto (cadeia) | "Aulify" |
concatenação |
| Lógico (booleano) | Verdadeiro, Falso |
E, OU, NÃO |
Escolher o tipo certo evita erros: 7 DIV 2 = 3 (divisão inteira), mas 7 / 2 = 3.5 (divisão real).
Nomes, tipos e conversões
Os nomes de variáveis seguem regras simples nesta sebenta: começam por uma letra, usam letras minúsculas, algarismos e _, sem espaços, e descrevem o conteúdo (preco_unitario, numAlunos). Evitamos acentos nos nomes para facilitar a transição para as linguagens de programação.
A escolha do tipo depende do que se faz com o dado, não apenas do seu aspeto:
| Dado | Tipo adequado | Razão |
|---|---|---|
| Idade | Inteiro | contam-se anos completos |
| Preço | Real | tem cêntimos |
| Quantidade de artigos | Inteiro | não existem 2,5 canetas |
| Número de telefone | Texto | não se somam telefones, e pode começar por zero ou por + |
| Código postal | Texto | contém um hífen e zeros à esquerda |
| Aprovado? | Lógico | só tem dois valores possíveis |
Quando um número é guardado como texto, as operações aritméticas deixam de fazer sentido; quando um código é guardado como número, perdem-se os zeros à esquerda. Em ambos os casos o tipo errado produz um erro silencioso.
O texto tem operações próprias. A concatenação junta cadeias ("Olá, " + nome) e a função COMPRIMENTO(nome) devolve quantos carateres tem. O tipo lógico combina-se com E, OU e NÃO, e é o resultado natural de qualquer comparação.
Exemplo resolvido · declarar os dados de uma compra
Problema: guardar o nome do produto, o preço unitário, a quantidade e se há promoção.
| Nome | Tipo | Constante ou variável | Exemplo |
|---|---|---|---|
produto |
Texto | variável | "Rato sem fios" |
preco_unitario |
Real | variável | 12.50 |
quantidade |
Inteiro | variável | 3 |
ha_promocao |
Lógico | variável | Verdadeiro |
TAXA_PROMO |
Real | constante | 0.10 |
Com estes dados, total ← preco_unitario * quantidade dá 37.50, e SE ha_promocao ENTÃO total ← total - total * TAXA_PROMO reduz-o para 33.75. Conferindo as contas: 12.50 * 3 = 37.50; 37.50 * 0.10 = 3.75; 37.50 - 3.75 = 33.75. Preço e taxa fictícios, só para o exercício.
Repara que a taxa de promoção é uma constante com nome. Se escrevesses 0.10 em vários sítios do algoritmo e depois a taxa mudasse, terias de encontrar todas as ocorrências; com a constante, mudas uma única linha.
Atribuição versus igualdade
Duas ideias que confundem os principiantes. A atribuição x ← x + 1 não é uma equação matemática (que seria impossível): lê-se "calcula o valor atual de x mais 1 e guarda o resultado em x". Já a comparação x = 5 pergunta se x vale 5 e devolve Verdadeiro ou Falso, sem mudar nada.
Estruturas de dados: o vetor
Até aqui, cada variável guardava um único valor. Quando há vários valores do mesmo tipo e do mesmo significado (as notas de uma turma, os preços de uma encomenda), cinco variáveis soltas tornam-se pouco práticas. Uma estrutura de dados resolve isso: organiza vários valores sob um só nome. A mais simples é o vetor, que guarda vários valores do mesmo tipo, cada um identificado por um índice (nesta sebenta, a começar em 1). notas[1] é a primeira nota e notas[5] a quinta.
notas: vetor de 5 reais
total ← 0
PARA i DE 1 ATÉ 5 FAÇA
LER notas[i]
total ← total + notas[i]
FIM PARA
ESCREVER "Média: ", total / 5
Com as notas 12, 8, 15, 10 e 18 o vetor fica [12, 8, 15, 10, 18], o total é 63 e a média é 12.6. A vantagem sobre cinco variáveis soltas é poder percorrer todos os valores com um ciclo PARA (que estudamos no capítulo 8) e guardá-los para os consultar depois: terminada a leitura, notas[3] continua a valer 15. O índice tem de estar entre 1 e o tamanho do vetor; notas[6] não existe e seria um erro.
5. Entrada e saída de dados
Todo o algoritmo interage com o exterior através de duas operações elementares: LER e ESCREVER.
INICIO
ESCREVER "Introduza o seu nome:"
LER nome
ESCREVER "Olá, ", nome
FIM
Boas práticas:
- Mensagens claras, que dizem exatamente o que se espera (ex.: "Introduza a nota (0 a 20):").
- Pedir (
ESCREVERa mensagem) sempre antes deLERo valor. - Separar a leitura dos dados do seu processamento: primeiro ler tudo o que é preciso, só depois calcular.
- A saída deve ser legível: texto explicativo, não só o número (
"Total: 45.50 €", não apenas45.50).
Mais exemplos de entrada e saída
Uma interação bem desenhada guia o utilizador e devolve um resultado completo.
Exemplo resolvido · soma e produto de dois números
INICIO
ESCREVER "Primeiro número:"
LER a
ESCREVER "Segundo número:"
LER b
soma ← a + b
produto ← a * b
ESCREVER "Soma: ", soma
ESCREVER "Produto: ", produto
FIM
Se o utilizador escrever 6 e 7, o ecrã mostra Soma: 13 e Produto: 42. Repara na estrutura de três blocos que se repete em quase todos os algoritmos: entrada, processamento, saída.
Quando um dado é lido várias vezes
Para ler, por exemplo, três notas, não é preciso escrever três vezes o mesmo bloco de pedido e leitura se usarmos um ciclo (capítulo 8). Mas fora de ciclos, é aceitável ler variáveis distintas, uma por dado, sempre com uma mensagem própria para cada uma. Uma mensagem pouco específica ("Introduza um valor:") confunde o utilizador quando há vários valores a pedir.
6. Estrutura sequencial
A estrutura sequencial é a mais simples das três estruturas lógicas: as ações executam-se uma a seguir à outra, pela ordem em que foram escritas.
Exemplo resolvido · área de um retângulo
INICIO
LER base
LER altura
area ← base * altura
ESCREVER "Área: ", area
FIM
Não há decisões nem repetições, só uma linha reta de execução. A ordem das instruções não é arbitrária: uma variável só pode ser usada depois de ter sido definida, por isso base e altura são lidas antes de area ser calculada. A estrutura sequencial é a base sobre a qual se constroem as duas estruturas seguintes.
Mais exemplos de estrutura sequencial
Exemplo resolvido · converter graus Celsius em Fahrenheit
A fórmula é F = C * 9 / 5 + 32.
INICIO
ESCREVER "Temperatura em Celsius:"
LER celsius
fahrenheit ← celsius * 9 / 5 + 32
ESCREVER celsius, " °C = ", fahrenheit, " °F"
FIM
Testes, feitos à mão antes de executar: 0 °C dá 32 °F; 100 °C dá 212 °F; 37 °C dá 98.6 °F. O algoritmo é puramente sequencial, e a ordem de cálculo respeita a precedência das operações: multiplica e divide primeiro, soma depois.
Exemplo resolvido · converter segundos em horas, minutos e segundos
Problema: dado um número de segundos, mostrar a duração no formato horas, minutos e segundos.
Este é um bom problema para praticar DIV e MOD.
INICIO
LER total
horas ← total DIV 3600
resto ← total MOD 3600
minutos ← resto DIV 60
segundos ← resto MOD 60
ESCREVER horas, "h ", minutos, "min ", segundos, "s"
FIM
Trace para total = 3725:
| Ação | horas |
resto |
minutos |
segundos |
|---|---|---|---|---|
LER total (3725) |
(nenhuma) | (nenhuma) | (nenhuma) | (nenhuma) |
horas ← 3725 DIV 3600 |
1 | (nenhuma) | (nenhuma) | (nenhuma) |
resto ← 3725 MOD 3600 |
1 | 125 | (nenhuma) | (nenhuma) |
minutos ← 125 DIV 60 |
1 | 125 | 2 | (nenhuma) |
segundos ← 125 MOD 60 |
1 | 125 | 2 | 5 |
O resultado é 1h 2min 5s. Confirma: 1 * 3600 + 2 * 60 + 5 = 3725. Esta contraprova, fazer a operação inversa, é uma ótima forma de testar.
O erro da ordem trocada
Um erro frequente nas sequências é usar uma variável antes de lhe dar valor. Se, no exemplo acima, a linha minutos ← resto DIV 60 viesse antes de resto ← total MOD 3600, o algoritmo usaria um resto que ainda não existe. Num algoritmo sequencial, cada linha só pode depender do que está acima.
7. Estrutura alternativa
A estrutura alternativa permite escolher entre caminhos diferentes consoante uma condição, que só pode ser Verdadeira ou Falsa.
SE simples:
SE nota >= 10 ENTÃO
ESCREVER "Aprovado"
FIM SE
SE composto (com SENÃO, para o caso em que a condição é falsa):
SE nota >= 10 ENTÃO
ESCREVER "Aprovado"
SENÃO
ESCREVER "Reprovado"
FIM SE
SE encadeado, quando há mais de duas hipóteses:
SE nota >= 18 ENTÃO
ESCREVER "Excelente"
SENÃO SE nota >= 10 ENTÃO
ESCREVER "Aprovado"
SENÃO
ESCREVER "Reprovado"
FIM SE
As condições são testadas por ordem, de cima para baixo; assim que uma é verdadeira, as restantes deixam de ser testadas. Regra prática: nunca mais do que 2 ou 3 níveis de aninhamento, ou o algoritmo torna-se ilegível.
Exemplo resolvido · desconto por categoria
Problema: ler o preço de uma compra e a categoria do cliente ("Premium" ou "Regular"), aplicando 15% de desconto a clientes Premium (sempre) e 5% a clientes Regular apenas quando a compra ultrapassa 50 €. Percentagens e valores fictícios, só para o exercício.
INICIO
LER preco
LER categoria
SE categoria = "Premium" ENTÃO
desconto ← preco * 0.15
SENÃO SE categoria = "Regular" E preco > 50 ENTÃO
desconto ← preco * 0.05
SENÃO
desconto ← 0
FIM SE
total ← preco - desconto
ESCREVER "Total a pagar: ", total
FIM
Condições compostas e tabelas de verdade
Uma condição pode juntar várias comparações com os operadores lógicos. A tabela de verdade diz o resultado de cada combinação.
A |
B |
A E B |
A OU B |
NÃO A |
|---|---|---|---|---|
| Verdadeiro | Verdadeiro | Verdadeiro | Verdadeiro | Falso |
| Verdadeiro | Falso | Falso | Verdadeiro | Falso |
| Falso | Verdadeiro | Falso | Verdadeiro | Verdadeiro |
| Falso | Falso | Falso | Falso | Verdadeiro |
Em palavras: E só é verdadeiro quando ambas as condições o são; OU só é falso quando ambas o são; NÃO inverte o valor. Quando misturas E e OU na mesma condição, usa parênteses para tornar a intenção explícita: SE (idade >= 18 E temCartao) OU eFuncionario ENTÃO.
Uma regra útil para simplificar condições negadas (as leis de De Morgan): NÃO (A E B) equivale a (NÃO A) OU (NÃO B), e NÃO (A OU B) equivale a (NÃO A) E (NÃO B). Por exemplo, "não é (maior de idade e com cartão)" é o mesmo que "é menor de idade ou não tem cartão".
Exemplo resolvido · par ou ímpar
Um número é par se o resto da divisão por 2 for zero.
INICIO
LER n
SE n MOD 2 = 0 ENTÃO
ESCREVER n, " é par"
SENÃO
ESCREVER n, " é ímpar"
FIM SE
FIM
Testes: 10 MOD 2 = 0 dá par; 7 MOD 2 = 1 dá ímpar; 0 MOD 2 = 0 dá par (o zero é par). O caso do zero é típico de valor-limite, e mostra que o algoritmo está correto sem exceções.
Exemplo resolvido · a ordem das condições num SE encadeado
Considera uma classificação com quatro escalões: 0 a 9 "Insuficiente", 10 a 13 "Suficiente", 14 a 17 "Bom", 18 a 20 "Excelente". Um aluno escreve:
SE nota >= 10 ENTÃO
ESCREVER "Suficiente"
SENÃO SE nota >= 14 ENTÃO
ESCREVER "Bom"
SENÃO SE nota >= 18 ENTÃO
ESCREVER "Excelente"
SENÃO
ESCREVER "Insuficiente"
FIM SE
Com nota = 19 o algoritmo escreve "Suficiente", porque 19 >= 10 é verdadeiro e as restantes condições nunca chegam a ser testadas. A correção é testar do caso mais exigente para o menos exigente:
SE nota >= 18 ENTÃO
ESCREVER "Excelente"
SENÃO SE nota >= 14 ENTÃO
ESCREVER "Bom"
SENÃO SE nota >= 10 ENTÃO
ESCREVER "Suficiente"
SENÃO
ESCREVER "Insuficiente"
FIM SE
Testes com valores nas fronteiras: 9 dá Insuficiente, 10 dá Suficiente, 13 dá Suficiente, 14 dá Bom, 17 dá Bom, 18 dá Excelente, 20 dá Excelente. As fronteiras são onde os erros se escondem.
Exemplo resolvido · ano bissexto
Um ano é bissexto se for divisível por 4, exceto se for divisível por 100, a não ser que também seja divisível por 400.
INICIO
LER ano
SE (ano MOD 4 = 0 E ano MOD 100 <> 0) OU ano MOD 400 = 0 ENTÃO
ESCREVER ano, " é bissexto"
SENÃO
ESCREVER ano, " não é bissexto"
FIM SE
FIM
ano |
MOD 4 = 0 |
MOD 100 <> 0 |
MOD 400 = 0 |
Resultado |
|---|---|---|---|---|
| 2024 | Verdadeiro | Verdadeiro | Falso | bissexto |
| 1900 | Verdadeiro | Falso | Falso | não bissexto |
| 2000 | Verdadeiro | Falso | Verdadeiro | bissexto |
| 2023 | Falso | Verdadeiro | Falso | não bissexto |
Esta tabela é uma forma excelente de testar condições compostas: uma linha por caso e uma coluna por cada parte da condição.
Exemplo resolvido · o maior de três números
INICIO
LER a
LER b
LER c
maior ← a
SE b > maior ENTÃO
maior ← b
FIM SE
SE c > maior ENTÃO
maior ← c
FIM SE
ESCREVER "O maior é ", maior
FIM
Em vez de compararmos todos com todos (que exigiria muitos E e vários ramos), partimos do pressuposto de que o primeiro é o maior e corrigimos à medida que encontramos um valor maior. Para a = 4, b = 9, c = 7: maior começa em 4, passa a 9 no primeiro SE e mantém-se em 9 no segundo. Este esquema repete-se com listas de qualquer tamanho (capítulo 11).
8. Estruturas repetitivas
Uma estrutura repetitiva (ciclo) executa um bloco de instruções várias vezes. Há três formas, cada uma adequada a uma situação diferente.
PARA: número de repetições conhecido
PARA i DE 1 ATÉ 10 FAÇA
ESCREVER i
FIM PARA
i é a variável de controlo, atualizada automaticamente a cada iteração. DE ... ATÉ ... define o intervalo; PASSO (opcional) define o incremento.
ENQUANTO: pré-teste, número de repetições desconhecido
LER num
ENQUANTO num <> 0 FAÇA
ESCREVER "Recebi: ", num
LER num
FIM ENQUANTO
A condição é testada antes de cada iteração; se já for falsa à partida, o corpo nunca executa.
REPETIR ATÉ: pós-teste, executa sempre pelo menos uma vez
REPETIR
ESCREVER "Introduza a nota (0-20):"
LER nota
ATÉ nota >= 0 E nota <= 20
| ENQUANTO | REPETIR ATÉ | |
|---|---|---|
| Teste | antes (pré-teste) | depois (pós-teste) |
| Executa pelo menos uma vez | não garante | sim, sempre |
| Uso típico | leitura com sentinela | validação de entrada |
Exemplo resolvido · trace table de um ciclo PARA
Para o algoritmo soma ← 0; PARA i DE 1 ATÉ 5 FAÇA soma ← soma + i FIM PARA:
| Iteração | i |
soma (depois) |
|---|---|---|
| Inicial | (nenhuma) | 0 |
| 1 | 1 | 1 |
| 2 | 2 | 3 |
| 3 | 3 | 6 |
| 4 | 4 | 10 |
| 5 | 5 | 15 |
A cada iteração, a tabela regista o novo valor da variável de controlo e do acumulador. É a ferramenta central para testar ciclos (capítulo 12).
Ciclos aninhados
Um ciclo pode conter outro ciclo. O ciclo interior executa-se por completo, do início ao fim, a cada iteração do ciclo exterior.
Exemplo resolvido · tabuadas do 1 ao 3
PARA i DE 1 ATÉ 3 FAÇA
PARA j DE 1 ATÉ 3 FAÇA
ESCREVER i, " x ", j, " = ", i * j
FIM PARA
FIM PARA
i |
j |
Escreve |
|---|---|---|
| 1 | 1 | 1 x 1 = 1 |
| 1 | 2 | 1 x 2 = 2 |
| 1 | 3 | 1 x 3 = 3 |
| 2 | 1 | 2 x 1 = 2 |
| 2 | 2 | 2 x 2 = 4 |
| 2 | 3 | 2 x 3 = 6 |
| 3 | 1 | 3 x 1 = 3 |
| 3 | 2 | 3 x 2 = 6 |
| 3 | 3 | 3 x 3 = 9 |
O corpo interior executa 3 * 3 = 9 vezes. Em geral, se o exterior repete m vezes e o interior n, o corpo interior corre m * n vezes. Isto importa para a otimização: ciclos aninhados crescem depressa.
PARA com passo e contagem decrescente
O PASSO altera o incremento. Um passo negativo conta para trás.
PARA i DE 10 ATÉ 1 PASSO -1 FAÇA
ESCREVER i
FIM PARA
ESCREVER "Fogo!"
Escreve 10, 9, 8, ..., 1 e depois "Fogo!". Outro uso comum é percorrer os pares: PARA i DE 2 ATÉ 10 PASSO 2 visita 2, 4, 6, 8 e 10. A soma destes cinco valores é 30.
Exemplo resolvido · soma dos algarismos de um número com ENQUANTO
Problema: dado um inteiro positivo, somar os seus algarismos. Aqui não sabemos à partida quantos algarismos tem, por isso PARA não serve.
INICIO
LER n
soma ← 0
ENQUANTO n > 0 FAÇA
soma ← soma + n MOD 10
n ← n DIV 10
FIM ENQUANTO
ESCREVER "Soma dos algarismos: ", soma
FIM
Ideia: n MOD 10 isola o último algarismo e n DIV 10 retira-o. Trace para n = 1234:
| Iteração | n (no teste) |
último algarismo | soma (depois) |
n (depois) |
|---|---|---|---|---|
| 1 | 1234 | 4 | 4 | 123 |
| 2 | 123 | 3 | 7 | 12 |
| 3 | 12 | 2 | 9 | 1 |
| 4 | 1 | 1 | 10 | 0 |
| Teste | 0 | (nenhuma) | 10 | 0 |
Com n = 0 na quinta verificação a condição n > 0 é falsa e o ciclo termina. O resultado é 10. Repara que este ciclo termina sempre, porque n diminui a cada passagem e acaba por chegar a 0.
Exemplo resolvido · número primo
Um número é primo se for maior do que 1 e só tiver dois divisores: 1 e ele próprio. Para decidir, tentamos dividir por todos os valores de 2 até n - 1.
INICIO
LER n
primo ← Verdadeiro
SE n < 2 ENTÃO
primo ← Falso
FIM SE
d ← 2
ENQUANTO d < n E primo FAÇA
SE n MOD d = 0 ENTÃO
primo ← Falso
FIM SE
d ← d + 1
FIM ENQUANTO
SE primo ENTÃO
ESCREVER n, " é primo"
SENÃO
ESCREVER n, " não é primo"
FIM SE
FIM
Variável lógica primo funciona como uma bandeira (flag): parte de Verdadeiro e baixa a Falso quando se descobre um divisor. Trace para n = 9:
d |
9 MOD d |
primo (depois) |
|---|---|---|
| 2 | 1 | Verdadeiro |
| 3 | 0 | Falso |
Como primo ficou Falso, a condição d < n E primo deixa de ser verdadeira e o ciclo para. Resultado: 9 não é primo. Para n = 7 o ciclo percorre d de 2 a 6 sem encontrar divisor, e 7 é primo. Para n = 1 e n = 2 o ciclo nem chega a executar (no 1 por ser menor que 2; no 2 porque d < n é falso logo à partida), e o resultado é o correto: 1 não é primo, 2 é primo.
Converter entre tipos de ciclo
Qualquer PARA pode escrever-se como ENQUANTO: inicializa-se a variável de controlo antes, testa-se a condição e incrementa-se no fim do corpo.
i ← 1
ENQUANTO i <= 5 FAÇA
ESCREVER i
i ← i + 1
FIM ENQUANTO
faz o mesmo que PARA i DE 1 ATÉ 5 FAÇA ESCREVER i FIM PARA. O inverso nem sempre é natural, e é por isso que escolhemos o ciclo que exprime melhor a intenção: PARA quando o número de repetições é conhecido, ENQUANTO quando depende de uma condição que pode falhar logo à primeira, REPETIR ATÉ quando o corpo tem de correr pelo menos uma vez.
Exemplo resolvido · menu com REPETIR ATÉ
REPETIR
ESCREVER "1 - Somar 2 - Multiplicar 0 - Sair"
LER opcao
SE opcao = 1 ENTÃO
ESCREVER "A somar..."
SENÃO SE opcao = 2 ENTÃO
ESCREVER "A multiplicar..."
FIM SE
ATÉ opcao = 0
O menu tem de aparecer pelo menos uma vez para que o utilizador possa escolher, o que torna o REPETIR ATÉ a escolha natural. Se o utilizador escrever 5, nenhum ramo é executado e o menu volta a aparecer.
9. Pseudocódigo
O pseudocódigo é uma notação intermédia entre a linguagem natural e uma linguagem de programação: estruturada, mas sem a sintaxe rígida de uma linguagem em concreto. Convenções desta sebenta:
- Blocos delimitados por
INICIO/FIMe porFIM SE,FIM PARA,FIM ENQUANTO. - Atribuição com
←; comparação de igualdade com=. - Indentação consistente, para mostrar o aninhamento das estruturas.
- Vocabulário em português:
LER,ESCREVER,SE,ENTÃO,SENÃO,PARA,ENQUANTO,REPETIR.
Boas práticas de escrita:
- Nomes descritivos:
preco_total, nãox. - Comentar só o que não é óbvio; um pseudocódigo bem escrito explica-se sozinho.
- Evitar duplicar código: se o mesmo bloco aparece duas vezes, falta reorganizar o algoritmo.
- Testar mentalmente com um exemplo pequeno antes de dar o pseudocódigo por terminado.
O pseudocódigo é transferível para qualquer linguagem: quem sabe pensar em pseudocódigo aprende Python, Java ou C em poucas semanas.
Do pseudocódigo ao código
O pseudocódigo é independente da linguagem, mas a tradução para uma linguagem real é direta. Vê como o mesmo algoritmo se escreve em pseudocódigo e em Python:
INICIO
total ← 0
PARA i DE 1 ATÉ 5 FAÇA
LER preco
total ← total + preco
FIM PARA
ESCREVER "Total: ", total
FIM
total = 0
for i in range(1, 6):
preco = float(input("Preço: "))
total = total + preco
print("Total:", total)
Correspondência entre os dois mundos:
| Pseudocódigo | Python |
|---|---|
← |
= |
= (comparar) |
== |
<> |
!= |
E, OU, NÃO |
and, or, not |
PARA i DE 1 ATÉ 5 |
for i in range(1, 6) |
ENQUANTO cond FAÇA |
while cond: |
DIV, MOD |
//, % |
Em Python, range(1, 6) termina antes de 6, o que é uma das diferenças que apanham os principiantes. A estrutura lógica é a mesma, só a sintaxe muda: por isso se diz que quem domina o pseudocódigo aprende uma linguagem depressa.
Exemplo resolvido · bom e mau pseudocódigo
Mau:
LER x
LER y
z ← x * y / 2
ESCREVER z
Bom:
INICIO
ESCREVER "Base do triângulo:"
LER base
ESCREVER "Altura do triângulo:"
LER altura
area ← base * altura / 2
ESCREVER "Área: ", area
FIM
Os dois fazem o mesmo, mas o segundo explica-se sozinho: quem o lê percebe que calcula a área de um triângulo, sem precisar de adivinhar o que são x, y e z. Com base = 6 e altura = 4, a área é 12.
10. Fluxograma
O fluxograma representa o algoritmo com símbolos gráficos normalizados (norma ISO 5807:1985), ligados por setas que indicam o fluxo de execução.
| Símbolo | Nome | Representa |
|---|---|---|
| Retângulo de cantos arredondados (muitas aplicações usam uma elipse) | Terminal | início ou fim |
| Paralelogramo | Entrada/Saída | LER, ESCREVER |
| Retângulo | Processo | cálculo, atribuição |
| Losango | Decisão | condição (SE) |
| Seta | Fluxo | ordem de execução |
Regras de boa prática (não são exigências da norma):
- Um único símbolo terminal de início e, normalmente, um de fim.
- Todo o losango tem exatamente duas saídas: Verdadeiro e Falso.
- As setas nunca se cruzam sem necessidade; o fluxo lê-se de cima para baixo.
- Todos os caminhos convergem antes do terminal final.
Exemplo resolvido · converter pseudocódigo em fluxograma
Para o pseudocódigo:
INICIO
LER nota
SE nota >= 10 ENTÃO
ESCREVER "Aprovado"
SENÃO
ESCREVER "Reprovado"
FIM SE
FIM
O fluxograma equivalente é: Terminal «INÍCIO» → Paralelogramo «LER nota» → Losango «nota ≥ 10?» com duas saídas (V leva a Paralelogramo «ESCREVER Aprovado»; F leva a Paralelogramo «ESCREVER Reprovado») → as duas saídas convergem → Terminal «FIM». Fluxograma e pseudocódigo são duas representações do mesmo algoritmo: o que se pode escrever num, pode desenhar-se no outro. Aplicações de desenho de algoritmos (draw.io, Lucidchart, Flowgorithm) ajudam a manter a norma.
Representar ciclos no fluxograma
Os ciclos desenham-se com um losango de decisão cuja saída "Falso" ou "Verdadeiro" volta atrás por uma seta, formando um circuito. Para o ENQUANTO, o losango fica no topo do circuito (o teste é feito antes do corpo). Para o REPETIR ATÉ, o losango fica no fim (o teste é feito depois do corpo).
Exemplo resolvido · fluxograma de um ciclo com contador
Pseudocódigo:
INICIO
i ← 1
ENQUANTO i <= 3 FAÇA
ESCREVER i
i ← i + 1
FIM ENQUANTO
FIM
Fluxograma, lido seta a seta:
- Terminal «INÍCIO».
- Retângulo «i ← 1».
- Losango «i ≤ 3?». Se Verdadeiro, segue para o passo 4. Se Falso, segue para o passo 6.
- Paralelogramo «ESCREVER i».
- Retângulo «i ← i + 1», com seta de volta ao losango do passo 3.
- Terminal «FIM».
Percorrendo o desenho com i = 1, 2 e 3, o algoritmo escreve 1, 2 e 3; com i = 4 o losango dá Falso e o fluxo sai do circuito. Se esquecesses o retângulo do passo 5, o desenho mostraria logo o problema: a seta de retorno passaria por um ponto onde nada altera i, e o circuito nunca terminaria. É por isso que o fluxograma é uma boa ferramenta para detetar ciclos infinitos.
Método para passar do pseudocódigo ao fluxograma
| Passo | O que fazer |
|---|---|
| 1 | Desenha o terminal de início |
| 2 | Para cada LER ou ESCREVER, um paralelogramo |
| 3 | Para cada atribuição ou cálculo, um retângulo |
| 4 | Para cada SE, um losango com duas saídas rotuladas, que se voltam a juntar no fim da estrutura |
| 5 | Para cada ciclo, um losango com seta de retorno |
| 6 | Termina com o terminal de fim, onde todos os caminhos convergem |
Erros frequentes nos fluxogramas
| Erro | Porquê é um problema |
|---|---|
| Losango com uma só saída | uma decisão tem sempre dois resultados |
| Setas sem rótulo nas decisões | não se sabe qual é o ramo Verdadeiro |
| Caminhos que não chegam ao terminal final | o algoritmo parece nunca terminar |
| Texto longo dentro dos símbolos | perde-se a leitura rápida; escreve a ação, não uma frase |
| Retângulo usado para leitura de dados | os dados lidos ou escritos usam o paralelogramo |
Na prática, as aplicações de desenho de algoritmos permitem mover símbolos, alinhar setas e exportar a imagem. Algumas, como o Flowgorithm, executam o fluxograma passo a passo, o que equivale a uma trace table automática. Escolhe a ferramenta que a turma tiver disponível: o importante é a lógica, não o programa.
11. Técnicas de construção: contadores, totalizadores, expressões e funções predefinidas
Contadores e totalizadores
Um contador regista quantas vezes algo acontece, somando sempre a mesma quantidade fixa (tipicamente 1):
contador ← 0
PARA i DE 1 ATÉ n FAÇA
LER nota
SE nota >= 10 ENTÃO
contador ← contador + 1
FIM SE
FIM PARA
Um totalizador (ou acumulador) soma valores variáveis, lidos ou calculados a cada iteração:
total ← 0
PARA i DE 1 ATÉ n FAÇA
LER preco
total ← total + preco
FIM PARA
Inicializa-se um acumulador-soma a 0, e um acumulador-produto a 1 (por exemplo, no cálculo de um fatorial); inicializar mal é a causa mais comum de resultados errados neste padrão.
Expressões aritméticas, relacionais e lógicas
| Tipo | Operadores | Resultado |
|---|---|---|
| Aritmética | + - * / DIV MOD ^ |
um número |
| Relacional | = <> < > <= >= |
Verdadeiro/Falso |
| Lógica | E, OU, NÃO |
Verdadeiro/Falso |
DIV devolve a parte inteira da divisão, MOD devolve o resto: 7 DIV 2 = 3, 7 MOD 2 = 1. As expressões lógicas combinam várias condições, como em SE idade >= 18 E temCartao ENTÃO.
Funções predefinidas
| Função | Faz |
|---|---|
RAIZ(x) |
raiz quadrada de x |
ABS(x) |
valor absoluto de x |
ARREDONDAR(x) |
arredonda x ao inteiro mais próximo |
MAIOR(a, b) / MENOR(a, b) |
maior ou menor de dois valores |
COMPRIMENTO(cadeia) |
número de carateres de uma cadeia de texto |
Usar uma função predefinida evita reescrever, com risco de erro, uma operação que já existe.
Exemplo resolvido · fatorial com acumulador-produto
INICIO
LER n
fact ← 1
PARA i DE 1 ATÉ n FAÇA
fact ← fact * i
FIM PARA
ESCREVER n, "! = ", fact
FIM
Para n = 0, o ciclo não executa e o resultado fica 1 (0! = 1, por definição), o que é correto graças à inicialização fact ← 1.
Padrões clássicos: média, máximo, mínimo e sentinela
Muitos problemas resolvem-se combinando poucos esquemas. Vale a pena conhecê-los pelo nome.
| Padrão | Para que serve | Inicialização típica |
|---|---|---|
| Contador | quantos casos | contador ← 0 |
| Totalizador | soma de valores | total ← 0 |
| Acumulador-produto | produto de valores | produto ← 1 |
| Máximo | maior valor | maior ← primeiro valor lido |
| Mínimo | menor valor | menor ← primeiro valor lido |
| Média | total dividido por contador | calcula-se no fim, depois do ciclo |
| Sentinela | valor especial que termina a leitura | lê-se antes do ciclo e dentro dele |
| Bandeira (flag) | memória de um acontecimento | achou ← Falso |
Para o máximo e o mínimo, inicializar a 0 é uma armadilha: se todas as notas lidas fossem negativas (num contexto em que isso fizesse sentido) o máximo ficaria em 0, que nem sequer foi lido. A regra segura é partir do primeiro valor lido.
Exemplo resolvido · estatísticas de uma turma
Retomamos o problema do capítulo 2: ler as notas de 5 alunos e mostrar a média, a nota mais alta, a mais baixa e quantos estão aprovados.
INICIO
total ← 0
aprovados ← 0
ESCREVER "Nota do aluno 1 (0 a 20):"
LER nota
maior ← nota
menor ← nota
total ← nota
SE nota >= 10 ENTÃO
aprovados ← aprovados + 1
FIM SE
PARA i DE 2 ATÉ 5 FAÇA
ESCREVER "Nota do aluno ", i, " (0 a 20):"
LER nota
total ← total + nota
SE nota > maior ENTÃO
maior ← nota
FIM SE
SE nota < menor ENTÃO
menor ← nota
FIM SE
SE nota >= 10 ENTÃO
aprovados ← aprovados + 1
FIM SE
FIM PARA
media ← total / 5
ESCREVER "Média: ", media
ESCREVER "Maior: ", maior, " Menor: ", menor
ESCREVER "Aprovados: ", aprovados
FIM
Trace com as notas 12, 8, 15, 10 e 18:
| Passo | nota |
total |
maior |
menor |
aprovados |
|---|---|---|---|---|---|
| Primeira leitura | 12 | 12 | 12 | 12 | 1 |
i = 2 |
8 | 20 | 12 | 8 | 1 |
i = 3 |
15 | 35 | 15 | 8 | 2 |
i = 4 |
10 | 45 | 15 | 8 | 3 |
i = 5 |
18 | 63 | 18 | 8 | 4 |
No fim: média 63 / 5 = 12.6, maior 18, menor 8, aprovados 4. Estes valores coincidem com o gabarito calculado à mão no planeamento. Quando o algoritmo e o gabarito concordam, ganhamos confiança; quando discordam, descobrimos um erro.
A primeira leitura fora do ciclo pode parecer repetição de código, mas serve para inicializar maior e menor com um valor real. Há soluções alternativas (usar um valor inicial convencional), mas esta é a mais segura.
Exemplo resolvido · estatísticas com um vetor
Se as notas ficarem guardadas num vetor, podem consultar-se mais do que uma vez depois de lidas. Com as mesmas notas 12, 8, 15, 10 e 18:
INICIO
notas: vetor de 5 reais
total ← 0
PARA i DE 1 ATÉ 5 FAÇA
ESCREVER "Nota do aluno ", i, " (0 a 20):"
LER notas[i]
total ← total + notas[i]
FIM PARA
maior ← notas[1]
PARA i DE 2 ATÉ 5 FAÇA
SE notas[i] > maior ENTÃO
maior ← notas[i]
FIM SE
FIM PARA
ESCREVER "Média: ", total / 5
ESCREVER "Maior: ", maior
FIM
O total é 63 e a média 12.6. Para o máximo, maior parte de notas[1] (12), passa a 15 em notas[3] e a 18 em notas[5], e no fim vale 18. Repara que há dois ciclos: só é possível percorrer os dados uma segunda vez porque o vetor os guardou. Sem vetor, o máximo e a média têm de ser calculados num único ciclo, como no exemplo anterior.
Exemplo resolvido · leitura com sentinela e média
Problema: ler idades até ser introduzido -1, que não conta como idade, e mostrar a média. Se não houver idades, avisar.
INICIO
total ← 0
contador ← 0
LER idade
ENQUANTO idade <> -1 FAÇA
total ← total + idade
contador ← contador + 1
LER idade
FIM ENQUANTO
SE contador = 0 ENTÃO
ESCREVER "Nenhuma idade introduzida."
SENÃO
ESCREVER "Média: ", total / contador
FIM SE
FIM
Trace com a sequência 20, 30, 40, -1:
| Iteração | idade processada |
total |
contador |
próxima leitura |
|---|---|---|---|---|
| Antes do ciclo | (nenhuma) | 0 | 0 | 20 |
| 1 | 20 | 20 | 1 | 30 |
| 2 | 30 | 50 | 2 | 40 |
| 3 | 40 | 90 | 3 | -1 |
| Teste final | (nenhuma) | 90 | 3 | (nenhuma) |
A média é 90 / 3 = 30. A verificação contador = 0 evita uma divisão por zero quando o utilizador escreve logo -1. Repara no padrão do sentinela: uma leitura antes do ciclo, outra no fim do corpo. Se a leitura estivesse no início do corpo, o -1 seria processado como se fosse uma idade.
Funções predefinidas em ação
Exemplo resolvido · distância entre dois pontos
A distância entre os pontos (x1, y1) e (x2, y2) é a raiz quadrada de (x2 - x1)^2 + (y2 - y1)^2.
INICIO
LER x1
LER y1
LER x2
LER y2
dx ← x2 - x1
dy ← y2 - y1
distancia ← RAIZ(dx * dx + dy * dy)
ESCREVER "Distância: ", distancia
FIM
Para os pontos (0, 0) e (3, 4): dx = 3, dy = 4, soma dos quadrados 9 + 16 = 25, e RAIZ(25) = 5. Escrevemos dx * dx em vez de usar um operador de potência para evitar dependermos de uma notação específica; ambas são válidas.
Exemplo resolvido · arredondar a duas casas decimais
Uma função ARREDONDAR(x) devolve o inteiro mais próximo. Para obter duas casas decimais, multiplica-se por 100, arredonda-se e divide-se por 100:
valor ← 3.14159
arredondado ← ARREDONDAR(valor * 100) / 100
3.14159 * 100 = 314.159, que arredondado dá 314; dividido por 100, obtém-se 3.14. É um exemplo de como se combinam funções simples para obter funções mais úteis. Outro exemplo é a diferença absoluta entre duas leituras: ABS(a - b) dá sempre um valor não negativo, qualquer que seja a ordem dos operandos.
Precedência das operações
Numa expressão, a ordem de cálculo é: parênteses, depois ^, depois * / DIV MOD, depois + -, da esquerda para a direita em caso de empate. Por isso 2 + 3 * 4 vale 14 e (2 + 3) * 4 vale 20. Na dúvida, usa parênteses: custam pouco e evitam muitos erros.
12. Validação, teste e depuração de algoritmos
Validação de dados
Validar é confirmar que um valor lido está dentro do intervalo ou formato esperado, antes de o usar nos cálculos. Sem validação, dados absurdos (uma nota de 250, uma idade negativa) contaminam todo o resultado. O padrão combina sempre um REPETIR ATÉ com uma condição de validade:
REPETIR
ESCREVER "Idade (0-120):"
LER idade
SE idade < 0 OU idade > 120 ENTÃO
ESCREVER "Valor fora do intervalo. Tente outra vez."
FIM SE
ATÉ idade >= 0 E idade <= 120
Cada validação é uma fronteira de confiança: depois dela, o resto do algoritmo pode assumir que o valor está correto. É uma forma de programação defensiva: escrever o algoritmo de modo a que dados inesperados não o façam falhar.
Testar com trace tables
Testar um algoritmo é executá-lo, à mão ou no computador, com dados concretos, e confirmar que o resultado está certo. A ferramenta principal é a trace table, como a do capítulo 8. É essencial escolher casos de teste variados: valores típicos, valores-limite (0, negativos) e valores inválidos.
Depurar: erros comuns e correção
| Erro típico | Causa | Correção |
|---|---|---|
| Ciclo infinito | variável de controlo não muda | garantir incremento/decremento no corpo |
| Resultado sempre 0 | acumulador-produto (multiplicação) inicializado a 0 em vez de 1 | inicializar a 1 antes do ciclo |
| Totalizador nunca aumenta (fica sempre 0) | falta a instrução de acumulação (totalizador ← totalizador + valor) dentro do ciclo |
garantir que a acumulação está dentro do corpo do ciclo |
| Off-by-one (falta ou sobra uma iteração) | limites do PARA mal definidos |
rever DE/ATÉ |
Depurar (debug) é encontrar e corrigir os erros detetados no teste, sempre a partir da causa, não por tentativa. Depois de correto, um algoritmo pode ainda ser otimizado: combinar cálculos numa só passagem pelos dados, eliminar código repetido e escolher a estrutura mais direta, sem mudar o resultado. Todo este trabalho é apoiado por IDEs, compiladores e aplicações de desenho de algoritmos e fluxogramas.
Tipos de validação
A validação não se resume a intervalos. Há vários tipos, e cada um tem a sua condição.
| Tipo | Pergunta | Exemplo de condição |
|---|---|---|
| Intervalo | O valor está entre dois limites? | nota >= 0 E nota <= 20 |
| Obrigatoriedade | Foi preenchido? | COMPRIMENTO(nome) > 0 |
| Comprimento | Tem o tamanho certo? | COMPRIMENTO(codigo) = 4 |
| Lista de valores | É uma das opções permitidas? | opcao = 1 OU opcao = 2 OU opcao = 3 |
| Coerência | Combina com outros dados? | dataFim >= dataInicio |
Exemplo resolvido · validar com mensagem de erro e limite de tentativas
Em situações reais, não se deve prender o utilizador para sempre. Este algoritmo dá no máximo 3 tentativas para introduzir uma nota válida.
INICIO
tentativas ← 0
valida ← Falso
ENQUANTO tentativas < 3 E NÃO valida FAÇA
ESCREVER "Nota (0 a 20):"
LER nota
tentativas ← tentativas + 1
SE nota >= 0 E nota <= 20 ENTÃO
valida ← Verdadeiro
SENÃO
ESCREVER "Valor inválido."
FIM SE
FIM ENQUANTO
SE valida ENTÃO
ESCREVER "Nota registada: ", nota
SENÃO
ESCREVER "Número de tentativas esgotado."
FIM SE
FIM
Trace com as leituras 25, -3 e 14:
| Tentativa | nota |
valida |
Mensagem |
|---|---|---|---|
| 1 | 25 | Falso | Valor inválido. |
| 2 | -3 | Falso | Valor inválido. |
| 3 | 14 | Verdadeiro | (nenhuma) |
Com as leituras 25, -3 e 40, as três tentativas gastam-se sem valida mudar e o algoritmo escreve «Número de tentativas esgotado.». Há aqui uma combinação de bandeira, contador e validação, as três técnicas a trabalharem juntas.
Desenhar casos de teste
Um bom conjunto de testes cobre três famílias:
| Família | Objetivo | Exemplo para uma nota (0 a 20) |
|---|---|---|
| Típicos | confirmar o funcionamento normal | 7, 12, 16 |
| Limite | verificar as fronteiras | 0, 9, 10, 19, 20 |
| Inválidos | confirmar que são recusados | -1, 21, 250 |
Cada caso tem de ter o resultado esperado calculado antes de executar o algoritmo. Se calculas o esperado depois de ver o resultado, estás a confirmar o que já lá estava, não a testar.
Com a classificação do capítulo 7 (Insuficiente, Suficiente, Bom, Excelente), uma tabela de testes completa seria:
| Nota | Esperado |
|---|---|
| 0 | Insuficiente |
| 9 | Insuficiente |
| 10 | Suficiente |
| 13 | Suficiente |
| 14 | Bom |
| 17 | Bom |
| 18 | Excelente |
| 20 | Excelente |
Oito testes cobrem todas as fronteiras, e se todos passam, há uma forte garantia de que a estrutura SE está bem escrita.
Exemplo resolvido · depurar uma média
Um aluno escreveu:
LER a
LER b
LER c
media ← a + b + c / 3
ESCREVER media
Para a = 10, b = 12, c = 14, o resultado esperado é (10 + 12 + 14) / 3 = 12. O algoritmo escreve cerca de 26.67. Para encontrar o erro, seguimos a precedência: a divisão faz-se primeiro, 14 / 3 = 4.67, e só depois as somas, 10 + 12 + 4.67 = 26.67. A causa é a ausência de parênteses. Corrigido:
media ← (a + b + c) / 3
O método foi: (1) calcular o esperado, (2) comparar com o obtido, (3) seguir a execução para localizar onde divergem, (4) corrigir a causa. Corrigir sem localizar a causa leva a remendos que escondem o problema.
Técnicas de depuração
| Técnica | Como se faz |
|---|---|
| Trace table | seguir as variáveis passo a passo, à mão |
| Escritas intermédias | acrescentar ESCREVER temporários para ver os valores a meio do algoritmo |
| Isolar o problema | testar cada subproblema sozinho, como decidimos no planeamento |
| Explicar em voz alta | contar o algoritmo, linha a linha, a um colega: muitas vezes o erro aparece ao explicar |
| Reduzir o caso | repetir o erro com os dados mais pequenos possíveis |
Estas técnicas mostram a vantagem de ter decomposto o problema em partes. Um erro num algoritmo de 5 linhas é fácil de achar; num de 80 linhas, só se se puder testar por partes.
Otimizar, com cuidado
Otimizar vem depois de o algoritmo estar correto e testado. Algumas otimizações simples:
| Antes | Depois | Ganho |
|---|---|---|
| Dois ciclos, um para a soma e outro para o máximo | Um só ciclo a fazer as duas coisas | metade das passagens pelos dados |
Testar todos os divisores de 2 a n - 1 sem parar |
Parar assim que se encontra um divisor (como já faz a bandeira primo do capítulo 8) ou testar só até RAIZ(n) |
menos iterações |
| Mesma expressão calculada várias vezes | guardá-la numa variável | menos cálculo e mais legibilidade |
Três SE seguidos mutuamente exclusivos |
um SE encadeado |
menos testes |
Depois de otimizar, volta a correr todos os testes. Uma otimização que muda o resultado não é uma otimização, é um erro novo.
13. Problemas integrados
Este capítulo junta as técnicas anteriores em problemas completos. Segue sempre o ciclo: definir, planear, estruturar, testar.
Exemplo resolvido · caixa de loja com total e desconto
Definição. Ler o preço de cada artigo, até o operador escrever 0. Preços negativos são recusados. No fim, mostrar o número de artigos e o total. Se o total passar de 50 €, aplicar um desconto de 5%. Valores e percentagem são fictícios, para o exercício.
| Elemento | Definição |
|---|---|
| Entrada | preços (reais), 0 para terminar |
| Saída | número de artigos, total, desconto, total a pagar |
| Restrições | preço não negativo; desconto só acima de 50 € |
| Constantes | LIMITE ← 50, TAXA ← 0.05 |
Planeamento. (1) inicializar contador e totalizador; (2) ler o primeiro preço; (3) enquanto não for 0, validar, somar, contar e ler o seguinte; (4) calcular o desconto; (5) mostrar o resumo.
INICIO
LIMITE ← 50
TAXA ← 0.05
total ← 0
artigos ← 0
LER preco
ENQUANTO preco <> 0 FAÇA
SE preco < 0 ENTÃO
ESCREVER "Preço inválido, ignorado."
SENÃO
total ← total + preco
artigos ← artigos + 1
FIM SE
LER preco
FIM ENQUANTO
desconto ← 0
SE total > LIMITE ENTÃO
desconto ← total * TAXA
FIM SE
ESCREVER "Artigos: ", artigos
ESCREVER "Total: ", total
ESCREVER "Desconto: ", desconto
ESCREVER "A pagar: ", total - desconto
FIM
Teste. Sequência 20, -5, 30, 10, 0.
| Leitura processada | total |
artigos |
Nota |
|---|---|---|---|
| 20 | 20 | 1 | |
| -5 | 20 | 1 | recusado |
| 30 | 50 | 2 | |
| 10 | 60 | 3 | |
| 0 | 60 | 3 | termina |
Como 60 > 50, desconto = 60 * 0.05 = 3.00, e o valor a pagar é 60 - 3 = 57. Teste-limite: se o total fosse exatamente 50, o desconto não se aplicaria, porque a condição é > e não >=. Este pormenor deve estar escrito no enunciado, e o teste deve confirmá-lo.
Exemplo resolvido · adivinhar o número secreto
Definição. O número secreto é uma constante (7). O jogador tenta adivinhar; o programa diz se o palpite é maior ou menor e conta as tentativas.
INICIO
SECRETO ← 7
tentativas ← 0
REPETIR
ESCREVER "Palpite:"
LER palpite
tentativas ← tentativas + 1
SE palpite > SECRETO ENTÃO
ESCREVER "Demasiado alto."
SENÃO SE palpite < SECRETO ENTÃO
ESCREVER "Demasiado baixo."
FIM SE
ATÉ palpite = SECRETO
ESCREVER "Acertou em ", tentativas, " tentativas."
FIM
Trace com os palpites 5, 9, 7:
| Palpite | tentativas |
Mensagem | Sai? |
|---|---|---|---|
| 5 | 1 | Demasiado baixo. | não |
| 9 | 2 | Demasiado alto. | não |
| 7 | 3 | (nenhuma) | sim |
Escreve «Acertou em 3 tentativas.». Escolhemos REPETIR ATÉ porque o jogador tem de tentar pelo menos uma vez. Num jogo real, o número seria sorteado, o que levaria a uma função específica da linguagem que não faz parte destas funções predefinidas básicas; aqui o objetivo é treinar a estrutura.
Escolher a estrutura certa
| Se o problema pede... | Usa... |
|---|---|
| Executar ações por ordem, sem decisões | estrutura sequencial |
| Escolher entre dois caminhos | SE ... SENÃO |
| Escolher entre vários escalões | SE encadeado, do mais exigente para o menos |
| Repetir um número conhecido de vezes | PARA |
| Repetir até um valor especial, sem saber quantas vezes | ENQUANTO com sentinela |
| Pedir e repetir até o dado ser aceitável | REPETIR ATÉ |
| Contar casos | contador |
| Somar valores | totalizador |
| Memorizar se algo aconteceu | bandeira lógica |
Como se relacionam as realizações da UC
As cinco realizações do referencial correspondem a momentos do mesmo trabalho: definir o problema (capítulos 1 e 2), planear as etapas (capítulos 2 e 3), estruturar em pseudocódigo (capítulos 4 a 9, 11 e 12), desenhar em fluxograma (capítulo 10) e testar e depurar (capítulo 12). Os problemas integrados deste capítulo mobilizam todas as cinco, e são o modelo para o projeto e para a ficha de avaliação.
Erros comuns
- Definir mal o problema: avançar para o pseudocódigo sem saber ao certo o que entra e o que sai.
- Variável não inicializada: usar um acumulador ou contador sem lhe atribuir valor antes do ciclo.
- Confundir contador com totalizador: um soma sempre 1, o outro soma um valor variável.
- Ciclo infinito: esquecer de atualizar a variável testada num
ENQUANTO. - Inicializar mal um acumulador-produto: a 0 em vez de 1, o que anula todo o cálculo.
- Erro off-by-one: limites mal definidos num
PARA, a mais ou a menos uma iteração. - Ignorar a validação: aceitar qualquer valor lido, sem confirmar que está no intervalo esperado.
-
Testar só com um caso: nunca verificar os valores-limite (0, negativos, vazios).
-
Trocar duas variáveis sem auxiliar: copiar
a ← be depoisb ← aperde o valor original dea. - Testar as condições do SE encadeado pela ordem errada: a condição menos exigente "apanha" casos que deviam ser tratados antes.
- Inicializar o máximo ou o mínimo a 0: parte-se de um valor que pode nunca ter sido lido; o correto é partir do primeiro valor lido.
- Dividir por zero: calcular uma média sem verificar se houve pelo menos um valor lido.
- Esquecer a leitura dentro do ciclo: o sentinela é lido antes do ciclo e no fim do corpo; sem a segunda leitura o ciclo nunca termina.
- Esquecer os parênteses:
a + b + c / 3não é a média de três valores. - Usar
>quando o enunciado diz «igual ou superior»: o erro só aparece no valor exato da fronteira. - Guardar um código ou um telefone como número: perdem-se zeros à esquerda e sinais.
- Otimizar antes de testar: uma versão mais curta que ninguém verificou é só um erro mais discreto.
- Calcular o resultado esperado depois de ver o obtido: assim o teste só confirma o que já lá estava.
Glossário
- Algoritmo: sequência finita, ordenada e não ambígua de ações que resolve um problema.
- Pensamento computacional: forma de raciocinar sobre um problema para que a solução seja executável passo a passo.
- Decomposição: dividir um problema em subproblemas mais simples.
- Variável: espaço com nome que guarda um valor que pode mudar.
- Constante: espaço com nome que guarda um valor fixo.
- Estrutura sequencial: ações executadas uma a seguir à outra, sem desvios.
- Estrutura alternativa: escolha de caminho consoante uma condição (SE).
- Estrutura repetitiva: bloco de instruções executado várias vezes (PARA, ENQUANTO, REPETIR ATÉ).
- Contador: variável que regista quantas vezes algo acontece, somando sempre a mesma quantidade.
- Totalizador / acumulador: variável que soma valores variáveis ao longo de um ciclo.
- Pseudocódigo: notação estruturada intermédia entre linguagem natural e linguagem de programação.
- Fluxograma: representação gráfica normalizada de um algoritmo (norma ISO 5807).
- Validação de dados: confirmação de que um valor lido cumpre o intervalo ou formato esperado.
- Trace table: tabela que regista o valor das variáveis a cada iteração, usada para testar um algoritmo.
- Depurar (debug): encontrar e corrigir erros detetados no teste de um algoritmo.
-
Ciclo infinito: repetição cuja condição de paragem nunca se torna falsa.
-
Abstração: guardar apenas a informação essencial para resolver o problema.
- Estado: conjunto dos valores de todas as variáveis num dado momento da execução.
- Atribuição: ação que guarda um valor numa variável, substituindo o anterior.
- Variável auxiliar: variável usada temporariamente, por exemplo para trocar dois valores.
- Sentinela: valor especial que, quando lido, indica o fim de uma sequência de dados.
- Bandeira (flag): variável lógica que memoriza se um acontecimento já ocorreu.
- Valor-limite: valor na fronteira de um intervalo ou de uma condição, onde os erros se escondem.
- Caso de teste: conjunto de dados de entrada com o resultado esperado calculado de antemão.
- Ciclo aninhado: ciclo colocado dentro do corpo de outro ciclo.
- Precedência: ordem em que as operações de uma expressão são calculadas.
- Concatenação: operação que junta duas cadeias de texto numa só.
- Refinamento sucessivo: decomposição em níveis, de cada vez mais detalhe, de cima para baixo.
- Acumulador-produto: variável que multiplica valores ao longo de um ciclo, inicializada a 1.
- Divisão inteira (DIV): divisão que devolve só a parte inteira do quociente.
- Resto (MOD): resto da divisão inteira.
- Estrutura de dados: forma de organizar vários valores sob um só nome.
- Vetor: estrutura de dados que guarda vários valores do mesmo tipo, identificados por um índice.
- Índice: posição de um valor dentro de um vetor (nesta sebenta, a começar em 1).
- Programação defensiva: escrever o algoritmo de modo a que dados inesperados não o façam falhar.
Síntese
Construir um algoritmo segue sempre a mesma ordem: definir o problema (inputs, outputs, restrições) → planear as etapas (decompor e ordenar) → estruturar em pseudocódigo, com constantes e variáveis, as estruturas sequencial, alternativa e repetitiva (PARA, ENQUANTO, REPETIR ATÉ), vetores, contadores, totalizadores, expressões e funções predefinidas, e validação de dados → desenhar em fluxograma (símbolos ISO 5807) → testar e depurar, com trace tables, casos típicos, limite e inválidos, e por fim otimizar, sempre voltando a correr os testes. Os problemas integrados do capítulo 13 mostram as cinco realizações a trabalhar em conjunto. Domina este ciclo e estarás pronto para aprender qualquer linguagem de programação.
Exercícios resolvidos
1. Classifica cada ciclo pelo tipo mais adequado: (a) imprimir os múltiplos de 3 até 30; (b) ler senhas até o utilizador acertar; (c) ler números até aparecer um 0, sem saber quantos virão.
Resolução: (a) PARA, o número de iterações é conhecido (10 múltiplos); (b) REPETIR ATÉ, executa pelo menos uma vez e só sai quando acerta; (c) ENQUANTO, o número de leituras não é conhecido à partida.
2. Um algoritmo calcula soma ← 0; PARA i DE 1 ATÉ n FAÇA soma ← soma * i FIM PARA. Qual é o erro?
Resolução: usa
*(multiplicação) em vez de+(adição) para calcular uma soma, e a inicializaçãosoma ← 0torna o produto sempre0. O erro combina lógica errada (operador) com inicialização incompatível com um acumulador-produto.
3. Porque é que ENQUANTO conta <> 10 FAÇA conta ← conta + 3 FIM ENQUANTO, partindo de conta ← 0, nunca termina?
Resolução:
contatoma os valores 0, 3, 6, 9, 12, 15, … e nunca é exatamente10, porque o incremento de 3 "salta" por cima desse valor. A condiçãoconta <> 10mantém-se sempre verdadeira. Ciclo infinito; a correção seria usarconta < 10como condição.
4. Distingue um contador de um totalizador e dá um exemplo de cada um no mesmo algoritmo.
Resolução: o contador soma sempre a mesma quantidade fixa (normalmente 1), por exemplo
contador ← contador + 1para contar quantas notas foram lidas. O totalizador soma valores variáveis, por exemplosoma ← soma + nota. Usados em conjunto, permitem calcular uma média:media ← soma / contador.
5. Um algoritmo lê a idade do utilizador sem a validar. Porque é isso um problema, e como corrigir?
Resolução: sem validação, um valor absurdo (por exemplo, uma idade negativa ou 300) é aceite e contamina os cálculos seguintes. A correção passa por um
REPETIR ATÉque só aceita valores dentro de um intervalo razoável (por exemplo, 0 a 120), mostrando uma mensagem de erro em cada tentativa inválida.
6. Escreve um algoritmo que leia um número inteiro e diga se é par ou ímpar. Testa-o com 10, 7 e 0.
Resolução:
SE n MOD 2 = 0 ENTÃO ESCREVER "par" SENÃO ESCREVER "ímpar" FIM SE. Com 10,10 MOD 2 = 0, par. Com 7,7 MOD 2 = 1, ímpar. Com 0,0 MOD 2 = 0, par; o zero é um valor-limite e o algoritmo trata-o bem.
7. Converte 4000 segundos em horas, minutos e segundos.
Resolução:
4000 DIV 3600 = 1hora, resto4000 MOD 3600 = 400;400 DIV 60 = 6minutos, resto400 MOD 60 = 40segundos. Resultado: 1 h 6 min 40 s. Contraprova:3600 + 360 + 40 = 4000.
8. O ciclo n ← 5072; soma ← 0; ENQUANTO n > 0 FAÇA soma ← soma + n MOD 10; n ← n DIV 10 FIM ENQUANTO termina? Qual é o valor final de soma?
Resolução: termina, porque
ndiminui a cada iteração e chega a 0. Os valores densão 5072, 507, 50, 5 e 0; os algarismos somados são 2, 7, 0 e 5. A soma final é 14.
9. Um algoritmo classifica notas com SE nota >= 10 ... SENÃO SE nota >= 14 ... SENÃO SE nota >= 18 .... Que classificação recebe o 16 e porquê está errado?
Resolução: recebe a do primeiro ramo (a de
>= 10, «Suficiente»), porque16 >= 10é verdadeiro e os outros testes nunca são feitos; devia receber a do segundo ramo (>= 14, «Bom»). Deve-se testar do mais exigente para o menos exigente: primeiro>= 18, depois>= 14, depois>= 10.
10. Constrói a trace table de um algoritmo que lê as notas 9, 14, 10, 7 e 20 e calcula total, maior e aprovados (nota igual ou superior a 10).
Resolução: após cada leitura,
totaltoma os valores 9, 23, 33, 40 e 60;maiortoma 9, 14, 14, 14 e 20;aprovadostoma 0, 1, 2, 2 e 3. Média final:60 / 5 = 12.
11. Porque é que, ao calcular a média de idades lidas até ao sentinela -1, convém testar contador = 0 antes da divisão?
Resolução: se o utilizador escrever
-1logo à primeira leitura,contadorfica a 0 e a divisãototal / contadorseria uma divisão por zero. O teste permite mostrar uma mensagem em vez de falhar. Com as leituras 15, 25 e-1,contadoré 2,totalé 40 e a média é40 / 2 = 20.
12. Corrige media ← a + b + c / 3 e mostra que a versão corrigida dá 13 para 9, 12 e 18.
Resolução:
media ← (a + b + c) / 3. Com os valores dados,(9 + 12 + 18) / 3 = 39 / 3 = 13. A versão errada dava9 + 12 + 18 / 3 = 9 + 12 + 6 = 27, porque a divisão tem precedência sobre a soma.
13. Num vetor temp de 4 reais, guardaram-se as temperaturas 18, 21, 19 e 24. Qual é o valor de temp[3], qual é a média, e o que acontece com temp[5]?
Resolução:
temp[3]vale 19, porque o índice começa em 1. A soma é18 + 21 + 19 + 24 = 82e a média é82 / 4 = 20.5. O índice 5 está fora do vetor, que só tem posições de 1 a 4: aceder-lhe é um erro.