Seletores

Atualizado pela última vez em 18/NOV/20.

Os seletores são comandos que determinam qual o próximo comando a ser executado ou ainda quais os caminhos possíveis da sequência de comandos. São também chamados de estruturas condicionais porque determinam condições para escolher um ou outro caminho.

Tipos de seletores

Os dois tipos principais de seletores são:

Como tudo na programação, é possível obter resultados corretos e semelhantes de formas variadas. Quando programadores usam um tipo de seletor no lugar de outro, podem até conseguir o efeito desejado, mas estão dificultando a criação e a manutenção do programa. Para saber qual qual tipo de seletor usar, você pensar no significado deles, conforme apresentado acima.

Você realmente quer usar uma sequência de seletores unidirecionais?

Um problema comum quando se está aprendendo a programar é usar uma sequência de seletores unidirecionais, quando se deveria usar seletores bidirecionais aninhados. Uma sequência assim só deve ser usada quando existe uma sequência de instruções opcionais, o que não é comum. Na maioria das vezes, o que o programador quer é escolher um dentre vários caminhos possíveis.

Por exemplo: suponha que você deseja escrever um programa que lê um número e diz se ele é positivo, nulo ou negativo. Uma forma ruim de resolver isso é:

Ruim (sequência de seletores unidirecionais):

cin >> numero; if (numero > 0) cout << "positivo"; if (numero == 0) cout << "nulo"; if (numero < 0) cout << "negativo"; cout << endl;

Bom (seletores bidirecionais aninhados):

cin >> numero; if (numero > 0) cout << "positivo"; else if (numero == 0) cout << "nulo"; else cout << "negativo"; cout << endl;

A primeira forma é mais perigosa, porque dá vontade de usar Ctrl-C/CtrlV para repetir trechos de código e com frequência se esquece de fazer ajustes no código copiado. Além disso, erros nos testes podem fazer com que o programa diga que o número é positivo mas também diga que é negativo (pois um caminho não excluiu os outros) ou ainda que o programa não dê resposta alguma. Escrever testes errados é algo mais fácil de se notar em seletores bidirecionais aninhados, porque sempre um e somente um caminho de execução será seguido.

A primeira forma também é menos eficiente porque requer a execução de três comparações entre o número e zero, qualquer que seja o número. A segunda forma requer uma ou às vezes duas comparações, mas nunca três. Comparações são operações bem lentas em processadores modernos. Quando um código assim aparece dentro de uma repetição extensa, pode ser possível notar a diferença de velocidade.

Você realmente quer terminar isso com um if?

Terminar um conjunto de seletores bidirecionais aninhados com um seletor unidirecional é ineficiente porque inclui um teste inútil e é perigoso porque o código deixa de ser uma escolha de um entre vários caminhos e passa a ser uma escolha de um dos caminhos ou de nenhum deles (ver seção anterior).

Ruim (seletor unidirecional no fim):

if (n < 0) cout << "negativo" else if (n == 0) cout << "nulo" else if (n > 0) cout << "positivo"

Bom:

if (n < 0) cout << "negativo" else if (n == 0) cout << "nulo" else cout << "positivo"

Testes excessivos

Na verificação de intervalos é comum o uso excessivo de comparações que podem ser facilmente evitadas. Lembre-se que quanto mais comparações você escreve, mais tempo você gasta para escrever, mais tempo será gasto na execução e mais lugares para erro existirão no seu programa.

Toda vez que algo aparece mais de uma vez no seu programa, é um indício de que algo pode ser simplificado. No exemplo abaixo, testar se o nível é menor ou igual a 3 é a mesma coisa de testar se ele é maior ou igual 4 pois não tem como ser os dois. Se o computador já testou se é ≤ 3 e viu que não era, não há porque testar na sequência se é ≥ 4.

Exemplo de classificação de nível de alerta inteiro, no intervalo [0, 10], com verificação de valor válido:

Ruim (6 comparações):

if ((nivel >= 0) and (nivel <= 3)) cout << "Nível baixo." << endl; else if ((nivel >= 4) and (nivel <= 6)) cout << "Nível médio." << endl; else if ((nivel >= 7) and (nivel <= 10)) cout << "Nível alto." << endl; else cout << "Nível fora do intervalo." << endl;

Bom (4 comparações):

if ((nivel < 0) or (nivel > 10)) cout << "Nível fora do intervalo." << endl; else if (nivel < 4) cout << "Nível baixo." << endl; else if (nivel < 7) cout << "Nível médio." << endl; else cout << "Nível alto." << endl;

Vale também lembrar que a verificação de valor válido não costuma ser exigida em IAlg e não faz muito sentido até que aprenda sobre tratamento de erros. Portanto o primeiro caminho no bom exemplo acima é normalmente desnecessário, sendo necessárias duas comparações para escolha entre baixo, médio e alto.

Seletores e testes

Seletores estão diretamente relacionados com as escolhas de entradas para testar se o programa funciona. Faça testes para cada caminho de execução possível.

Esta página é mantida por Bruno Schneider para a disciplina de IAlg