Introdução ao comando de seleção e às expressões lógicas

[ Expressão em C | Expressão em Python | Operadores | Seleção | Seleções | Exemplo | Par ou ímpar ]

Como ler este texto. Aqui procuro explicar os fundamentos do comando de seleção `if-else` tanto para as linguagens C quanto Python. Em várias seções apresento os conceitos básicos ilustrando-os em tabelas, com uma coluna ou linha para cada linguagem. Mas existe uma seção em que apresento o conceito de expressão lógica separandamente, assim, se lhe interessar apenas uma das linguagens, leia apenas a seção correspondente.

Na seção sobre variáveis, ressaltamos a importância de poder variar os valores armazenados em determinada posição de memória, por intermédio das variáveis.

Entretanto se não fosse possível executar uma ação específica apenas quando determinada condição ocorrer, de acordo com o valor de algumas variáveis, não se poderia fazer muito com o computador. Isso pode ser feito efetuando-se uma conta e verificando se o resultado é nulo ou não, sendo nulo segue-se determinado "caminho" no código e em caso negativo, segue-se outro (executa outros comando).

Mas a explicação acima está quase ao nível do hardware, portanto baixo-nível. De um ponto de vista mais elevado (alto-nível), as linguagens de programação como C e Python dispõem de um comando que permite tal seleção de caminho de execução é o comando `if-else`.

A figura 1.a e 1.b ilustram o desvio do fluxo de execução de acordo com o resultado da condição, do resultado da condição lógica, se verdadeiro segue o caminho indicado pela seta com rótulo sim e se falso segue outro. Adicionalmente, nota-se que o comando de seleção (ou desvio de fluxo) pode explicitar um caminho para o caso da expressão lógica resultar falso, figura 1.b, ou simplesmente apresentar o caminho no caso de verdadeiro, na figura 1.a.

Fig. 1. Diagrama de fluxo de execução (a) sem o ramo de senão e (b) com o ramo de senão ..

Expressão lógica em C

Na linguagem C, qualquer expressão (mesmo que aritmética) dentro de abre e fecha parênteses `(...)` é interpretado como uma expressão lógica, como nos dois exemplos de comandos abaixo:

    if (a==b) <verm>printf</verm>("%d == %d\n", a, b);
    while (i < N) { <verm>printf</verm>("i = %d\n", i); i++; }

Cód. 1. Exemplos de expressão lógica em C.

Ou seja, o tratamento de expressões é mais um exemplo de que o contexto pode mudar a forma como os dados são interpretados.

Mas vale a pena notar que a linguagem C permite construções cujo processamento é uma pouco mais rápido, mas menos intuitivo, é permitido usar qualquer expressão aritmética (como `a-b`) dentro do contexto de expressão lógica! Isso é possível a partir do seguinte "truque": calcula-se o resultado da expressão aritmética, se o seu resultado for diferente de 0, ele é interpretado como sendo o valor lógico verdeiro, caso contrário como falso. Desse modo, no comando seguinte, sempre que a variável inteira N tiver valor não nulo, será "impresso" OK e se o valor for nulo será "impresso" NAO:

`if (N) <verm>printf</verm>("OK\n"); else <verm>printf</verm>("NAO\n");`.
Cód. 2. Exemplos de expressão aritmética tratada como expressão lógica em C.
Negação em C. Pode-se usar o operador `!` (exclamação) para negar o resultado da expressão lógica (que esteja à sua direita). Por exemplo, os seguintes trechos de código são equivalentes em C:

`if (a==b) <verm>printf</verm>("OK"); else <verm>printf</verm>("NAO");`

`if (!(a-b)) <verm>printf</verm>("OK"); else <verm>printf</verm>("NAO");`

Cód. 3. Exemplos de uso de negação em expressão lógica em C.

Fica fácil entender a razão dos dois códigos serem equivalente ao observarmos que a == b é a mesma coisa que a - b == 0 e, usando a negação, a != b é a mesma coisa que a - b != 0 e essa última expressão equivale à expressão !((a - b) == 0) (negar que (a - b) == 0).

Portanto, a expressão `a-b` é interpretada como expressão lógica, do seguinte modo: seu resultado é verdadeiro se, e somente se `a-b!=0` (`a-b` não nulo), por isso usamos a negação para inverter o resultado, ou seja, `!(a-b)` equivale a negar `a-b` (e portanto negar `a-b!=0`).

<porque> Atenção programadores C, um erro bastante comum ao tentar usar o operador relacional `==` é acabar digitando apenas `=`. Em função da explicação acima, não existe qualquer erro sintático, o código será gerado, mas ao rodar, pode ser muito difícil detectar esse erro semântico.
O resultado de um comando como `if (a=b) <verm>printf</verm>("Sao iguais\n");` é que, se `a` estiver com qualquer valor diferente de zero, a mensagem será impressa.
Para descobrir este tipo de erro uma boa técnica é usar bandeiras. </porque>

Expressão e valor lógicos em Python

Em Python existem um particular tipo de variável que é booleano, sendo que uma variável boleana pode ter apenas os valores: True e False.

Assim, uma expressão lógica em Python deve sempre resultar nos valores lógicos True ou False. Deste modo os três blocos de comandos abaixo podem ser usados e são equivalente, entretanto o primeiro (mais à esquerda) é mais eficiente:

`varlog = a == b <cyan># ou: varlog = (a == b)</cyan> if (varlog) : <verm>print</verm>("OK") else : <verm>print</verm>("NAO")`

`varlog = (a == b) <cyan># ou: varlog = a == b</cyan> if (varlog == True) : <verm>print</verm>("OK") else : <verm>print</verm>("NAO")`

`varlog = (a == b) <cyan># ou: varlog = a == b</cyan> if (not (varlog == False)) : <verm>print</verm>("OK") else : <verm>print</verm>("NAO")`

Cód. 4. Exemplos de uso de negação em expressão lógica em C.

Note que no exemplo acima mais à direita usamos `not (varlog == False)` que equivale a `varlog == True`, que portanto também equivale a `varlog` (pois está armazenando valore booleanos).

Operadores lógicos em C e em Python

Os operadores lógicos e relacionais básicos são os mesmo tanto em C quanto em Python. Os operadores relacionais (relações entre expressões aritméticas) são:

Tab. 1. Tabela dos operadores relacionais.

Operação | Operador | Exemplo
--- | --- | ---
iguais | == | n1 == 4
diferentes | != | n1 != 4
maior | > | n1 > n2
menor | < | n2 < n1
maior ou igual | >= | n1 >= 3
menor ou igual | <= | n1 <= 33

Os operadores lógicos principais em C e em Python são

Tab. 2. Tabela dos operadores lógicos em C e em Python.

Operação | Operador | Exemplo
--- | --- | ---
| C | Python | C | Python
conjunção (`e`) | && | and | (n1 > 1 && n1 < 10) | (n1 > 1 and n1 < 10)
disjunção (`ou`) | || | or | (n1 > 1) || (n1 < 10) | (n1 > 1) or (n1 < 10)
negação (`não`) | ! | not | !(n1 > 1 || n1 < 10) | not(n1 > 1 or n1 < 10)

Comando de seleção `if-else` em C e em Python

O comando de seleção é essencial para qualquer software, é ele que permite que o programa desvie seu fluxo de execução de acordo com os valores dos dados (as já citadas variáveis). Ele está presente em qualquer linguagem de programação e está baseado no cômputo de uma expressão lógica (EXPLOG), se o resultado dela for verdadeiro, o fluxo segue por um "caminho", senão segue por outro. Essa estrutura está ilustrada na figura abaixo:

Fig. 2. Diagrama de fluxo de execucação do comando de seleção.

Existem outras duas características de comando de seleção (em qualquer linguagem) que são:

1. permitir a execução de comandos mutuamente exclusivo, ou seja, se a expressão lógica resultar verdadeira executa-se determinado comando, senão executa-se outro comando ("comando alternativo") - mas a existência do "senão" é opcional;
2. possível subordinar mais de uma instrução ao comando "se" ou ao comando "senão", mas cada linguagem tem a sua sintaxe particular para isso (marcadores '{' e '}' em C e alinhamento em Python).

Tanto a linguagem C quanto na linguagem Python, usam as masmas palavras reservadas (palavras que não podem ser usados como nomes para variáveis): as palavras `if` e o `else`. A sintaxe de ambas é ilustrada na tabela abaixo.

Além disso, as linguagens C e Python permitem que vários comandos (bloco de comandos) sejam subordinados à uma seleção. Em C deve-se usar abre e fecha chaves (`{...}`) para delimitar os blocos, enquanto que na linguagem Python isso é feito com o deslocamento horizontal de linhas, ou seja, com "indentação".

A tabela a seguir ilustra a sintaxe do comando de seleção tanto em C quanto em Python:

Tab. 3. Comandos de seleção em C e em Python.

Linguagem | Apenas 1 comando | Vários comandos
--- | --- | ---

C

     if (EXPR) comando1;
     else comando2;

     if (EXPR) { comando1;
       comando2; }
     else { comando3;
       comando4; }

Python

     if (EXPR) : comando1;
     else : comando2;

     if (EXPR) :
       comando1;
       comando2;
     else :
       comando3;
       comando4;

Vale destacar que o comando `else` é opcional (como já citado), ou seja, não existindo ação a ser executada caso a condição seja falsa, não é necessário usar um `else` com algum comando. Assim é correto em C escrever `if (1==1) <verm>printf</verm>("ok");` e escrever `if (1==1) : <verm>print</verm>("ok")` em Python.

Em Python os parênteses não são obrigatórios em expressões, quer dizer é válido redigir o comando `if n1==n2 : comando1` (assim como `if (n1==n2) : comando1`). Deste modo para o interpretador Python conseguir traduzir corretamente o comando, lançou-se mão dos dois pontos para indicar final de expressão (`if EXPR :`) e no `else`, e por uniformidade, os `:` também é obrigatório no `else :`.

Outro item em que C e Python diferem é no modo como indicam a existência de um bloco de comandos subordinados a outro comando. Em C utiliza-se abre e fecha chaves, enquanto em Python usa-se a "indentação". Experimente em Python eliminar o deslocamento horizontal e deixe, e.g., o `comando1` alinhado com o `if` e tente rodar o programa. Você receberá uma mensagem de erro.

Comandos de seleção `if-else` aninhados em C e em Python

Em geral, toda linguagem de programação de alto-nível permite que os comandos `if-else` sejam utilizados de modo aninhado, ou seja, qualquer dos `comando1` acima podem ser um novo `if-else`. Por exemplo:

Tab. 4. Comandos de seleção aninhados em C e em Python.

Linguagem | if aninhado
--- | ---

C

    if (a<b) { <cyan>// este exemplo nao trata todos os casos...</cyan>
      if (b<c) <verm>printf</verm>("O menor e': %d\n", a);
      }
    else if (b>=c)
      <verm>printf</verm>("O maior e': %d\n", a);

Python

    if (a<b) : <cyan># este exemplo nao trata todos os casos...</cyan>
      if (b<c) : <verm>print</verm>("O menor e': %d" % a);
    elif (b>=c) : <cyan># usar "elif" para economizar "indentacao"</cyan>
      <verm>print</verm>("O maior e': %d" % a);

Note que a regra para associar um "else" a um "if" é por proximidade (o "else" é associado ao "if" mais próximo), e em caso que precisamos que o "else" seja associado a um "if" mais longe, somos obrigados a usar os blocos de comandos. Isso está ilustrado nos exemplos acima, o primeiro "else" está associado ao `if (a<b)` e não ao mais "próximo".

Um exemplo para decidir se uma variável inteira armazena um valor par ou ímpar

Utilizando a divisão inteira (quer dizer `7/2` resultando `3`) pode-se conseguir determinar se um inteiro é ou não par. Nos códigos abaixo ilustramos este método, mas note que existe uma diferença sensível entre as versões Python 2 e Python 3, este último obriga o uso de "duas barras" (`//`) para indicar divisão inteira. Vejamos os códigos abaixo:

Tab. 5. Exemplo de expressão aritmética em expressão lógica para decidir se valor é par em C e em Python.

C | Python 2 | Python 3
--- | --- | ---

    if (n1/2*2==n1)
      <verm>printf</verm>("%d eh par\n", n1);
    else
      <verm>printf</verm>("%d eh impar\n", n1);

    if (n1/2*2==n1) :
       <verm>print</verm>(n1, " eh par\n")
    else :
       <verm>print</verm>(n1, " eh impar\n")

    if (n1//2*2==n1) :
       <verm>print</verm>(n1, " eh par\n")
    else :
       <verm>print</verm>(n1, " eh impar\n")

Mas pode-se obter o mesmo resultado utilizando o operador binário `%` que é "resto da divisão inteira". Este operador devolve o resto da divisão, por exemplo, `7%2` resulta `1` (o quociente é `3`: `3 * 2 + 1 = 7`). Assim o código fica:

Tab. 6. Exemplos de comandos para decidir se valor é ímpar ou par em C e em Python.

C | Python
--- | ---

    if (n1%2==0)
       <verm>printf</verm>("%d eh par\n", n1);
    else
       <verm>printf</verm>("%d eh impar\n", n1);

    if (n1%2==0) :
       <verm>print</verm>(n1, " eh par\n")
    else :
       <verm>print</verm>(n1, " eh impar\n")

Mas por que razão "n1/2*2==n1" é suficiente para decidir se n1 é ou não par?

Bem, isso é um truque computacional baseado em como o computador interpreta e trata os valores numéricos de acordo com seu tipo. Quanto todos os valores (variáveis) são inteiros, é utilizada uma aritmética de precisão inteira, como examinamos ao final da seção sobre variáveis e expressões.

Lembre-se que em C sempre que fizer divisão entre inteiros o resultado é inteiro (ou seja, `7/2` resulta `3`) e em Python é análogo, entretanto no Python 3 é preciso usar o operador `//` (`7/2` resulta erro, deve-se usar `7//2`) e no Python 2 pode-se usar `7/2` (resultando `3`).

Novamente é o contexto determinando o resultado.

Leônidas de Oliveira Brandão
http://line.ime.usp.br

Alterações:
2020/08/20: revisado formato, pequenas correções;
2020/08/10: novo formato, pequenas correções;
2019/06/06: vários pequenos acertos;
2019/01/13: pequenas melhorias de frases e mudanca no CSS
2018/04/16: pequenos acertos
2018/03/28: melhorado quadro de operadores lógicos C e Python, reescrita a seção "Comandos de seleção ao if-else aninhados em C e em Python"
2017/04/14: adicionados novos itens (como `True/False` e `//` do Python e `%` C e Python)