Expressões
Slides
O que são?
Expressões devolvem sempre um valor concreto com um determinado tipo.
Operações aritméticas
1+2 // soma
3.14-2 // subtração
1*2.3 // multiplicação
5/2 // divisão, devolve 2 -> porquê?
5%2 // resto da divisão
int v = 2;
-v // torna valor negativo, operação unáriaOperação unária ➡ Operação que recebe apenas 1 operando, e.g. -v
Por outro lado, as outras operações são binárias ➡ 2 operandos, e.g. 1+2
O resto da divisão % requer 2 operandos inteiros.
Usar 0 como o segundo operando da divisão / ou resto da divisão %, i.e. divisão por 0, gera comportamento não definido.
Precedência e associatividade
Qual o valor desta expressão?
1+2*-2Evitem escrever expressões deste tipo. Usem
( )para melhorar legibilidade.Melhor?
1 + (2 * -2)
As operações no C têm uma precedência.
| Precedência | Nome | Operadores | Associatividade |
|---|---|---|---|
| 1 | incremento (sufixo) | ++ -- |
esquerda |
| 2 | incremento (prefixo) additivos unários |
++ --+ - |
direita |
| 3 | multiplicativos | * / % |
esquerda |
| 4 | aditivos binários | + - |
esquerda |
| 5 | desigualdades | < <= > >= |
esquerda |
| 6 | igualdades | == != |
esquerda |
| 7 | atribuição | = *= /= %= += -= |
direita |
Exemplos:
1 + 2 * -2➡1 + (2 * (-2))i + j * k➡i + (j * k)-i * -j➡(-i) * (-j)
E quando uma expressão tem 2 operações com a mesma precedência?
i - j + k
i / j * k Tem-se em conta a associatividade.
i / j * k == (i / j) * k
+ - * / % têm associtividade à esquerda, logo agrupam o que está antes do operador.
Os operadores unários têm associatividade à direita.
- -2 == - (-2)
Operadores de atribuição
Já conhecemos o operador de atribuição simples =.
É o que designamos por uma operação com efeitos secundários, porque altera o estado dos operandos.
a = 2 altera o estado da variável a porque o seu valor é agora 2.
Adicionalmente, a = 2 é uma expressão válida que devolve o valor que foi atribuido à variável
Todas as operações de atribuição exigem que o operando da esquerda seja uma variável.
Existem outros que se combinam com operações aritméticas.
| Expressão | Descrição |
|---|---|
var+=3 |
soma 3 ao valor de var e atribui o resultado a var |
var-=3 |
subtrai 3 ao valor de var e atribui o resultado a var |
var*=3 |
multiplica 3 com o valor de var e atribui o resultado a var |
var/=3 |
divide o valor de var por 3 e atribui o resultado a var |
var%=3 |
faz o resto da divisão entre var e 3 e atribui o resultado a var |
v*=3não é equivalente av = v * 3, embora na maior parte das utilizações o resultado seja o mesmo. Porquê?Observem a expressão
v *= 3 + 10. É equivalente av = v * 3 + 10?Devido às regras de precedência e associatividade leva a um resultado diferente.
Não confundir += com =+.
A primeira operação acumula o valor à direita.
A segunda é uma simples atribuição seguida do operador + unário.
Em suma…
… usem sempre ( ) para deixar claro qual é a ordem das operações.
Incremento e decremento
Existe uma instrução que é frequentemente usada no C (irão perceber porquê quando abordarmos ciclos):
Existe outra forma de escrever esta instrução, com o operador de incremento ++
Este operador pode ser usado tanto antes de uma variável (pré-incremento) como depois (pós-incremento).
Qual será a diferença?
int i=10;
printf("%d\n", ++i); // ?
printf("%d\n", i); // ?
i=10;
printf("%d\n", i++); // ?
printf("%d\n", i); // ?int i=10;
printf("%d\n", ++i); // 11
printf("%d\n", i); // 11
i=10;
printf("%d\n", i++); // 10
printf("%d\n", i); // 11Além do incremento ++, também temos disponível o decremento --, que funciona da mesma forma, mas subtrai em uma unidade.
Avaliação de expressões
Com este conhecimento conseguimos avaliar expressões complicadas.
a= b += c++ - d + --e / -f
- Encontrar o operador com maior precedência.
- Colocar ( ) à volta do operador e operandos.
- Aplicar regras de precedência e associatividade.
- Repetir.
a= b += c++ - d + --e / -f
a= b += (c++) - d + (--e) / -fc++e depois--e(precedência)a= b += (c++) - d + (--e) / (-f)operador unário-f(precedência)a= b += (c++) - d + ((--e) / (-f))divisão (precedência)
a= b += (c++) - d + ((--e) / (-f))a= b += ((c++) - d) + ((--e) / (-f))-e+com a mesma precedência e com operando em comumd(precedência), agrupam da esquerda para a direita, logo-primeiro (associatividade)a= b += (((c++) - d) + ((--e) / (-f)))+(precedência)a= (b += (((c++) - d) + ((--e) / (-f))))=e+=com mesma precedência (precedência), agrupam da direita para a esquerda, logo+=primeiro (associatividade)(a= (b += (((c++) - d) + ((--e) / (-f)))))sobra apenas o=(precedência)
Moral da história: façam um favor a vós próprios…
. . .
… e usem ( ).