Subsecções

15 Operadores e Expressões Especiais

15.1 Operadores de Incremento e Decremento

Há alguns operadores em C++ que são equivalentes as seguintes expressões (que são bastante comuns em programas):

   k = k + 1;

   j = j - 1;

Estes operadores adicionais, que são ++ e - -, podem ser usados para encurtar as operações acima:

   k++;

   j--;

Estes operadores também podem ser colocados depois do nome da variável:

   ++k;

   --j;

O fato do operador de incremento ser colocado antes ou depois da variável não altera o efeito da operação - o valor da variável é incrementada ou decrementada de um. A diferença entre os dois casos é QUANDO a variável é incrementada. Na expressão k++, o valor de k é primeiro usado e então é incrementada - isto é chamado pós-incremento. Na expressão ++k, k é incrementado primeiro, e então o valor (o novo valor) de k é usado - isso é chamado pré-incremento.

A diferença é ilustrada nos seguintes exemplos:

   int main()
   {
      int k = 5;

      cout << "k1 = " << k << endl;
      cout << "k2 = " << k++ << endl;
      cout << "k3 = " << k << endl;
   }

O programa acima (que usa pós-incremento) imprimirá o seguinte:

k1 = 5

k2 = 5

k3 = 6

A segunda linha impressa com o valor de k é 5 porque o valor de k++ era 5, e k é 6 depois da impressão.

Para o programa:

   int main()
   {
      int k = 5;

      cout << "k1 = " << k << endl;
      cout << "k2 = " << ++k << endl;
      cout << "k3 = " << k << endl;
   }

O programa, que usa pré-incremento, terá a seguinte saída:

k1 = 5

k2 = 6

k3 = 6

A segunda linha impressa é 6 porque o valor de ++k é 6.

Os operadores de atribuição não podem ser usados com expressões aritméticas. Por exemplo, as expressões

    (ack + 2)++;

    (nope + 3) += 5;

resultarão em erros de compilação.

Finalmente, quando usar o operador de incremento em um cout, tome cuidado para não fazer o seguinte:

    cout << ++uhoh << uhoh * 2 << endl;

Embora isso seja perfeitamente legal em C++ , os resultados não são garantidados que sejam consistentes. A razão para isso é que não há garantia que os argumentos do cout sejam avaliados em uma determinada ordem. O resultado do cout será diferente dependendo se ++uhoh é avaliado primeiro ou depois de uhoh * 2.

A solução para este problema é escrever o seguinte:

    ++uhoh;
    cout << uhoh << uhoh * 2 << endl;

15.2 Expressões como Valor com Operadores de incremento e decremento

Já que incremento e decremento são formas de atribuição, o operando deve ser um lvalue. O valor de uma expressão de incremento ou decremento depende se o operador é usado na notação PRé ou PóS fixada (x++, ++x, x--, --x). Se for pré-fixada, o valor da expressão é o novo valor após o incremento ou decremento. Se for pós-fixada, o valor da expressão é o valor antigo (antes do incremento ou decremento). Por exemplo no caso de incremento, a expressão:

x++ tem o valor de x

++x tem o valor de x + 1

Note que não importando a notação usada, o valor de x (o conteúdo do endereço de memória associada a x) será x + 1. A diferença está no valor das expressões x++ e ++x, não no valor de x (em ambos os casos o valor de x será incrementada de um).

15.3 Ambiguidade em certas expressões

Às vezes, problemas podem acontecer devido o fato que C++ não especifica a ordem de avaliação dos operadores em uma operação binária. Em outras palavras, em expressões como a + b ou a < b, não há maneira de saber se o valor de a será avaliado antes ou depois de b (pense em a e b como sendo qualquer expressão, não somente variáveis.) Qual deles será avaliado primeiro é particular de cada compilador, e diferentes compiladores em máquinas diferentes podem ter resultados diferentes. Portanto, se a avaliação de um dos operadores pode alterar o valor do outro, o resultado pode ser diferente dependendo da ordem de avaliação. Portanto, em expressões do tipo x + x++, o valor pode diferir dependendo do compilador utilizado. Isto porque não sabemos quando exatamente o incremento de x ocorre. Outros maus exemplos: y = x + x-- e x = x++. De forma geral, para evitar este problema, não utilize senteças como estas.

15.3.1 Valor de expressões envolvendo atribuição aritmética

Como podemos ver, os operadores de incremento/decremento, e os operadores de atribuição aritmética vistos até aqui funcionam de forma similar ao comando de atribuição. O lado esquerdo da expressão de atribuição aritmética e o operando de incremento/decremento devem ser um lvalue. O valor da expressão da é igual ao valor da sentença de atribuição correspondente. Por exemplo:

x += 3 é igual a x = x + 3 e tem valor x + 3

x *= y + 1 é igual a x = x * (y + 1) e tem valor x * (y + 1)

y = i++ é igual a y = i, i = i + 1; e tem valor i

y = ++i é igual a i = i + 1, y = i; e tem valor i + 1

15.4 Exercício de fixação

O que é impresso pelos dois programas abaixo?

  #include <iostream>
  using namespace std;

  int main() {
    int n1, n2, n3;

    cout << "Entre com um numero inteiro: ";
    cin >> n1;
    n1 += n1 * 10;
    n2 = n1 / 5;
    n3 = n2 % 5 * 7;
    n2 *= n3-- % 4;
    cout << n2 << " " << n3 << " " << (n2 != n3 + 21) << endl;
  }

15.5 Precedência de Operadores

A tabela de precedência abaixo mostra a posição dos operadores vistos aqui, incluindo a atribuição aritmética e decremento/incremento.

Operador Associatividade
   
() [] -> . esquerda para direita
! - ++ -- * \& direita para esquerda
* / % esquerda para direita
+ - esquerda para direita
< <= > >= esquerda para direita
== != esquerda para direita
&& esquerda para direita
|| esquerda para direita
= += -= *= /= %= direita para esquerda
, esquerda para direita


Créditos: Documento produzido pelo Prof. Armando L.N. Delgado (DINF/ET/UFPR), baseado em revisão sobre material de Prof. Carmem Hara e Prof. Wagner Zola (DINF/ET/UFPR).

Esta obra está licenciada com uma Licença Creative Commons Atribuição-NãoComercial-CompartilhaIgual 4.0 Internacional.  Licença Creative Commons

Armando Luiz Nicolini Delgado
2020-10-20