Operadores em C
LidoEsta aula aborda os operadores em C, incluindo aritméticos, relacionais, lógicos, atribuição composta e precedência, com exemplos práticos e exercícios para fixação.
Os operadores são fundamentais na linguagem C, pois permitem realizar operações sobre dados, desde cálculos matemáticos até comparações e decisões lógicas. Nesta aula, exploraremos os principais operadores disponíveis em C, entendendo sua sintaxe, comportamento e particularidades. Você aprenderá a utilizá-los em expressões e a compreender a ordem de avaliação, essencial para escrever código correto e eficiente.
Dominar os operadores é um passo crucial para qualquer programador, pois eles estão presentes em praticamente todos os programas. Ao final desta aula, você terá uma base sólida para construir expressões complexas e evitar erros comuns relacionados à precedência e à avaliação de curto-circuito.
Aritméticos
Os operadores aritméticos em C realizam operações matemáticas básicas: adição (+), subtração (-), multiplicação (*), divisão (/) e módulo (%). Eles podem ser aplicados a tipos inteiros e de ponto flutuante, mas com algumas nuances importantes.
A divisão entre inteiros resulta em um inteiro, truncando a parte fracionária. Por exemplo, 7 / 2 resulta em 3, não 3.5. Para obter um resultado fracionário, pelo menos um dos operandos deve ser do tipo float ou double. O operador de módulo (%) retorna o resto da divisão inteira e só pode ser usado com inteiros.
#include <stdio.h>
int main() {
int a = 10, b = 3;
float c = 10.0, d = 3.0;
printf("a + b = %d\n", a + b); // 13
printf("a - b = %d\n", a - b); // 7
printf("a * b = %d\n", a * b); // 30
printf("a / b = %d\n", a / b); // 3 (divisão inteira)
printf("a %% b = %d\n", a % b); // 1 (resto)
printf("c / d = %.2f\n", c / d); // 3.33 (ponto flutuante)
return 0;
}
Além dos operadores binários, C também possui operadores unários: + (sinal positivo) e - (sinal negativo). O operador de incremento (++) e decremento (--) são especiais e podem ser usados na forma prefixada ou pós-fixada, alterando a ordem de avaliação.
Relacionais e lógicos
Os operadores relacionais comparam dois valores e retornam 1 (verdadeiro) ou 0 (falso). São eles: >, <, >=, <=, == (igualdade) e != (desigualdade). Eles são frequentemente usados em estruturas de decisão, como if e while.
Os operadores lógicos permitem combinar expressões relacionais: && (E lógico), || (OU lógico) e ! (NÃO lógico). Eles seguem as regras da lógica booleana e apresentam um comportamento importante chamado curto-circuito: no caso de &&, se a primeira condição for falsa, a segunda não é avaliada; em ||, se a primeira for verdadeira, a segunda é ignorada.
#include <stdio.h>
int main() {
int idade = 20;
int renda = 1500;
if (idade >= 18 && renda > 1000) {
printf("Apto para o crédito\n");
}
if (idade < 18 || renda < 500) {
printf("Não apto\n");
}
if (!(idade > 21)) {
printf("Jovem\n");
}
return 0;
}
É importante lembrar que em C, qualquer valor diferente de zero é considerado verdadeiro, e zero é falso. Isso permite expressões como if (x) para verificar se uma variável é diferente de zero.
Atribuição composta
Os operadores de atribuição composta combinam uma operação aritmética ou bit a bit com a atribuição, tornando o código mais conciso. Por exemplo, a += 5 é equivalente a a = a + 5. Os operadores incluem +=, -=, *=, /=, %=, e também os bit a bit &=, |=, ^=, etc.
Esses operadores não apenas reduzem a digitação, mas também podem melhorar a legibilidade quando a variável é longa. Além disso, em alguns casos, a avaliação é feita de forma mais eficiente, pois o operando esquerdo é avaliado apenas uma vez.
#include <stdio.h>
int main() {
int x = 10;
x += 5; // x = x + 5; agora x = 15
x -= 3; // x = x - 3; agora x = 12
x *= 2; // x = x * 2; agora x = 24
x /= 4; // x = x / 4; agora x = 6
x %= 4; // x = x % 4; agora x = 2
printf("x = %d\n", x); // 2
return 0;
}
A atribuição composta é muito útil em loops e acumuladores, como no cálculo de somatórias.
Precedência
A precedência de operadores define a ordem em que as operações são avaliadas em uma expressão. Em C, os operadores têm níveis de precedência bem definidos, e os parênteses podem ser usados para alterar essa ordem. Por exemplo, na expressão a + b * c, a multiplicação é realizada antes da adição, pois * tem precedência maior que +.
A associatividade determina a ordem de avaliação quando operadores de mesma precedência aparecem em sequência. A maioria dos operadores binários é associativa à esquerda, mas os de atribuição são associativos à direita. Conhecer a precedência evita erros sutis, como em if (x & 1 == 0), onde a comparação == tem precedência maior que o bit a bit &, resultando em x & (1 == 0), que é provavelmente indesejado. O correto seria if ((x & 1) == 0).
#include <stdio.h>
int main() {
int a = 5, b = 3, c = 2;
int resultado = a + b * c; // 5 + (3*2) = 11
int comParenteses = (a + b) * c; // (5+3)*2 = 16
printf("resultado = %d\n", resultado);
printf("comParenteses = %d\n", comParenteses);
return 0;
}
Uma tabela de precedência simplificada (da maior para a menor):
- Pós-fixados:
() [] -> . ++ -- - Unários:
+ - ! ~ ++ -- (tipo) - Multiplicativos:
* / % - Aditivos:
+ - - Relacionais:
< <= > >= - Igualdade:
== != - E lógico:
&& - OU lógico:
|| - Condicional:
?: - Atribuição:
= += -= *= /= %= ... - Vírgula:
,
Boas práticas e observações
Para evitar erros, é recomendável usar parênteses em expressões complexas, mesmo que a precedência já defina a ordem, pois isso melhora a legibilidade. Além disso, cuidado com o operador de igualdade (==) em comparações com atribuição (=), um erro comum é escrever if (x = 5) em vez de if (x == 5). Sempre compile com warnings habilitados (-Wall) para detectar possíveis ambiguidades.
Outra dica é evitar misturar tipos inteiros e de ponto flutuante em operações aritméticas sem conversão explícita, pois podem ocorrer perdas de precisão. Entender o comportamento de curto-circuito também é útil para otimizar condições e evitar operações desnecessárias.
Exercícios
- Escreva um programa que leia dois números inteiros e imprima a soma, subtração, multiplicação, divisão inteira e o resto da divisão.
- Dado um ano, determine se é bissexto. Um ano é bissexto se for divisível por 4, exceto se for divisível por 100, a menos que seja divisível por 400. Use operadores relacionais e lógicos.
- Implemente um programa que calcule a média de três notas e determine se o aluno está aprovado (média >= 7) ou reprovado, usando operador ternário.
- Escreva um código que use atribuições compostas para calcular o fatorial de um número, mas de forma acumulada (sem usar laço). Dica: use múltiplas atribuições compostas em uma expressão?
- Analise a expressão
int x = 5; int y = 3; int z = x++ - --y * 2;e determine o valor final de x, y e z, explicando a ordem de avaliação.
#include <stdio.h>
int main() {
int a, b;
printf("Digite dois inteiros: ");
scanf("%d %d", &a, &b);
printf("Soma: %d\n", a + b);
printf("Subtração: %d\n", a - b);
printf("Multiplicação: %d\n", a * b);
if (b != 0) {
printf("Divisão inteira: %d\n", a / b);
printf("Resto: %d\n", a % b);
} else {
printf("Divisão por zero não permitida.\n");
}
return 0;
}
#include <stdio.h>
int main() {
int ano;
printf("Digite um ano: ");
scanf("%d", &ano);
if ((ano % 4 == 0 && ano % 100 != 0) || (ano % 400 == 0))
printf("%d é bissexto\n", ano);
else
printf("%d não é bissexto\n", ano);
return 0;
}
#include <stdio.h>
int main() {
float nota1, nota2, nota3, media;
printf("Digite três notas: ");
scanf("%f %f %f", ¬a1, ¬a2, ¬a3);
media = (nota1 + nota2 + nota3) / 3;
printf("Média: %.2f - %s\n", media, media >= 7 ? "Aprovado" : "Reprovado");
return 0;
}
#include <stdio.h>
int main() {
int n, i;
long fat = 1;
printf("Digite um número: ");
scanf("%d", &n);
for (i = 2; i <= n; i++) {
fat *= i;
}
printf("Fatorial = %ld\n", fat);
return 0;
}