Operadores binários para comparações entre expressões numéricas:
menor que | < |
maior que | > |
menor ou igual | <= |
maior ou igual | >= |
igual | == |
diferente | != |
O resultado é inteiro: 0 se a condição for falsa, 1 se a condição for verdadeira
int i, j;
= 2;
i = 4;
j ("%d\n", i > j); // imprime 0
printf("%d\n", i < j); // imprime 1
printf("%d\n", i*i == j); // imprime 1
printf("%d\n", i*j >= 10); // imprime 0 printf
i + j < k - 1
equivale a
(i+j)<(k-1)
A expressão
< j < k i
é válida mas não testa se j
está entre
i
e k
:
<
associa à esquerda, logo a expressão acima é
equivalente a (i<j) < k
k
com o resultado da
comparação i<j
(0 ou 1)A expressão correta usa a conjunção de duas condições:
< j && j < k i
==
(igual) e !=
(diferente)int i, j;
= 2;
i = 3;
j ("%d\n", i == j); // imprime 0
printf("%d\n", i+1 == j); // imprime 1
printf("%d\n", i != j); // imprime 1 printf
Não confundir atribuições com comparações:
i = j
modifica o lado esquerdo; resultado é o valor atribuido
i == j
compara o lados esquerdo e o direito; resultado é 0 ou 1
if
if
executa condicionalmente uma instrução
conforme o resultado de uma expressãoif (
expressão )
instruçãoif ( line_num == MAX ) line_num = 0;
// continuação do programa
...
if
{
instruções }
Podemos colocar numa só linha:
if (line_num == MAX) { line_num = 0; page_num ++; }
Mas fica mais claro se partimos em várias linhas:
if (line_num == MAX)
{
= 0;
line_num ++;
page_num }
else
if
pode incluir uma alternativa
else
:if (
expressão )
instrução
else
instruçãoelse
é executada se a expressão
tiver valor zero (i.e. for falsa)Exemplo:
if (i > j) max = i; else max = j;
else
if
dentro de outros
if
sif (i > j)
if (i > k)
= i;
max else
= k;
max else
if (j > k)
= j;
max else
= k; max
else
Podemos também acrescentar chavetas para auxiliar a compreensão:
if (i > j) {
if (i > k)
= i;
max else
= k;
max } else {
if (j > k)
= j;
max else
= k;
max }
else
Há quem prefira colocar sempre chavetas:
if (i > j) {
if (i > k) {
= i;
max } else {
= k;
max }
} else {
if (j > k) {
= j;
max } else {
= k;
max }
}
Ao colocarmos sempre chavetas:
if
ou do
else
if
em “cascata”Para testar condições em sequência escrevemos múltiplas instruções
if
em “cascata”.
Exemplo:
if (n < 0)
("n negativo\n");
printfelse
if (n == 0)
("n zero\n");
printfelse
("n positivo\n"); printf
if
em “cascata”Apesar do segundo if
estar dentro do primeiro, é
preferível alinhar os else
em vez de indentar:
if (n < 0)
("n negativo\n");
printfelse if (n == 0)
("n zero\n");
printfelse
("n positivo\n"); printf
if
em “cascata”Desta forma evitamos a indentação exagerada quando temos muitas condições.
if (expressão)
instruçãoelse if(expressão)
instrução...
else if(expressão)
instruçãoelse
instrução
Montante | Comissão |
---|---|
Até €2500 | €30 + 1.7% |
€2500-€6250 | €56 + 0.66% |
€6250-€20K | €76 + 0.34% |
€20K-€50K | €100 + 0.22% |
€50K-€500K | €155 + 0.11% |
Acima de €500K | €255 + 0.09% |
corretor.c
lê o valor da transação, calcula
a comissão e imprime-a:Introduza o valor: EUR 30000
Comissão: EUR 166.00
if
em cascata
para determinar em que intervalo está o valor/* corretor.c
Calcular a comissão de uma transação
*/
#include <stdio.h>
int main(void)
{
float valor, comissao;
("Introduza o valor: EUR ");
printf("%f", &valor);
scanf
if(valor < 2500.0)
= 30.0 + 0.017 * valor;
comissao else if(valor < 6250.0)
= 56.0 + 0.0066 * valor; comissao
(continua no slide seguinte)
(continuação do slide anterior)
else if(valor < 20e3)
= 76.0 + 0.0034 * valor;
comissao else if(valor < 50e3)
= 100.0 + 0.0022 * valor;
comissao else if(valor < 500e3)
= 155.0 + 0.0011 * valor;
comissao else
= 255.0 + 0.0009 * valor;
comissao
if (comissao < 39.0)
= 39.0;
comissao
("Comissão: EUR %.2f\n", comissao);
printf}
Podemos construir condições complexas partindo de outras mais simples usando operadores lógicos.
conjunção (\(\land\)) | && |
disjunção (\(\lor\)) | || |
negação (\(\neg\)) | ! |
Exemplos:
>=0 && i<10
i==j || i+j==0
i!(i==0)
i
está dentro
de um intervalo:if (0 <= i && i < n) ...
i
está fora do
intervalo):if (0 > i || i >= n) ...
!
é unário enquanto
&&
e ||
são binários!
\(expr\)resultado 1 se \(expr\) tem valor 0
&&
\(expr_2\)resultado 1 se \(expr_1\) e \(expr_2\) são ambos diferentes de 0
||
\(expr_2\)resultado 1 se \(expr_1\) é diferente de 0 ou \(expr_2\) é diferente de 0 (ou ambos são diferentes de 0)
Em todos os outros casos: o resultado é 0.
&&
e ||
avaliam
primeiro o lado esquerdo e só depois o lado direito(i != 0) && (j/i > 0)
i != 0
i
for diferente de 0, então é avalia
j/i > 0
i
for 0 então a conjução será sempre falsa
e não avaliamos j/i > 0
(evitando a divisão por
zero)&&
e ||
têm menor precedência que
os operadores de comparação e associam à esquerda!
tem precedência igual a +
e
-
unários e associa à direitaExemplos:
i < j && k < m
é equivalente a (i < j) && (k < m)
i < j && j < k && k < l
é equivalente a ((i < j) && (j < k)) && (k < l)
!i == 0
não é equivalente a i != 0
if
Um erro comum é trocar ==
(igualdade) por =
(atribuição)
if (i == 0) ...
testa se i
é igual a 0
if (i = 0) ...
atribui 0 a i
e depois testa se o resultado é diferente
de 0 (o que é sempre falso)
Recomendação: o gcc
avisa possíveis erros deste tipo
compilando com a opção -Wall
else
Ao colocarmos if
dentro de outro, temos de ter o cuidado
de “casar” corretamente os else
:
if (y != 0)
if (x != 0)
= x / y;
result else
("erro: y igual a 0\n"); printf
else
associa ao
if
mais exteriorelse
associa ao
if
mais próximo (o interior)else
Uma versão corretamente indentada seria assim:
if (y != 0)
if (x != 0)
= x / y;
result else
("erro: y igual a 0\n"); printf
else
Para associar o else
ao if
exterior temos
de delimitar o if
interior usando chavetas:
if (y != 0) {
if (x != 0)
= x / y;
result } else
("erro: y igual a 0\n"); printf
Recomendação: para evitar estes problemas use sempre
chavetas num if
que contém outro if
Uma função que calcula a média aritmética de dois valores:
float media(float a, float b)
{
float m = (a + b) / 2.0;
return m;
}
media
float
antes do
identificador indica o tipo do resultadoa
e b
são os dois
valores de tipo float
que devem fornecidos para executar a
funçãoO corpo da função está delimitado entre chavetas:
{
float m = (a + b) / 2.0;
return m;
}
m
)return
termina a função e devolve o
resultado ao contexto onde a função foi chamadaUm expressão: identificador(arg1, arg2, …)
main
main
pode chamar outra função e assim
sucessivamentemain
(direta ou indirectamente)= media(x*0.5, y+1); z
("%f\n", media(x*0.5,y+1)); printf
Vamos escrever um programa que lê três números e calcula as médias dois a dois.
Introduza 3 números: 3.5 9.6 10.2
Médias
3.5 e 9.6: 6.55
9.6 e 10.2: 9.9
3.5 e 10.2: 6.85
#include <stdio.h>
float media(float a, float b) {
float m = (a + b)/2;
return m;
}
int main(void) {
float x, y, z;
("Introduza 3 números: ");
printf("%f %f %f", &x, &y, &z);
scanf("Médias\n");
printf("%f e %f: %f\n", x, y, media(x,y));
printf("%f e %f: %f\n", y, z, media(y,z));
printf("%f e %f: %f\n", x, z, media(x,z));
printfreturn 0;
}
float media(float, float);
int
float media(float, float); // protótipo
int main(void) {
...
(..., x, y, media(x,y)); // uso
printf...
return 0;
}
float media(float a, float b) { // definição
= (a + b)/2.0;
m return m;
}
void
return
void print_time(int n)
{
("T minus %d and counting\n", n);
printf}
int main(void) {
(3);
print_time(2);
print_time(1);
print_timereturn 0;
}
return
void
deve usar a
instrução return
para especificar o resultadoreturn expressão ;
return 0;
return n;
return (x + y) / 2.0;
return
Podemos usar return
para terminar
a execução da função a meio do corpo.
int max(int a, int b)
{
if(a >= b)
return a; // termina imediatamente
// se a execução chegar a este ponto,
// então a < b; logo o máximo é b
return b;
}
return
return
em funções que não retornam
resultados (void
)return
serve apenas para terminar a execução
da funçãovoid print_time(int n)
{
if (n < 0)
return; // terminar imediatemente
("T minus %d and counting\n", n);
printf}
return
return
pode dificultar a compreensão do
fluxo de execução// máximo de 2 valores
// NB: modifica o primeiro argumento
int max(int a, int b) {
if (b > a)
= b;
a return a;
}
int main(void) {
int x = 1, y = 2;
("%d\n", max(x,y)); // imprime 2
printf("%d %d\n", x, y); // imprime 1, 2
printfreturn 0;
}
// Tenta trocar os valores de a, b;
// não funciona porque a,b são temporários
void trocar(int a, int b) {
int t;
= a;
t = b;
a = t;
b }
int main(void) {
int x = 1, y= 2;
(x, y);
trocar("%d %d\n", x, y); // imprime 1, 2
printfreturn 0;
}
Escrever um programa que imprime os algarismos das dezenas e unidades de um inteiro até 99.
Exemplos de execução:
12
um dois
78
sete oito
7
zero sete
Dado o valor de um algarismo de 0–9, imprimir o texto correspondente em português:
0 | "zero" |
1 | "um" |
2 | "dois" |
3 | "três" |
4 | "quatro" |
5 | "cinco" |
6 | "seis" |
7 | "sete" |
8 | "oito" |
9 | "nove" |
Vamos definir uma função auxiliar:
void imprime_algarismo(int a);
void
)A definição da função é longa mas simples: uma sequência de condições
if
em cascata.
void imprime_algarismo(int a) {
if (a == 0)
("zero");
printfelse if (a == 1)
("um");
printfelse if (a == 2)
("dois");
printfelse if (a == 3)
("três");
printfelse if (a == 4)
("quatro"); printf
(continua no slide seguinte)
(continuação do slide anterior)
else if (a == 5)
("cinco");
printfelse if (a == 6)
("seis");
printfelse if (a == 7)
("sete");
printfelse if (a == 8)
("oito");
printfelse if(a == 9)
("nove");
printfelse
("algarismo inválido!");
printf}
n
é um inteiro entre 0 e 99:
n%10
é são as unidades;n/10
remove unidades; restam as dezenasint main(void) {
int n, d, u;
("%d", &n);
scanfif (!(n>=0 && n<=99)) {
("número inválido\n");
printfreturn -1; // erro
}
= n % 10; // unidades (0..9)
u = n / 10; // dezenas (0..9)
d (d); printf(" ");
imprime_algarismo(u); printf("\n");
imprime_algarismoreturn 0; // OK
}
if
sA decomposição em funções permitiu:
while
é usado para ciclos em que a expressão é testada antes de executar o corpo do ciclo
do...while
é usado para ciclos em que a expressão é testada depois de executar o corpo
for
é uma forma conveniente para ciclos com uma variável de controlo
while
while ( expressão ) instrução
Execução:
= 1;
i while (i < 10) /* expressão de controlo */
= i * 2; /* corpo do ciclo */ i
i = 1; |
|
i < 10 ? |
1 (verdade) |
i = i * 2 = 2 |
|
i < 10 ? |
1 (verdade) |
i = i * 2 = 4 |
|
i < 10 ? |
1 (verdade) |
i = i * 2 = 8 |
|
i < 10 ? |
1 (verdade) |
i = i * 2 = 16 |
|
i < 10 ? |
0 (falso) |
No final: i
= 16.
while
O corpo pode ser um bloco de instruções em vez de uma só:
= 1;
i while (i < 10) {
("%d\n", i);
printf= i * 2;
i }
Podemos colocar chavetas mesmo com uma só instrução:
= 1;
i while (i < 10) {
= i * 2;
i }
while
termina quando o valor da expressão for 0
(falso) - e.g., se a expressão for i < 10
então o ciclo
termina quando \(i\geq 10\)while (1) {
... /* ciclo infinito */
}
Limite superior: 5
1 1
2 4
3 9
4 16
5 25
/*
quadrados.c
Imprimir uma tabela de quadrados
*/
#include <stdio.h>
int main(void) {
int i, n;
("Limite superior: ");
printf("%d", &n);
scanf= 1;
i while (i <= n) {
("%d\t%d\n", i, i*i);
printf++;
i }
return 0;
}
/*
somar.c
Somar uma sequência de números
*/
#include <stdio.h>
int main(void) {
int n, soma = 0;
("Introduza valores; 0 termina.\n");
printf("%d", &n); // primeiro valor
scanfwhile (n != 0) { // enquanto não terminou
+= n; // acumular
soma ("%d", &n); // ler próximo valor
scanf}
("A soma é: %d\n", soma);
printfreturn 0;
}
do...while
do instrução while ( expressão );
Execução:
Vamos re-escrever o programa para somar números usando um ciclo
do
.
/*
somar2.c
Somar uma sequência de números (alternativa)
*/
#include <stdio.h>
int main(void) {
int n, soma = 0;
("Introduza valores; 0 termina.\n");
printfdo {
("%d", &n); // próximo valor
scanf+= n; // acumular
soma } while (n != 0); // enquanto não terminou
("A soma é: %d\n", soma);
printfreturn 0;
}
Calcular o número de algarismos de um inteiro positivo:
Introduza um inteiro positivo: 5633
4 algarismo(s)
do
é mais conveniente do que while
porque qualquer número positivo tem pelo menos um algarismo/* algarismos.c
Contar algarismos de um inteiro positivo
*/
#include <stdio.h>
int main(void) {
int digits = 0, n;
("Inteiro positivo: ");
printf("%d", &n);
scanfdo {
/= 10; // quociente divisão por 10
n ++; // mais um algarismo
digits } while (n > 0);
("%d algarismo(s)\n", digits);
printfreturn 0;
}
for
for ( expr1; expr2; expr3 ) instrução
expr1
é a inicializaçãoexpr2
é a condição de repetiçãoexpr3
é a atualização após cada iteraçãoinstrução
é o corpo do cicloExemplo:
for (i = 0; i < 10; i++)
("%d\n", i); printf
for
for
é conveniente para ciclos que necessitam de
contar de um valor inicial até um valor finalwhile
em vez do for
, mas
o for
é mais clarofor
Exemplo:
for (i = 0; i < 10; i++)
("%d\n", i); printf
é equivalente a
= 0;
i while (i < 10) {
("%d\n", i);
printf++;
i}
for
A forma geral
for (expr1; expr2; expr3) instrução
é equivalente a:
;
expr1while ( expr2 ) {
instrução;
expr3}
Esta tradução pode ajudar a compreender alguns detalhes.
for
Exemplo: qual o efeito de usar ++i
em vez de
i++
no ciclo seguinte?
for(i = 0; i < 10; ++i)
("%d\n", i); printf
Traduzindo para while
:
= 0;
i while (i < 10) {
("%d\n", i);
printf++i; // alternativa: i++;
}
Usar ++i
ou i++
é equivalente — contamos de
0 a 9.
for
Repetir n
vezes:
// contagem ascendente de 0 até n-1
for(i = 0; i < n; i++) ...
// contagem ascendente de 1 até n
for(i = 1; i <= n; i++) ...
// contagem descendente de n-1 até 0
for(i = n-1; i >= 0; i--) ...
// contagem descendente de n até 1
for(i = n; i > 0; i--) ...
for
<
ou
<=
>
ou
>=
==
em vez <
, <=
,
>
, >=
i<n
em vez de i<=n
for
Podemos omitir uma ou mais expressões no ciclo for
.
Omitir a inicialização:
int i = 10;
for (; i > 0; i--)
("%d\n", i) printf
Omitir a atualização:
int i;
for (i = 10; i > 0;)
("%d\n", i--) printf
for
Omitir ambas inicialização e atualização:
int i = 10;
for (; i > 0;)
("%d\n", i--) printf
Isto é equivalente a um ciclo while
:
int i = 10;
while (i > 0)
("%d\n", i--) printf
for
for
só termina se
usarmos instruções de saida no corpo (mais à frente)for
sem condição
em vez de while
para esses ciclos// usando ciclo while
while (1) {
...
}
// usando ciclo for
for (;;) {
...
}
for
em C99for
pode ser
substituida por uma declaraçãofor(int i = 0; i < n; i++) ...
for
em C99for(int i = 0; i < n; i++) {
("%d\n", i); // OK: i é válido
printf}
("%d\n", i); // ERRO: i fora de âmbito
printf("%d\n", n); // OK: n é válido printf
break
while
ou for
do...while
break
para terminar
um ciclo em qualquer momentobreak
Exemplo: procurar o primeiro divisor próprio de um número \(n\) (isto é, um divisor entre 2 e \(n-1\)):
int i, n;
... /* obter valor de `n' */
for (i = 2; i < n; i++) {
if (n%i == 0) break;
}
Este ciclo pode terminar de duas formas:
i >= n
)i < n
)break
No final do ciclo podemos determinar a causa de terminação com um teste simples:
int i, n;
... /* obter valor de `n' */
for (i = 2; i < n; i++) {
if (n%i == 0) break;
}
if (i < n)
("Encontrou divisor: %d\n", i);
printfelse
("Não tem divisores próprios\n"); printf
break
break
é útil para
escrever um ciclo com um teste de terminação a meiofor(;;) {
("%d", &n);
scanfif (n == 0) // se for zero
break; // terminar o ciclo
... // se não: processar o valor
}
continue
continue
transfere a
execução para o ponto imediatamente antes do fim do corpobreak
termina o ciclo, continue
continua no
cicloLer e acumular 10 inteiros não-negativos.
int i = 0, n, soma = 0;
while (i < 10) {
("%d", &n);
scanfif (n < 0)
continue;
+= n;
soma ++;
i /* continue salta para aqui */
}
continue
colocando
instruções dentro de um if
n >= 0
em vez de
n < 0
int i = 0, n, soma = 0;
while (i < 10) {
("%d", &n);
scanfif (n >= 0) {
+= n;
soma ++;
i }
}
Uma instrução pode ser vazia, isto é, apenas um ponto-e-vírgula sem mais símbolos:
= 0; ; j = 1; // segunda instrução vazia i
Uma instrução vazia não faz nada; é útil apenas para escrever um ciclo cujo corpo é vazio.
Considere o ciclo para procurar divisores:
for (i = 2; i < n; i++) {
if (n%i == 0) break;
}
Podemos juntar as duas condições e retirar o break
; o
corpo fica vazio:
for (i = 2; i < n && n%i != 0; i++)
; /* instrução vazia */
Para evitar confusão, devemos escrever a instrução vazia numa linha separada.