Username: Password:

.Condições

Operadores

A formulação correcta para as expressões lógicas é «expressões Booleanas». O nome vem do nome do inventor da Algebra de Boole, Georges Boole matemático inglês do século 19.

As expressões lógicas (ou Boolenas) são expressões que podem ter dois valores possíveis: verdadeiro e falso. Por exemplo x > 3 será verdadeiro se x for maior que 3 e falso no caso contrário. A linguagem C tem uma particularidade que é a falta de tipo booleano (muitas linguagens de programação possuem um tipo booleano). Não se pode definir uma variável que conterá apenas valores booleanos. A solução adoptada em C consiste em usar valores inteiros para a representação interna. O valor 0 (zero) corresponde ao valor falso e todos os valores diferentes de zero correspondem ao valor verdadeiro.

Os operadores > (maior), >= (maior ou iqual), < (menor) , <= (menor ou igual), == (igual) != (diferente) são operadores binários cujos argumentos são valores numericos. Esses valores podem ser expressões aritméticas: x > 3 ou y / 10 < z + 4 * a

Os operadores && e || representam o «e» e o «ou». Os seus operandos são expressões booleanas por exemplo x > 10 && x <= 20 é uma expressão que será verdadeira se o valor de x for no intervalo ]10, 20].

Regras de precedência

Existem mais de 45 operadores diferentes na linguagem C (operadores aritméticos, booleanos, operadores para valores binários, para aceder à zonas da memória etc...). Expressões podem combinar vários tipos de operadores (por exemplo aritméticos e booleanos como descrito nesta nesta secção) e regras de precedência são definidas para lidar com tadas as combinações.

Tal como no caso das expressões aritméticas, existem regras de precedência entre esses operadores. Os operadores <, >, <= e >= partilham o mesmo nível de precedência que é maior do que o nível dos operadores == e !=. À seguir está o operador && e finalmente o operador || Por exemplo:
x > y && z <= k será avaliado como se tivesse sido escrito (x > y) && (z <= k).
x > y && z <= k || a != b será avaliado como se tivesse sido escrito ((x > y) && (z <= k)) || (a != b)
Os operadores aritméticos têm precedência sobre os operadores boolenanos. A expressão y / 10 < z + 4 * a será avaliada como se fosse (y / 10) < (z + (4 * a)).

Instrução if

A instrução if é usada para executar instruções condicionalmente. A síntaxe é a seguinte:

<instrução-if> ::= "if" "(" <expressão-booleana> ")" <instrução> ["else" <instrução>]
A <instrução> corresponde a qualquer instrução. Caso seja preciso executar mais de uma instrução a sequência de instruções deve aparecer entre chavetas. A instrução que aparece a direita da expressão booleana é excutada caso a expressão seja verdadeira. Opcionalmente, a seguir a primeira instrução pode aparecer uma instrução alternativa (excutada quando a condição é falsa) precedida da palavra else. Exemplos :
if (a >= 3) 
  printf("O valor de a é maior ou igual a 3.\n");

Agora com o else :

if (a >= 3) 
   printf("O valor de a é maior ou igual à 3.\n");
 else 
   printf("O valor de a é menor que 3.\n");

Nos dois exemplos anteriores, apenas uma instrução é executada após o teste. Caso seja preciso executar mais de uma instrução, é necessário colocar chavetas antes e à seguir :

if (x % 2 == 0) {
   printf("O valor de x é um número par.\n");
   x = x + 1;
else {
   printf("O valor de x é um número impar.\n");
   z = 0;
}

Pode haver uma instrução if encaixada noutra instrução if :

if (x < 10) 
   if (x > 1) 
     printf("x está no intervalo ]1, 10[\n");
   else
     printf("O valor de x é menor ou igual à 1.\n");
Neste caso o else é sempre associado ao if mais próximo (aqui o segundo).

Perigos e Armadilhas

Nomes dos operadores

Tem de lembrar-se que os operadores booleanos «e» e «ou» se escrevem && e || respectivamente. Um erro comum consiste em escrever & e | que correspondem outros operadores em C. Os erros que podem decorrer deste engano são as vezes dificieis de perceber.

Vários operadores lógicos são compostos por dois caracteres (ex: >=, || etc...). É um erro comum inserir um espaço entre os dois caracteres.

Indentação da instrução if

A instrução if é uma boa ilustração da necessidade de apresentar (indentar) correctamente o programa. Considere o seguinte pedaço de código :

if (x < 10) 
   if (x > 1) 
     printf("x está no intervalo ]1, 10[\n");
else
  printf("O valor de x é maior ou igual à 10.\n");
O programa não funcionará como esperado. Não é a indentação da do else que determina o if a qual «pertence». O else é sempre associado à última condição encontrada.

Comparação de valores reais

É necessário ter cuidado quando quer compara valores de tipo float ou double. Vejamos este programa :

1 #include <stdio.h>
2 #include <math.h>
3
4 int main (void) {
5   double y = 3.0;
6   float k1 = 1/y;
7   double k2 = 1/y;
8
9   if (k1 == k2) {
10     printf("k1 e k2 são iguais.\n");
11   }
12   if (k1 == 1.0/3.0) {
13     printf("k1 é igual à 1/3\n");
14   } 
15   if (k2 == 1.0/3.0) {
16     printf("k2 é igual à 1/3\n");
17   }
18   y = M_PI; /* M_PI é uma constante predefinida que cujo valor é PI. */
19   if (cos(y/2) == 0.0) {
20     printf("O resultado é correcto !\n");
21   } else {
22     printf("O que é isto ? cos(pi/2) = %e\n", cos(y/2));
23   }
24   y = sqrt(2.0);
25   if (y * y == 2) {
26     printf("O resultado é correcto !\n");
27   } else {
28     printf("O que é isto ? sqrt(2)^2 = %e diferença: %e\n", y * y, 2.0 - y * y);
29   }
30 }
31
Uma vez compilado, quando executamos este programa obtemos:
> ./testif1
k2 é igual à 1/3
O que é isto ? cos(pi/2) = 6.123032e-17
O que é isto ? sqrt(2)^2 = 2.000000e+00 diferença: -2.734358e-16

Os resultados estão surpreendentes e um pouco desanimadores. O que é que aconteceu ? k1 é de tipo float logo o valor contido na variável está limitado à precisão do tipo. O valor de k1 é portanto 1/3 com a precisão dos float que é um valor diferente de 1/3 com a precisão do tipo double. São dois valores diferentes o resultado do teste k2 == k2 é portanto falso. Os números literais com virgula (ex 3.0) são interpretados automáticamente como sendo de tipo double. Iso explica porque o teste k1 == 1.0/3.0 é falso, temos aqui também dois valores diferentes. Pelas mesmas razões o teste k2 == 1.0/3.0 é verdadeiro.

Essas subtilezas não acontecem apenas quando se misturam valores de tipo float e double, acontecem porque a precisão da representação (quer dos float quer dos double) é limitada. No teste da linha 19 compara-se o valor de cos(pi/2) e zero (que deveriam ser iguais) mais mais uma vez o resultado não é o esperado porque o valor de cos(pi/2) é uma aproximação de zero: 6.123032e-17.

O teste da linha 25 é mais uma ilustração. A função sqrt calcula a raíz quadrada mas como a precisão do resultado é limitada, sqrt(2)^2 é diferente de 2.

Como devemos resolver este problema ? Não se deve usar a igualidade == (ou desigualidade !=) para comapar valores float ou double. Temos que tomar em conta a precisão esperada (que depende do problema à resolver). Em vez de escrever :

if (valor == valorEsperado) { ...
vamos escrever :
if (fabs(valor - valorEsperado) < 0.00001) { ...
(assumindo que 1.0e-5 é uma precisão suficiente para o nosso problema). A função fabs(x) retorna o valor absoluto de x.

Para saber mais

Em certas situações a tarefa que o programa deve efectuar corresponde a uma sequência de instruções if para executar processamentos diferentes em cada uma de uma série de condições. Na secção «Condições (nível 2)» encontrará esclarecimentos sobre este assunto e uma descrição da instrução switch.