Professor: Gabriel Soares Baptista
Nesta aula, exploraremos as diversas operações que podem ser realizadas com variáveis na linguagem C.
Uma das operações mais fundamentais na programação é a atribuição. Sua função é armazenar um determinado valor em uma variável.
nome_da_variável = expressão;
O fluxo de dados da atribuição ocorre sempre da direita para a esquerda. O computador calcula a expressão à direita do "=" e armazena o resultado na variável à esquerda.
O computador avalia primeiro o que está à direita do sinal de "=" e atribui o resultado à variável da esquerda. Tentar realizar o inverso resultará em erro de compilação.
// Correto: recebe o resultado da soma
x = y + 5;
// Correto: recebe o valor constante
x = 5;
// ERRADO: não se atribui a uma expressão
y + 5 = x;
// ERRADO: não se atribui a uma constante
5 = x;
A linguagem C suporta múltiplas atribuições em uma única linha, onde o valor é copiado em cadeia (da direita para a esquerda):
x = y = z = 5;
A linguagem permite a atribuição entre tipos básicos distintos, realizando conversão automática.
Ao atribuir um número real (float) a uma variável inteira (int), apenas a parte inteira será preservada, descartando-se toda a precisão decimal (truncamento).
Os operadores atuam sobre valores numéricos, resultando sempre em um novo valor numérico.
| Operador | Significado | Exemplo |
|---|---|---|
| + | Adição de dois valores | z = x + y |
| - | Subtração de dois valores | z = x - y |
| * | Multiplicação de dois valores | z = x * y |
| / | Quociente (divisão) de dois valores | z = x / y |
| % | Resto de uma divisão inteira | z = x % y |
As operações de multiplicação (*), divisão (/) e resto (%) são executadas sempre antes da adição (+) e da subtração (-).
z = x * y + 10; (Multiplica, depois soma)z = x * (y + 10); (Soma, depois multiplica)Os sinais de + e - podem atuar sobre um único valor para inversão de sinal (ex: x = -y;).
5 / 4.0).O operador de resto da divisão (%) é exclusivo para tipos de dados inteiros, como int e char. Tentar utilizá-lo com números reais (float ou double) causará um erro.
Utilizados para verificar a relação de magnitude e a igualdade entre valores. Eles retornam um valor lógico (booleano): UM (1) para verdadeiro ou ZERO (0) para falso.
| Operador | Significado | Exemplo |
|---|---|---|
| > | Maior do que | x > 5 |
| >= | Maior ou igual a | x >= 10 |
| < | Menor do que | x < 5 |
| <= | Menor ou igual a | x <= 10 |
| == | Igual a | x == 0 |
| != | Diferente de | x != 0 |
Não existem os operadores "=<", "=>" ou "<>". Os símbolos devem seguir a ordem estrita: <= e >=. Utiliza-se obrigatoriamente != para representar "diferente de".
Não confunda o operador de atribuição = com o operador de teste de igualdade ==.
// Errado para testar igualdade: atribui o valor 4 a x
if(x = 4)
// Correto: testa se x é igual a 4
if(x == 4)
Permitem combinar múltiplas expressões relacionais em uma única estrutura (ex: $0 < x < 10$). Retornam 1 (verdadeiro) ou 0 (falso).
| Operador | Significado | Comportamento |
|---|---|---|
| && | Operador E (AND) | Verdadeiro apenas se todas as condições forem verdadeiras. |
| || | Operador OU (OR) | Verdadeiro caso qualquer uma das condições for verdadeira. |
| ! | Operador NEGAÇÃO (NOT) | Inverte o estado lógico (verdadeiro vira falso, falso vira verdadeiro). |
Resumo das combinações possíveis para os operadores lógicos, onde a e b representam os resultados de expressões relacionais (0 para falso, 1 para verdadeiro).
a | b | !a | !b | a && b | a || b |
|---|---|---|---|---|---|
| 0 | 0 | 1 | 1 | 0 | 0 |
| 0 | 1 | 1 | 0 | 0 | 1 |
| 1 | 0 | 0 | 1 | 0 | 1 |
| 1 | 1 | 0 | 0 | 1 | 1 |
1. O operador de atribuição (=) é fundamental na linguagem C. Analise o trecho de código abaixo e identifique qual das instruções gera um erro de compilação, justificando sua resposta com base na "Regra de Direção" apresentada no texto.
int main() {
int a = 10;
int b = 20;
int c;
c = a + b; // Instrução I
a = 5; // Instrução II
a + b = c; // Instrução III
c = 15; // Instrução IV
return 0;
}
2. A divisão em C pode se comportar de maneira diferente dependendo dos tipos de dados envolvidos. Considere o código a seguir:
#include <stdio.h>
int main() {
float x, y;
x = 7 / 2;
y = (float) 7 / 2;
printf("x = %f\n", x);
printf("y = %f\n", y);
return 0;
}
Sem executar o código, determine qual será a saída exata impressa para x e y. Explique por que o valor de x pode não ser o esperado (3.5), mencionando o conceito de divisão inteira e perda de precisão.
3. Analise a expressão abaixo considerando a tabela de precedência de operadores: int x = 10 + 5 * 2 < 25 && 4 != 5;
Qual será o valor final armazenado em x (0 ou 1)? Descreva o passo a passo da resolução que o computador faria (ex: qual conta é feita primeiro, qual comparação vem depois, etc.).
O computador representa números em formato binário (0s e 1s). Esses operadores manipulam cada um desses bits individualmente, essenciais para programação em baixo nível.
Estes operadores só podem ser aplicados aos tipos char, int e long. Não funcionam com tipos de ponto flutuante (float e double).
| Operador | Significado | Exemplo |
|---|---|---|
| ~ | Complemento (inversão) | ~x |
| & | E (AND) bit a bit | x & 167 |
| | | OU (OR) bit a bit | x | 167 |
| ^ | OU Exclusivo (XOR) | x ^ 167 |
| << | Deslocamento à esquerda | x << 2 |
| >> | Deslocamento à direita | x >> 2 |
Demonstração E (&):
00101100 (44)10100111 (167)00100100 (Resultado: 36)Demonstração XOR (^):
00101100 (44)10100111 (167)10001011 (Resultado: 139)Movem o conjunto de bits para a esquerda ou direita por N posições.
Exemplo (x = 44 ou 00101100):
10110000 (176)00001011 (11)Tornam o código mais conciso ao combinar uma operação com a atribuição do resultado à mesma variável.
| Operador | Significado | Exemplo | Equivalente a |
|---|---|---|---|
| += | Soma e atribui | x += y | x = x + y |
| -= | Subtrai e atribui | x -= y | x = x - y |
| *= | Multiplica e atribui | x *= y | x = x * y |
| /= | Divide e atribui quociente | x /= y | x = x / y |
| %= | Divide e atribui resto | x %= y | x = x % y |
(Também aplicáveis aos operadores bitwise: &=, |=, ^=, <<=, >>=)
Ao usar atribuição simplificada, o compilador avalia toda a expressão à direita do operador antes de realizar a operação combinada (como se estivesse entre parênteses).
Escrita Convencional:
int x = 10, y = 20;
// x = 10 - 5 + 20 = 25
x = x - 5 + y;
Atribuição Simplificada:
int x = 10, y = 20;
// x = 10 - (5 + 20) = -15
x -= 5 + y;
Somam ou subtraem exatamente uma unidade de uma variável.
Pense no posicionamento do operador como uma fila de prioridade: se o sinal vier antes da variável, a conta é feita primeiro; se vier depois, a conta fica para o final.
Permitem a conversão explícita de dados, forçando o resultado de uma expressão a assumir o tipo especificado.
(nome_do_tipo) expressão;
float x, y, f = 65.5;
// x = 6.550000
x = f / 10.0;
// y = 6.000000 (descarta decimais)
y = (int) (f / 10.0);
Garante que operações entre tipos diferentes resultem no comportamento esperado, evitando ambiguidades e controlando a perda de precisão conscientemente.
Papéis do operador vírgula:
int a, b;).x = (y = 2, y + 3); (x recebe 5).A linguagem adota uma hierarquia estrita para decidir a ordem de execução.
(), Array [], Estruturas ->, Incrementos Pós/Pré.* / % depois + -, Relacionais, Lógicos.=, +=, etc., e por último a vírgula ,.As operações que vimos geram valores que orientam o fluxo do programa. Uma condição é qualquer expressão (matemática, relacional, lógica) que resulte em verdadeiro ou falso.
Lógica Binária do Compilador:
Equivalências Práticas:
(num != 0) equivale a (num) -> Verdadeiro se não for nulo.(num == 0) equivale a (!num) -> Falso se for zero.Utilizado para escolher caminhos ou executar instruções baseadas em um teste lógico. Se a condição for verdadeira, o bloco é executado. Se falsa, é ignorado.
if(num > 10) {
printf("O numero e maior do que 10\n");
}
Nunca utilize o ponto e vírgula (;) logo após a condição if(condicao);. Isso encerra o comando prematuramente.
Atua como complemento direto do if. Só será processado se a condição do if for FALSA. Representa o "caso contrário" exato.
if(num == 10){
printf("O numero e igual a 10.\n");
} else {
printf("O numero e diferente de 10.\n");
}
else não recebe (e não aceita) uma condição própria.if e else são independentes; apenas um é executado por vez.1. Sobre os operadores de pré-incremento (++x) e pós-incremento (x++), analise a saída do seguinte programa e explique o comportamento da variável res em cada caso:
int main() {
int x = 5, res;
// Caso 1
res = x++;
// Qual o valor de 'res' e 'x' aqui?
x = 5; // Resetando x
// Caso 2
res = ++x;
// Qual o valor de 'res' e 'x' aqui?
return 0;
}
2. Realize manualmente as operações bitwise (bit a bit) abaixo, considerando A = 12 (Binário: 00001100) e B = 10 (Binário: 00001010). Apresente o resultado em decimal.
A & B (AND)A | B (OR)A ^ B (XOR)A >> 2 (Deslocamento à direita)3. Escreva um programa completo em C que solicite ao usuário dois números inteiros. O programa deve:
4. Utilize os operadores de atribuição simplificada para reescrever e programar a seguinte lógica de forma mais concisa. Considere que a variável total inicia com o valor 100.
total.total por 2.total por 5.5. Escreva um programa que leia um número inteiro fornecido pelo usuário. O programa deve verificar se o número é par ou ímpar e imprimir uma mensagem correspondente.
Um if aninhado é a utilização de um comando if dentro do bloco de outro if (ou else). Permite lidar com múltiplos caminhos e refinar decisões.
if(num == 10){
printf("Igual a 10.\n");
} else {
if(num > 10)
printf("Maior que 10.\n");
else
printf("Menor que 10.\n");
}
Um else sempre se associa ao if mais próximo anterior a ele dentro do mesmo escopo. Use chaves {} para forçar associações específicas.
Simplificação prática da estrutura if-else em uma única linha. Ideal para atribuições condicionais compactas.
expressão condicional ? expressão1 : expressão2;
Estrutura Tradicional (IF/ELSE):
if (x > y) {
z = x;
} else {
z = y;
}
Operador Ternário:
z = (x > y) ? x : y;
Comando de seleção múltipla. Verifica se uma variável (int ou char) é igual a valores constantes preestabelecidos, sendo mais elegante que múltiplos ifs aninhados.
switch (variável) {
case valor1:
// comandos;
break;
case valor2:
// comandos;
break;
default:
// comandos de escape;
}
x > 10), apenas igualdade exata de valores constantes.O break interrompe a execução e sai do bloco switch. Se for omitido, ocorre o "efeito cascata": o programa continuará executando todos os comandos dos cases seguintes, ignorando seus valores.
// Se op = 1, imprimirá "ABC"
switch(op) {
case 1: printf("A");
case 2: printf("B");
case 3: printf("C");
}
A ausência do break pode ser uma falha lógica grave ou uma técnica intencional (para estados que compartilham a mesma saída).
1. Crie um programa que verifique se um número é "Válido". Um número é válido se ele atender a todas as seguintes regras simultaneamente (utilize operadores lógicos e relacionais):
O programa deve imprimir 1 se o número for válido e 0 caso contrário.
2. O comando switch é uma alternativa elegante ao uso de múltiplos if-else encadeados, mas possui limitações. Assinale a alternativa que descreve corretamente uma restrição do switch em C:
case (x > 10 && x < 20):.float ou double como parâmetro de controle.{ } em cada case, mesmo que não haja declaração de variáveis.int ou char.3. O operador ternário é uma ferramenta poderosa para simplificação de código. Reescreva o trecho de código abaixo utilizando uma única linha com o operador ternário:
// Código Original
if (nota >= 60) {
printf("Aprovado");
} else {
printf("Reprovado");
}
4. Crie um programa que receba três números inteiros como entrada e imprima o maior deles. Utilize estruturas if-else aninhadas para realizar as comparações.
5. Desenvolva uma calculadora básica utilizando o comando switch. O programa deve ler dois números reais e um operador aritmético (+, -, *, /).
6. Escreva um programa que leia um ano (ex: 2024) e determine se ele é bissexto ou não. As regras para um ano ser bissexto são:
7. Analise o comportamento do break no comando switch. Dado o código abaixo, qual será a saída exata se o usuário digitar o valor 2? Explique por que a saída ocorre dessa forma.
int main() {
int op;
scanf("%d", &op);
switch(op) {
case 1: printf("A");
case 2: printf("B");
case 3: printf("C");
default: printf("D");
}
return 0;
}
if, else, switch, ternário).while, do-while e for.