Estruturas de Decisão e loops Nos códigos que vimos até agora, as instruções são seguidas seqüencialmente usando os valores de variáveis atuais a cada linha. Essa estrutura linear não é adequada para a maioria das aplicações. Necessitamos de mecanismos que provoquem bifurcações na excecução, ou seja, que certos comandos só sejam executados se determinadas condições forem satisfeitas. Também precisamos de uma forma de forçar a repetição de grupos de comandos. As diversas estruturas condicionais existentes na linguagem fornecem esses mecanismos. O funcionamento delas depende da avaliação, como falsa ou verdadeira, de uma determinada afirmativa. 1
Estruturas de Decisão Queremos instruir o programa a executar um conjunto de instruções caso uma certa condição seja satisfeita. if (condição){ comandos - n = 0 x = 2. if ( x > 0 ) { printf ("x positivo\n"); n = n + 1; printf ("n = %d\n", n); 2
Se a instrução é simples (um só comando), as chaves são desnecessárias: n = 0 x = 2. if ( x > 0 ) n = n + 1; printf ("n = %d\n", n); Uma expressão lógica tem valor numérico 0 se for falsa e 0 se for verdadeira 3
if-else if (condição){ comandos else { comandos - x =...; if(x > 0){ y = sqrt(x); else { y = sqrt(-x); 4
A forma mais geral possível: else-if if (condição) { comandos else if (condição) { comandos else if (condição) { comandos else { comandos if (media >= 9.0) printf("grau A"); else if (media >= 7.0) printf("grau B"); else if (media >= 5.0) printf("grau C"); else printf("grau D"); 5
Operadores lógicos e relacionais Os operadores relacionais são > (maior) >= (maior ou igual) < (menor) <= (menor ou igual), e == (igual)!= (diferente de), Os operadores relacionais tem precedência abaixo dos aritméticos: a expressão x < y-1 é avaliada como x < (y-1). Atenção para a diferença entre if (a = = b) e if (a = b) 6
Os operadores lógicos são && (e) (ou). A avaliação de uma expressão é feita de acordo com a tabela: V && V = V V && F = F F && F = F V V = V V F = V F F = F Expressões conectadas por && e são avaliadas da esquerda para a direita, e a avaliação é interrompida assim que seja possível determinar se a expressão é falsa ou verdadeira. O operador unário! é o operador de negação. Ele troca V por F e vcvs. 7
Exemplos: if (a > 0.0 && 1./a < c) x = 0; Se quisermos saber se x está dentro de um certo intervalo: if ( x > xmin && x < xmax) { instrucoes Se quisermos saber se x está fora de um certo intervalo: if ( x < xmin x > xmax) { instrucoes if ( (a == b && a!= 0) a == 2 ) if (!(a < b) ) 8
Ordem de precedência:! ; (*, /, % ) ; (+, - ) ; ( >, <, >=,<= ) ; ( = =,!= ) ; && ; De Morgans Law: Sempre use parêntesis!(a && B)!A!B!(A B)!A &&!B O operador ternário? fornece um modo alternativo de se fazer teste lógico: z = condição? instrução 1 : instrução 2 Se condição for V, a instrução 1 é executada, senão, a instrução 2 é executada. z = (a > b)? a : b; 9
Exercício vspace0.5cm Modifique o programa que calula as raízes da equação de segundo grau para levar em conta < 0. Os valores dos coeficientes a, b e c, devem ser lidos pelo teclado. Seu programa deve: recusar valores nulos de a, e discriminar os casos: raizes iguais, raizes reais diferentes, raizes complexas diferentes. No último caso, os valores das raízes devem ser escritos como Re +-i Im, onde Re= b 2a e Im= 2a 10
Laços (loops) Os loops são muito úteis quando precisamos executar um conjunto de instruções várias vezes. Exemplo : Suponha que queremos calcular o somatório s = N n=1 1 n Sem uma estrutura de loop teríamos que fazer: 11
#include <stdio.h> int main() { double soma; int n; n = 1; soma = 1./n; n = n + 1; soma = soma + 1./n; n = n + 1; soma = soma + 1./n; n = n + 1; soma = soma + 1./n; printf(" soma para N = 4 e %lf \n",soma); return 0; 12
loops do tipo for for (condição inicial ; expressão de controle ; expressão de atualização) { instruções Ao entrar no loop, a condição inicial é executada e a expressão de controle é testada. Se for V, as instruções são executadas e após a última instrução, a expressão de atualização é executada. A expressão de controle é testada novamente, e só sai do loop quando ela for F. for ( i = 0; i < 50; i = i + 1){ printf ( " Aprendendo a contar %d \n", i); A expressão de controle pode conter combinações de && e. 13
#include <stdio.h> int main() { double soma; int n, N; printf("de o numero de termos a serem somados:\n"); scanf("%d", &N); soma = 0.; for(n = 1; n <= N ; n++){ soma = soma + 1./n; // ou soma += 1./n; printf("%d\t%lf\n", n, soma); return 0; 14
Como no if, as chaves são dispensáveis se instruções contiver apenas uma linha de código. A instrução break interrompe o loop, a execução passa para a primeira instrução logo após a chave. A instrução continue faz com que as próximas instruções sejam puladas, a expressão de atualização é executada e a expressão de controle é testada. O programa não sai do loop. for ( i = 0; i < 10; i = i + 1){ if ( i == 5) continue; printf ( " i = %d \n", i); Ao término do loop, os contadores preservam o último valor que lhes foi atribuído antes de deixá-lo. Estes contadores não precisam ser números inteiros. 15
Abreviações i = i + 1 i ++ j = j - 1 j - - soma = soma + n soma + = n pode ser usada com qualquer um dos operadores aritméticos: +, -, *, / e %. A forma geral é: t = t operador (expressão) t operador (expressão) 16
loops do tipo while while (condição) { instruções Executa as instruções enquanto a condição for satisfeita. Deve-se tomar cuidado em inicializar o valor testado em condição, e em atualizar essa condição dentro do loop. Útil quando não sabemos a quantidade, mas uma condição a ser satisfeita. Ex: Estamos lendo vários valores de n e queremos que o programa pare quando n = = 0 17
#include <stdio.h> int main() { int n; int soma = 0; scanf ("%d", &n); while ( n!= 0) { soma += n; scanf ("%d", &n); printf("%d\n", soma); return 0; 18
#include <stdio.h> int main() { double soma; int n, N; printf("de o numero de termos a serem somados:"); scanf("%d", &N); soma = 0.; n = 1; while(n <= N){ soma = soma + 1./n; // ou s += 1./n; printf("%d\t%lf\n", n, soma); n++; 19
loops do tipo do while do { instruções while (condição); Executa as instruções enquanto a condição for satisfeita, sendo a avaliação da condição feita no final de cada passo. Isto significa que as instruções sao executadas ao menos uma vez. 20
#include <stdio.h> int main() { double soma; int n, N; printf("de o numero de termos a serem somados:"); scanf("%d", &N); soma = 0.; n = 1; do { soma += 1./n; printf("%d\t%lf\n", n, soma); n++; while(n <= N); 21
goto e rótulos. goto label;. label:. O rótulo, um identificador seguido de dois pontos, pode ser colocado em qualquer parte dentro da função onde ocorre o goto. Ao encontrar o goto a execução do programa passa para o primeiro comando após o rótulo. É muito flexível, mas torna o programa muito confuso e difícil de manter. Deve ser evitado ao máximo. 22
Vejamos um exemplo onde o uso do goto é realmente útil: int main() {int i, j, k; int imax=3, jmax=2, kmax=5; int n=0, nmax=25; for(i=0;i<imax;++i) { for(j=0;j<jmax;++j) { for(k=0;k<kmax;++k) { n++; printf("%d\t%d\t%d\t%d\n", i,j,k,n); if( n >= nmax ) goto fim; fim: return 0; 23
O comando switch Um outra estrutura de decisão é o switch: switch (expressão ) { case a: comandos;. case b: comandos; default:comandos; Todos os cases a, b, c,... devem ser expressões constantes inteiras e diferentes entre si. A execução começa a partir do case que se iguala à expressão e continua por todos os outros que o seguem. O caso default é executado quando todos os cases falham, mas é opcional. 24
Frequentemente queremos que só um dos cases seja executado. Devemos então utilizar o comando break como último comando de cada case: switch (expressão ) { case a: comandos; break; case b: comandos; break;. default:comandos; Exemplo: int main() { char key; int ndigitos=0, nvogais=0, nconsoantes=0; while( 1 ) { 25
scanf("%c",&key); if( key == \n ) break; switch( key ){ case 0 : case 1 : case 2 : case 3 : case 4 : case 5 : case 6 : case 7 : case 8 : case 9 : { ndigitos++; printf("%c e um digito\n",key); break; 26
case a : case e : case i : case o : case u : { nvogais++; printf("%c e uma vogal\n",key); break; default: { nconsoantes++; printf("%c e uma consoante\n",key); printf("digitos: %d Vogais: %d Consoantes: %d\n", ndigitos, nvogais, nconsoantes); 27
return 0; 28
Redirecionamento de Entrada e saída no Unix O dispositivo padrão para entrada de dados (stdin) é o teclado. O dispositivo padrão para saída de dados (stdout)é o monitor. Podemos redirecionar a entrada de dados para um arquivo usando o <. Podemos redirecionar a saída de dados para um arquivo usando o >. Se o arquivo notas.dat contém a lista das notas de uma turma, podemos ler a partir deste arquivo com o mesmo programa media que lê a partir do teclado com o comando:./media < notas.dat O resultado será escrito na tela do monitor. Se quisermos salvar estes resultados num arquivo resultados.dat, podemos fazer./media < notas.dat > resultados.dat 29