Prévia do material em texto
ESTRUTURAS ITERATIVAS
Na aula anterior, vimos como realizar desvios condicionais em um programa. Desse modo,
criamos programas em que um bloco de comandos é executado somente se uma determinada
condição for satisfeita.
Entretanto, há casos em que se deseja repetir um determinado trecho de um programa um
certo número de vezes. Por exemplo, pode-se citar um algoritmo que calcula a soma dos números
ímpares entre 500 e 1000 ou então um algoritmo que escreva os números maiores que 0 enquanto
a sua soma não ultrapasse 1000.
Dessa forma, precisamos utilizar uma estrutura de repetição que permita executar um
conjunto de comandos quantas vezes for necessário. Tais estruturas, também chamadas de
estruturas iterativas, são utilizadas nessas situações específicas. Elas também são muitas vezes
chamadas de laços ou também de loops.
A classificação das estruturas de repetição é feita de acordo com o conhecimento prévio do
número de vezes que o conjunto de comandos será executado. Assim, os laços se dividem em:
✓ Laços Contados → quando se conhece previamente quantas vezes o comando composto no
interior da construção será executado;
✓ Laços Condicionais → quando não se conhece de antemão o número de vezes que o
conjunto de comandos no interior do laço será repetido, pelo fato do mesmo estar
subordinado à uma condição sujeita à modificação pelas instruções do interior do laço.
Todo algoritmo que possui um ou mais de seus passos repetidos um determinado número
de vezes denomina-se algoritmo com repetição.
Com a utilização de estruturas de repetição para a elaboração de algoritmos, torna-se
necessário o uso de dois tipos de variáveis para a resolução de diversos tipos de problemas:
variáveis contadoras e variáveis acumuladoras.
Uma variável contadora é uma variável que recebe um valor inicial, geralmente 0 (zero)
antes do início de uma estrutura de repetição, e é incrementada no interior da estrutura de um
valor constante, geralmente 1, conforme o exemplo abaixo:
...
cont = 0;
...
cont = cont + 1;
...
...
Uma variável acumuladora é uma variável que recebe um valor inicial, geralmente 0 (zero)
antes do início de uma estrutura de repetição, e é incrementada no interior da estrutura de um
valor variável, geralmente a variável usada na estrutura de controle, conforme o exemplo abaixo:
...
soma = 0;
...
soma
...
Estruturas Iterativas Condicionais, ou simplesmente laços condicionais, são aqueles cujo
conjunto de comandos em seu interior é executado até que uma determinada condição seja
satisfeita. Ao contrário do que acontece nos laços contados, nos laços condicionais não se sabe de
antemão quantas vezes o corpo do laço será executado.
As construções que implementam laços condicionais em linguagem de programação C são:
✓ WHILE → laço condicional com teste no início
✓ DO-WHILE → laço condicional com teste no final
✓ FOR → laço condicional simplificado com teste no início
Nos laços condicionais a variável que é testada, tanto no início quanto no final do laço, deve
sempre estar associada a um comando que a atualize no interior do laço. Caso isso não ocorra, o
programa ficará repetindo indefinidamente este laço, gerando uma situação conhecida como “laço
infinito”.
1. LAÇO CONDICIONAL COM TESTE NO INÍCIO (WHILE)
O laço condicional com teste no início caracteriza-se por uma estrutura que efetua um teste
lógico no início de um laço, verificando se é permitido ou não executar o conjunto de comandos no
interior deste laço.
O fluxo de controle da estrutura iterativa condicional com teste no início pode ser
representado por:
A sintaxe básica para o laço condicional com teste no início é a seguinte:
while (condição)
{
sequência_de_comandos;
}
Na execução da estrutura, a condição será avaliada e:
✓ se a condição for verdadeira (ou possuir valor diferente de zero), a sequência de
comandos será executada; ao final da sequência de comandos, o fluxo do programa é
desviado novamente para o teste da condição;
✓ se a condição for considerada falsa (ou possuir valor igual a zero), a sequência de
comandos não será executada.
Observe abaixo um exemplo de um programa que lê dois números inteiros a e b digitados
pelo usuário e imprime na tela todos os números inteiros entre a e b:
1. #include
2. #include
3. int main()
4. {
5. int a, b;
6. printf("Digite o valor de a: ");
7. scanf("%d", &a);
8. printf("Digite o valor de b: ");
9. scanf("%d", &b);
10. while (a
2. #include
3. int main()
4. {
5. int a, b;
6. printf("Digite o valor de a: ");
7. scanf("%d", &a);
8. printf("Digite o valor de b: ");
9. scanf("%d", &b);
10. while (aa sequência de comandos é executada primeiro. Mesmo que a
condição seja falsa logo na primeira repetição do comando do-while, a sequência de comandos
terá sido executada pelo menos uma vez. Portanto, o comando do-while pode repetir uma
sequência de comandos uma ou mais vezes.
O comando do-while, assim como o comando while, segue todas as recomendações
definidas para o comando if quanto ao uso das chaves e definição da condição usada.
Observe o exemplo abaixo de um programa que exibe um menu de opções para o usuário e
espera que ele digite uma das suas opções.
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
#include
#include
int main()
{
int i;
do
{
printf("Escolha uma opção:\n");
printf("1 - Opção 1\n");
printf("2 - Opção 2\n");
printf("3 - Opção 3\n");
scanf("%d", &i);
}
while ((i3));
printf("Você escolheu a opção %d.\n", i);
return 0;
}
Vale ressaltar aqui que, diferentemente do comando while, é necessário colocar um ponto
e vírgula (;) depois da condição do comando do-while. No comando do-while, a sequência de
comandos é definida antes do teste da condição, diferente das outras estruturas condicionais e
iterativas. Isso significa que o teste da condição é p último comando da repetição do-while. Sendo
assim, o compilador entende que a definição do comando do-while já encerrou e exige que se
coloque o operador de ponto e vírgula (;) após a condição. Além disso, é responsabilidade do
programador modificar o valor de algum dos elementos usados na condição para evitar que ocorra
um laço infinito.
3. LAÇO CONDICIONAL SIMPLIFICADO (FOR)
O laço condicional simplificado com teste no início caracteriza-se por uma estrutura que
efetua um teste lógico no início de um laço, verificando se é permitido ou não executar o conjunto
de comandos no interior deste laço. É uma simplificação da estrutura while muito utilizada em laços
contados, quando se conhece previamente o número exato de vezes que se deseja executar um
determinado conjunto de comandos. Este tipo de laço nada mais é que uma estrutura dotada de
mecanismos para contar o número de vezes que o corpo do laço (ou seja, o comando composto em
seu interior) é executado.
O fluxo de controle da estrutura iterativa contada pode ser representado por:
A sintaxe básica para o laço contado é a seguinte:
for (inicialização; condição; incremento)
{
sequência_de_comandos;
}
Na execução da estrutura, a seguinte sequência de passos é realizada:
✓ a cláusula inicialização é executada: nela as variáveis de controle recebem um valor
inicial para serem usadas dentro do bloco for
✓ a condição é testada:
• se a condição for considerada verdadeira (ou possuir valor diferente de zero), a
sequência de comandos será executada; ao final da sequência de comandos, o fluxo
do programa é desviado para o incremento
• se a condição for considerada falsa (ou possuir valor igual a zero), a sequência de
comandos não será executada (fim do bloco for)
✓ incremento: terminada a execução da sequência de comandos, ocorre a etapa de
incremento das variáveis de controle usadas no bloco for; ao final dessa etapa, o fluxo
do programa é novamente desviado para a condição
Observe abaixo um exemplo de um programa que lê dois números inteiros a e b digitados
pelo usuário e imprime na tela todos os números inteiros entre a e b (incluindo a e b).
1. #include
2. #include
3. int main()
4. {
5. int a,b,c;
6. printf("Digite o valor de a: ");
7. scanf("%d", &a);
8. printf("Digite o valor de b: ");
9. scanf("%d", &b);
10. for (c=a; c
#include
int main()
{
int a,b,c;
printf("Digite o valor de a: ");
scanf("%d", &a);
printf("Digite o valor de b: ");
scanf("%d", &b);
for (; a
#include
int main()
{
int a,b,c;
printf("Digite o valor de a: ");
scanf("%d", &a);
printf("Digite o valor de b: ");
scanf("%d", &b);
for (c=a; ; c++)
{
printf("%d\n", c);
}
return 0;
}
Para o comando for, a ausência da cláusula de condição é considerada como uma condição
que é sempre verdadeira. Sendo a condição sempre verdadeira, não existe condição de parada para
o comando for, o qual vai ser executado infinitamente. Assim, ao omitir a condição do comando
for, criamos um laço infinito.
➢ Comando for sem incremento
#include
#include
int main()
{
int a,b,c;
printf("Digite o valor de a: ");
scanf("%d", &a);
printf("Digite o valor de b: ");
scanf("%d", &b);
for (c=a; c
2. #include
3. int main()
4. {
5. int a,b,c;
6. printf("Digite o valor de a: ");
7. scanf("%d", &a);
8. printf("Digite o valor de b: ");
9. scanf("%d", &b);
10. for (c=a; cfica claro que a cláusula de incremento pode conter qualquer comando que
altere o valor de uma das variáveis de controle utilizadas pelo comando for. Pode-se observar que,
na linha 10, a variável c está sendo incrementada de duas unidades, enquanto que na linha 14, um
novo valor para a variável c é lido através do teclado.
Usando o operador vírgula (,) no comando for
Na linguagem C, o operador vírgula (,) é um separador de comandos. Ele permite determinar
uma lista de expressões que devem ser executadas sequencialmente, inclusive dentro do comando
for. O operador vírgula pode ser usado em qualquer uma das cláusulas.
Observe o exemplo abaixo:
1. #include
2. #include
3. int main()
4. {
5. int i,j;
6. for (i=0, j=100; i
2. #include
3. int main()
4. {
5. char c;
6. for (c='A'; c
2. #include
3. int main()
4. {
5. int x=1;
6. while (x
2. #include
3. int main()
4. {
5. int x=1;
6. while (x
#include
int main()
{
int i, soma=0;
for (i=1; i
#include
int main()
{
int i, soma=0;
i = 1;
while (i
#include
int main()
{
int i, soma=0;
i = 1;
do
{
soma = soma + i;
i++;
}
while (i
2. #include
3. int main()
4. {
5. int quant;
6. int cont;
7. float valor;
8. float soma = 0;
9. float media;
10. printf("Digite a quantidade de valores: ");
11. scanf("%d", &quant);
12. for (cont=1; contjá foram
lidos. Já a variável valor armazenará o valor lido mais recentemente. E soma guardará a soma de
todos os valores que são lidos. Finalmente, media armazenará o resultado calculado no final do
programa.
Nas linhas 10 e 11, o programa solicita que o usuário digite o número de valores que devem
ser lidos para calcular a média. Já nas linhas 12 a 17, a estrutura for executa o bloco repetidamente,
uma vez para cada valor de cont entre 1 e o número armazenado em quant. A cada repetição,
solicita um número, o qual é somado ao valor anterior em soma, e que substitui o antigo valor nessa
variável.
No final, nas linhas 18 e 19, o programa calcula a média e apresenta o valor.
Caso 2 → ler uma quantidade fixa de valores (utilizando while)
➢ Usuário informa a quantidade de valores disponíveis e em seguida informa cada um dos valores.
O programa então calcula a média dos números lidos.
O mesmo programa pode ser escrito usando while, mas torna o código um pouco menos evidente.
Observe:
1. #include
2. #include
3. int main()
4. {
5. int quant;
6. int cont;
7. float valor;
8. float soma = 0;
9. float media;
10. printf("Digite a quantidade de valores: ");
11. scanf("%d", &quant);
12. cont=1;
13. while (cont
2. #include
3. int main()
4. {
5. int quant=0;
6. float valor;
7. float soma=0;
8. float media;
9. scanf("%f", &valor);
10. while (valor >= 0.0)
11. {
12. soma += valor;
13. quant++;
14. scanf("%f", &valor);
15. }
16. media = soma / quant;
17. printf("Media: %f", media);
18. return 0;
19. }
Nas linhas 05 a 08, há a declaração das variáveis, como nos exemplos anteriores. A diferença
está no uso da estrutura while para determinar o momento para terminar a repetição da leitura
(linhas 09 a 15). O programa precisa ler o primeiro número antes de verificar a condição, o que
justifica o scanf antes do while. Se ele for não negativo, então ele é somado no bloco do while
(linha 12). A variável quant é aumentada em uma unidade para saber quanto números foram
somados até agora (linha 13). Esse valor será necessário para o cálculo da média. Por fim, é
necessário ler o próximo número antes de avaliar novamente a condição do while. Por este motivo,
a última linha do bloco (linha 14) contém um scanf para ler tal número.
Nas linhas 16 e 17, a média é calculada da mesma forma como nos dois exemplos anteriores.
Caso 4 → ler uma quantidade desconhecida de valores (utilizando do-while)
➢ Deseja-se calcular a média de uma lista de números não negativos, de comprimento arbitrário.
O usuário escreve a lista de números, indicando o fim da lista com um número negativo.
O programa anterior pode ser reescrito usando a estrutura do-while. Observe:
1. #include
2. #include
3. int main()
4. {
5. int quant=0;
6. float valor;
7. float soma=0;
8. float media;
9. do
10. {
11. scanf("%f", &valor);
12. if (valor>=0.0)
13. {
14. soma += valor;
15. quant++;
16. }
17. }
18. while (valor>=0.0);
19. media = soma / quant;
20. printf("Media: %f", media);
21. return 0;
22. }
Este programa é semelhante ao caso anterior, variando apenas no uso da estrutura do-
while ao invés do while.
O primeiro comando executado no bloco é o comando scanf, que lê o próximo valor (linha
11). Se este valor for maior ou igual a zero, então ele é somando para o cálculo da média. Repare
agora que utiliza-se o comando scanf apenas uma vez. Por outro lado, precisamos sempre testar
o valor lido dentro do bloco do scanf (linha 12). Poderíamos ter evitado o teste, sempre somando
o valor lido dentro do bloco, mas desde que tenhamos o cuidado de, após terminada a execução do
do-while, subtrairmos o último valor somado, que terá sido somado indevidamente.
A condição se saída (linha 18) verifica se o último valor lido é maior ou igual a zero e repete
o bloco caso afirmativo.
Para este programa, é difícil decidir qual estrutura de repetição é mais vantajosa: o while o
do-while. Os dois programas são idênticos quanto ao resultado produzido. O do-while é menos
elegante pois é necessário verificar a condição duas vezes e por exigir um if dentro do bloco. O
while, tem o inconveniente de exigir duas linhas com o comando scanf.
Caso 5 → executar até que o usuário decida parar (utilizando do-while)
➢ Idêntico ao caso 1, mas com a opção de ser executado várias vezes. Usuário informa a
quantidade de valores disponíveis e em seguida informa cada um dos valores. O programa
então calcula a média dos números lidos. Depois de calcular a média, o programa pergunta ao
usuário se ele deseja repetir tudo de novo, para calcular uma nova média sobre novos números.
Observe o código-fonte:
1. #include
2. #include
3. int main()
4. {
5. int quant;
6. int cont;
7. float valor;
8. float soma;
9. float media;
10. char repete;
11. do
12. {
13. printf("Digite a quantidade de valores: ");
14. scanf("%d", &quant);
15. soma = 0;
16. for (cont=1; contNote que os comando da segunda estrutura iterativa só serão executados se a condição da
primeira for verdadeira. Esse processo se repete para cada comando de repetição que o programa
encontrar dentro do bloco de comando que ele executar.
O uso de estruturas iterativas aninhadas é muito útil quando se tem que percorrer dois
conjuntos de valores que estão relacionados dentro de um programa. Por exemplo, para imprimir
uma matriz identidade (composta apenas de 0’s e 1’s na diagonal principal) de tamanho 4 x 4 é
necessário percorrer as quatro linhas da matriz e, para cada linha, percorrer as suas quatro colunas.
Um único comando de repetição não é suficiente para realizar essa tarefa, como mostrado nos
exemplos abaixo.
Utilizando comando for Utilizando comando while
#include
#include
int main()
{
int i,j;
for (i=1; i
#include
int main()
{
int i,j;
i=1;
while (i
2. #include
3. int main()
4. {
5. int num;
6. int cont;
7. int resto;
8. int quantdiv;
9. printf("Digite um número inteiro: ");
10. scanf("%d", &num);
11. quantdiv = 0;
12. for (cont=1; cont= 3)
19. {
20. break;
21. }
22. }
23. }
24. if (quantdiv == 2)
25. {
26. printf("O numero %d é primo!\n", num);
27. }
28. else
29. {
30. printf("O numero %d não é primo!\n", num);
31. }
32. return 0;
33. }
A variável num armazena o valor digitado pelo usuário. A variável cont é um contador para
armazenar o próximo candidato a divisor a ser testado. A variável resto é usada para
armazenamento temporário dentro do bloco de repetição do for. E quantdiv conta quantos
divisores foram encontrados até o momento.
A repetição é controlada pelo valor da variável cont. Ela inicializa em 1 e a repetição ocorre
enquanto ela contiver valores menores ou iguais ao próprio número. O código executado dentro da
repetição calcula o resto da divisão. Sendo ele zero, significa que encontramos um divisor. Neste
caso, o contador quantdiv é atualizado. Verifica-se então se quantdiv ultrapassou o número
máximo de divisores para um número primo (2 divisores). Se verdadeiro, o break interrompe
imediatamente a execução do for, independente de quantas repetições ainda faltem.
No final, se o número de divisores for 2, então temos um número primo. Em qualquer caso,
uma mensagem é impressa informando este resultado. Note que o número 1 não é considerado
primo. Nesse caso, o funcionamento do programa também é correto, pois apenas um divisor (ele
mesmo) será encontrado.
7.2. COMANDO CONTINUE
O comando continue reinicia imediatamente a execução de um bloco de uma estrutura de
repetição. O comando continue não espera o término da execução do restante do bloco. No caso
do while, a execução retorna imediatamente para avaliar a expressão, antes de executar
novamente o bloco, se for o caso. Se a expressão avaliar como falso, então o while é finalizado,
caso contrário ele realiza uma nova iteração. Para o for, o continue interrompe a execução normal
do bloco, realiza imediatamente a atualização das variáveis de controle para, em seguida, realizar
novamente o teste. Se o teste resultar em falso, então o for é finalizado, caso contrário ele realiza
uma nova iteração. No do-while, o comando continue simplesmente inicia uma nova iteração,
no início do bloco. O comando continue é útil para avançar para a próxima repetição quando fica
evidente que a execução atual do bloco não se faz mais necessária.
Observe abaixo o desvio no fluxo de execução causado pelo comando continue. As linhas
tracejadas mostram o fluxo convencional. A linha contínua representa o fluxo caso o comando
continue seja executado.
while (condição)
{
sequência_de_comandos;
if (condição)
{
continue;
}
sequência_de_comandos;
}
do
{
sequência_de_comandos;
if (condição)
{
continue;
}
sequência_de_comandos;
}
while (condição);
for (inicialização;
condição; incremento)
{
sequência_de_comandos;
if (condição)
{
continue;
}
sequência_de_comandos;
}
Vale ressaltar que o uso do comando continue costuma estar associado à uma estrutura
condicional para que a repetição seja reiniciada somente sob determinadas condições.
Observe abaixo umexemplo de programa para imprimir a tangente de ângulos de 0º a 180º.
Quando a iteração chega ao ângulo de 90º, é acionado o comando continue para avançar para o
próximo ângulo, já que não existe tangente de 90º. O programa imprime uma tabela com a imagem
da função tangente, em intervalos de 10 em 10 graus.
Observe o código-fonte:
1. #include
2. #include
3. #include
4. int main()
5. {
6. double ang;
7. double pi = 3.14159265358979;
8. for (ang=0; ang