Laboratório de Programação
Prof. Oscar Luiz Monteiro de Farias
[email protected]
Capítulo 3 – Fluxo de Controle




Os comandos de fluxo de controle especificam a ordem
em que a computação é realizada.
Expressões, quando seguidas por um ; tornam-se um
comando:
x = 0; i++;
printf(...);
As chaves { e } agrupam declarações e comandos em
um comando composto ou bloco, e são sintaticamente
equivalentes a um único comando.
Variáveis podem ser declaradas dentro de quaisquer
blocos.
O comando if-else (1)


Usado para expressar decisões. Sintaxe:
if (expression)
statement1
else
statement2
onde a parte do else é opcional.
expression é avaliada. Se for verdadeira (!= 0),
statement1 é executado. Se for falsa (== 0) e se
houver a parte else, statement2 é executado.
O comando if-else (2)


Como o else é opcional , há uma ambigüidade quando um
else é omitido em uma seqüência de comandos if-else
aninhados.
Solução: o else é sempre associado com o mais recente if
sem else.
if (n > 0)
if (n > 0) {
if (a > b)
z = a;
if (a > b)
!=
z = a;
else
}
z = b;
else
z = b;
O comando else-if (1)
if (condition1)
/* para decisões múltiplas */
statement1
else if (condition2)
statement2
...
...
else
statementn+1
O comando else-if (2)


As condições são avaliadas em ordem, a partir do topo, até
que uma das condições (conditioni )seja satisfeita; nesse
ponto statementi é executado e a construção inteira é
terminada. (statementi pode representar vários statements
envolvidos por chaves). Se nenhuma das condições for
satisfeita, o statementn+1 após o else é executado, se houver.
Se o else e statementn+1 forem omitidos nenhuma ação é
tomada.
A última parte else corresponde ao caso “nenhuma das
anteriores” ou caso default, quando nenhuma das
condições é satisfeita.
O comando else-if (3)



Quando não há ação explícita para o caso default, o
else
statementn+1
pode ser omitido, ou usado para recuperação de
erro, capturando uma condição “impossível”.
Ver exemplo binsearch → prog25-chap03-pg52.c
Alternativa para decisões múltiplas: o comando
switch.
O comando switch (1)
switch (expression) {
case const-expr1: statements
…
case const-exprn: statements
default: statements
}
O comando switch (2)







Cada case é rotulado por um ou mais constantes de valor inteiro
ou expressões constantes.
Se um case corresponde aovalor de expression, a execução tem
início neste case.
Todas as case expressions devem ser diferentes umas das outras.
O case rotulado como default é executado se nenhum dos outros
cases for satisfeito.
O case default é opcional; se não estiver presente e nenhum dos
cases combinar com expression, nenhuma ação é realizada.
Os cases and a cláusula default podem ocorrer em qualquer
ordem.
Ver prog26-chap03-pg52.c
O comando switch (3)




O comando break causa uma saída imediata do
switch.
Após o término da execução do código
associado a um case, a execução prossegue no
código associado ao case que se segue.
break e return são as formas mais comuns de se
abandonar um switch.
O comando break também pode ser usado para
forçar uma saída imediata de loops (while, for e
do)
Loop while
while (expression)
statement
 expression é avaliada. Se for diferente de zero
(verdadeira), statement é executado. Este ciclo
continua até expression se tornar zero (falsa),
prosseguindo a execução após statement.
 statement
i pode representar vários statements
envolvidos por chaves.
Loop for (1)
for (expr1; expr2; expr3)
statement
É equivalente a:
expr1;
while (expr2) {
statement
expr3;
}
Exceção: quando emprega o comando continue.
Loop for (2)




Gramaticamente os três componentes do loop for são
expressões.
Normalmente expr1 e expr3 são atribuições ou chamadas de
função e expr2 é uma expressão relacional.
Qualquer uma das tres partes pode ser omitida, embora os ;
devam permanecer.
Se expr2 não estiver presente, é assumida como
permanentemente verdadeira.
for (;;) {
...
}
/* representa um loop infinito */
Loop for (3)



for (i = 0; i < n; i++){
…
}
O índice e o limite de um loop for em C podem
ser alterados dentro do loop.
A variável de índice i retém o seu valor quando
o loop termina por algum motivo.
Exemplo: atoi - prog27-chap03-pg54.c




atoi converte uma cadeia de caracteres em seu
equivalente numérico.
Versão mais geral do que a do chap02; considera
espaços iniciais e um sinal opcional de + ou -.
Algoritmo de atoi:
Salta espaços em branco, se existirem
obtém o sinal, se houver
obtém a parte inteira e a converte
A biblioteca padrão provê a função strtol, mais
elaborada, para a conversão de strings em inteiros
longos; ver Section 5 do Appendix B.
Algoritmo de ordenação Shell(1)


Nos algoritmos de ordenação que movem os
ítens uma posição de cada vez, o tempo de
execução médio será, no melhor dos casos
proporcional a N2, uma vez que cada ítem se
deslocará em média (1/3)N posições durante o
processo de classificação.
Melhorias substanciais relativas à inserção
direta podem ser conseguidas se ítens distantes
puderem ser trocados, ao invés de apenas os
ítens próximos.
Algoritmo de ordenação Shell(2)'


i) divide-se os 16 registros em oito grupos de 2 cada (l1): (R1, R9), (R2, R10), ...(R8,R16);
Classifica-se os oito grupos de registro em separado. Observe que 154 trocou de lugar
com 512; 908 e 897 pularam para a direita (l2).
ii) Divide-se os registros em grupo de 4 cada: (R1, R5, R9, R13), …, (R4, R8, R12, R16) e
novamente classifica-se cada grupo em separado (l3).

iii) Divide-se os registros em grupo de 8 cada:...

iv) Divide-se os registros em grupo de 16 cada:...

Cada sort intermediário envolve um arquivo
relativamente pequeno ou um
arquivo razoavelmente ordenado, em que inserções diretas podem ser usadas.




Os registros tendem a convergir rapidamente para o seu destino final.
A seqüência de incrementos 8, 4, 1, 2 não é fixa; qualquer seqüência ht, ht-1, …, h1
ser usada, desde que o último incremento h1 seja igual a 1.
pode
Ver prog28-chap03-pg55.c.
As vantagens de manter os controles dos loops centralizados é mais evidente quando se
tem vários loops aninhados (loop for).
Shell sort
O operador , (1)





Mais usado no comando for.
Um par de expressões separadas por , é avaliado da
esquerda para a direita, e o tipo e o valor do resultado
são o tipo e o valor do operando direito.
Em um comando for é possível colocar múltiplas
expressões em seus componentes, por exemplo, para
processar dois índices em paralelo.
Exemplo: prog29-chap03-pg55.c – função reverse, que
inverte a cadeia de strings s.
Obs.: as vírgulas que separam argumentos de funções e
variáveis em declarações não são operadores.
O operador , (2)

Uma expressão com vírgula também poderia ser
usada para a atroca de elementos em reverse,
onde a troca seria feita em uma única operação.
for (i = 0, j = strlen(s)-1; i < j; i++, j--)
c = s[i], s[i] = s[j], s[j] = c;
Loop do-while (1)


O do-while testa a condição de término ao final do
loop, após executar o corpo do loop, ao contrário dos
loops while e for, que testam a condição de término no
início. Sintaxe:
do
statement
while (expression);
statement é executado e expression é avaliada. Se for
verdadeira statement é executado novamente, e assim
por diante. Se expression se torna falsa o loop finda.
Loop do-while (2)




Exemplo: prog30-chap03-pg56.c – função itoa, que
converte um número para uma cadeia de caracteres ( o
inverso de atoi).
A cadeia será gerada na ordem reversa e, então,
invertida.
O do-while é necessário ou, ao menos conveniente, pois
no mínimo um caracter deve ser instalado no vetor s,
mesmo que n seja zero.
Usou-se chaves ao redor do único comando que
constitui o corpo do do-while, para evitar confusões
como o início de um loop while.
break



O comando break permite uma saída imediata
de um for, while e do-while, e de um switch.
break faz com que o loop (ou switch) mais
interno seja terminado imediatamente.
Exemplo: prog31-chap03-pg57.c – função trim,
que remove espaços, tabulações e caracteres de
new line do final de um string, usando um break
para sair do loop, quando o caracter mais à
direita do string coincidir com um dos caracteres
anteriormente mencionados.
continue





O comando continue é relacionado com o
break.
continue inicia a próxima iteração do loop for,
while, ou do-while.
No while e do-while isto significa que a parte do
teste será executada imediatamente.
No for, o controle passa para a parte de
incremento (avalia expr3).
continue aplica-se só a loops e não a switch .
continue – exemplo de uso


Código para processar apenas elementos
positivos no vetor “a”; valores negativos são
saltados.
for (i = 0; i < n; i++) {
if (a[i] < 0) /* skip negative elements */
continue;
... /* do positive elements */
}
goto e labels (1)





Formalmente pode-se prescindir do uso do goto,
pois sempre existe formas de se escrever um
código equivalente.
Usado indiscriminadamente torna o código
confuso e não linear.
Todavia, existem situações em que pode ser útil.
Abandonar todos os loops, em uma estrutura de
loops profundamente aninhada.
Um label segue a mesma sintaxe de uma
variável e é seguido por um sinal de :
goto e labels (2)
for ( ... )
for ( ... ) {
...
if (disaster)
goto error;
}
...
error: /* clean up the mess */
...
goto e labels (3)

Determinar se dois vetores a e b possuem um elemento em
comum.
for (i = 0; i < n; i++)
for (j = 0; j < m; j++)
if (a[i] == b[j])
goto found;
/* didn't find any common element */
...
found:
/* got one: a[i] == b[j] */
...
goto e labels (4)

Código alternativo sem o uso do goto.
found = 0;
for (i = 0; i < n && !found; i++)
for (j = 0; j < m && !found; j++)
if (a[i] == b[j])
found = 1;
if (found)
/* got one: a[i-1] == b[j-1] */
...
else
/* didn't find any common element */
...
Download

statement