Escolar Documentos
Profissional Documentos
Cultura Documentos
Cap06 RepeticaoControle Texto PDF
Cap06 RepeticaoControle Texto PDF
Introduo
No captulo anterior verificamos que a execuo seqencial dos comandos da funo main
nos limita a programao de algoritmos muito simples. Passamos, ento, a dedicar nossa
ateno ao estudo de recursos de programao mais elaborados, tais como as estruturas
condicionais if...else e switch, as quais permitem executar partes do cdigo somente
sob determinadas condies.
Agora, estudaremos as estruturas de repetio, que permitem executar mais de uma vez um
mesmo trecho de cdigo. Trata-se de uma forma de executar blocos de comandos somente
sob determinadas condies, mas com a opo de repetir o mesmo bloco quantas vezes for
necessrio. As estruturas de repetio so teis, por exemplo, para repetir uma srie de
operaes semelhantes que so executadas para todos os elementos de uma lista ou de uma
tabela de dados, ou simplesmente para repetir um mesmo processamento at que uma certa
condio seja satisfeita.
0 while (expresso) {
expresso sentena;
sentena;
1 ...
}
sentena(s)
Figura 2 Sintaxe da estrutura de repetio
while
fim
Figura 1 Fluxo de controle da
estrutura de repetio while
A Figura 12 ilustra a sintaxe da estrutura condicional while em C. O fluxo de execuo
desta estrutura est ilustrado na Figura 21. A expresso uma condio que controla o
while. Primeiro, o programa avalia a expresso. Ela utiliza os mesmos operadores
relacionais e lgicos estudados quando tratamos das as estruturas condicionais. Caso o
resultado da expresso seja no nulo (verdadeiro), ento todo o bloco de sentenas ser
executado. Em seguida, o programa volta a avaliar a expresso e o processo se repete at
que a expresso retorne um valor zero (falso). A expresso sempre avaliada antes da
deciso de se executar o bloco de sentenas novamente.
Observao: A expresso dever ser colocada, obrigatoriamente, entre parnteses.
Declaramos uma varivel numero que controlar o while. Ela armazena o valor a
ser impresso. A expresso do while verifica se o nmero est dentro do limite
desejado (menor ou igual a 10).
No incio, a varivel numero contm o valor 1 e, portanto, a expresso do while
satisfeita. O bloco de expresses executado, imprimindo o valor de numero e
aumentando seu valor em uma unidade. Note que isto afeta a condio que controla
o bloco.
Nas prximas repeties, a expresso ser verdadeira para os valores de numero 2,
3, 4, ... 9 e 10. Quando numero armazenar o valor 11, a expresso que controla o
while se tornar falsa. Nesse ponto, o while termina, encerrando as repeties.
No final da execuo, o valor da varivel numero estar em 11, que foi justamente o
valor que tornou a expresso falsa, impedindo uma nova execuo do bloco while.
Estrutura de repetio while em uma linha
Quando o bloco da estrutura while contm
Sintaxe: apenas uma nica sentena, pode-se omitir as
while (expresso)
chaves que delimitam o bloco, como na Figura
sentena; 3. No entanto, essa forma no delimita
claramente o cdigo do while do restante do
Figura 3 Sintaxe abreviada da estrutura
programa. Por ser mais confusa, evite a forma
condicional while
abreviada!
Exemplo
O prximo exemplo um uso tpico do while para realizar uma operao para um
intervalo de nmeros. Este programa imprime todos os divisores de um nmero inteiro
positivo. Para o nmero n dado, o programa verifica se cada nmero de 1 at n ou no um
divisor de n.
divisor = 1;
while (divisor <= numero) {
resto = numero % divisor;
if (resto == 0) {
printf("Divisor encontrado: %d \n", divisor);
}
divisor = divisor + 1;
}
return 0;
}
Consulte: EstruturasRepeticao\Divisores01\Divisores01.vcproj
divisor = 1;
while (divisor <= numero) {
...
divisor = divisor + 1;
}
Este bloco corresponde estrutura de repetio. Por motivos de simplicidade, o
cdigo executado dentro do bloco foi omitido com objetivo de entender sua lgica
de funcionamento.
A repetio controlada pelo valor da varivel divisor. Isto quer dizer que o bloco
precisa modificar o valor da varivel divisor para, em algum momento, encerrar
as repeties.
Exemplo:
O prximo exemplo um uso tpico do while para realizar uma operao at que uma
condio seja satisfeita. Esta condio no depende de uma varivel contadora, tal como no
exemplo anterior. Assim, no possvel prever facilmente o nmero de repeties. O
programa calcula o mximo divisor comum (MDC) entre dois nmeros positivos.
Cdigo Fonte
#include <stdio.h>
#include <stdlib.h>
return 0;
}
Consulte: EstruturasRepeticao\mdc01\mdc01.vcproj
do {
resto = numeroB % numeroA;
printf("numeroB = %d; numeroA = %d; ", numeroB, numeroA);
printf("resto = %d\n", resto);
numeroB = numeroA;
numeroA = resto;
} while (numeroA > 0);
// ou while (resto > 0);
return 0;
}
Consulte: EstruturasRepeticao\mdc02\mdc02.vcproj
Operadores de incremento
Talvez voc tenha observado que, freqentemente, as estruturas de repetio utilizam
variveis para controlar o nmero de repeties. No exemplo de imprimir nmeros de 1 a
10, no final de cada iterao tnhamos:
numero = numero + 1;
Em C, a sentena acima significa que a varivel numero recebe um novo valor devido ao
operador de atribuio. O novo valor calculado da seguinte forma: somando-se 1 ao valor
da varivel no lado direito da atribuio. Como este tipo de atribuio muito freqente, a
linguagem C oferece atalhos que podem facilitam a sintaxe dessas operaes:
Para: Use o atalho: Forma original:
Somar uma unidade ao valor ++numero; numero = numero + 1;
da varivel (retorne numero)
Subtrair uma unidade do --numero; numero = numero - 1;
valor da varivel (retorne numero)
Observao:
1. comum que programadores experientes utilizem estes operadores dentro de
expresses complexas, at mesmo dentro das prprias condies que controlam a
execuo de um while. No momento, utilizaremos estes operadores apenas em
expresses simples. prefervel criar um cdigo simples e de fcil entendimento do que
um cdigo compacto e mais difcil de entender.
2. O novo valor atribudo varivel, cujo valor estar acrescido de uma unidade.
3. O novo valor, j acrescido da unidade, retornado como o valor do clculo da
expresso.
Existem comandos semelhantes aos anteriores, mas que retornam os valores que estavam
armazenados nas variveis antes de se realizar as operaes de incremento ou de
decremento.
val = numero--;
printf("val = %d, numero = %1d\n" , val, numero);
O grande nmero de situaes que requerem esta lgica justifica a prxima estrutura de
repetio. Ela apresenta, de forma compacta, as etapas de inicializao, do teste e da
atualizao.
atualizao
fim
Figura 7 Fluxo de controle da
estrutura de repetio for
Um for sempre est acompanhado de uma varivel contadora que armazena quantas vezes
o bloco de sentenas do for deve ser executado. Na Figura 7 observamos que o programa
faz a inicializao, que atribui o valor inicial varivel contadora. Em seguida avalia a
expresso, que determina se o valor da varivel contadora est dentro do limite desejado.
Caso positivo, o bloco de sentenas executado e, em seguida, executada a atualizao,
que altera o valor da varivel contadora. O processo se repete avaliando novamente a
expresso. A sintaxe da estrutura for est na ilustrada na Figura 8.
Tipicamente, uma estrutura for ocorre como no modelo abaixo:
int contador;
for (contador = 1; contador <= 10; contador++) {
...
}
Exemplo
Para imprimir os nmeros de 1 at 10:
int numero;
for (numero = 1; numero <= 10; numero++) {
printf("%d ", numero);
}
Consulte: EstruturasRepeticao\for01\for01.vcproj
Declaramos uma varivel numero que servir como contador para o for. Ela
armazenar a contagem de repeties. O for executa o bloco contendo o comando
printf vrias vezes, variando o valor da varivel numero de 1 at 10. Observe a
forma simplificada da escrita da expresso de atualizao.
Resultado: 1 2 3 4 5 6 7 8 9 10
Ao invs de iniciar a varivel numero com 1, ela agora iniciada com 10. A cada
repetio, a atualizao deve reduzir o valor da varivel correspondente em uma
unidade. Portanto, podemos escrever numero--. A condio deve verificar agora se
o valor de numero maior ou igual a 1.
Resultado: 10 9 8 7 6 5 4 3 2 1
Alm de condensar uma lgica recorrente de programao em poucas linhas, o for possui
outras duas vantagens importantes:
O seu cabealho agrupa todas as instrues mais importantes que controlam a
execuo do for: a inicializao, o teste e a atualizao. O programador obrigado
a declarar toda a lgica de execuo em uma nica linha e de uma s vez. Em uma
estrutura while, um erro muito comum o programador esquecer de inicializar
ou atualizar a varivel de controle.
O cabealho separa claramente as instrues de controle de repetio das instrues
de execuo. No exemplo para imprimir nmeros de 1 a 10 sem o uso do for a
varivel contadora atualizada logo aps a impresso. Em programas mais
elaborados, as instrues de atualizao tendem a ficarem escondidas ou diludas
dentro das demais instrues, tornando o programa obscuro e suscetvel a erros de
programao.
Toda a estrutura for equivalente a um while. A escolha entre uma estrutura ou outra
uma questo de gosto e estilo de programao. Use o bom senso para realizar sua escolha.
Observao: Note a ordem correta das declaraes no cabealho: inicializao, teste e
atualizao! No esquea do ponto-e-vrgula separando as declaraes. Todo o cabealho
dever estar obrigatoriamente entre parnteses!
Sintaxe:
for (inicializao; teste; atualizao)
sentena;
Quando o bloco da estrutura for contm apenas uma nica sentena, pode-se omitir as
chaves que delimitam o bloco, tal como na Figura 9. No entanto, essa forma no delimita
claramente o cdigo a ser executado repetidamente do restante do programa. Por ser mais
confusa, evite a forma abreviada!
Exemplo
Este programa imprime todos os divisores de um nmero. Para um dado nmero n, o
programa testa todos os nmeros de 1 at n.
Cdigo Fonte
#include <stdio.h>
#include <stdlib.h>
return 0;
}
Consulte: EstruturasRepeticao\Divisores02\Divisores02.vcproj
Casos de Uso
Um programa pode ser escrito corretamente tanto com while, como com do...while
como com for. A escolha da estrutura cabe ao programador, que deve preferir aquela que
produz cdigo mais simples e fcil de entender.
while (expresso) { ... }
Objetivo: Executar o bloco apenas enquanto uma condio for verdadeira. Se a condio
for falsa logo no incio, o bloco no executado nenhuma vez.
Sugerido quando:
No h necessidade de inicializar ou atualizar variveis contadoras.
As etapas de inicializao ou atualizao requerem muitas instrues e no
caberiam elegantemente numa nica linha do for.
As informaes necessrias para avaliar a condio no dependem de uma varivel
contadora ou so obtidas durante a execuo do bloco.
Nestes trs casos anteriores, prefira um while ao invs do for.
do { ... } while (expresso);
Objetivo: Executar o bloco pelo menos uma vez e repetir enquanto uma condio for
verdadeira.
Sugerido quando:
necessrio executar um bloco pelo menos uma vez para obter as informaes
necessrias para avaliar a condio.
muito comum utilizar o do...while para leitura de dados. Um uso tpico poderia ser
repetir a leitura enquanto o dado no for vlido.
for (inicializao; teste; reinicializao) { ... }
Objetivo: Executar o bloco um certo nmero de vezes, controlado por uma varivel
contadora.
Exemplos Tpicos
Para entender melhor quando utilizar cada uma das estruturas, analisaremos alguns
exemplos que exigem execuo repetida do mesmo bloco de cdigo.
Caso 1, usando for: Ler uma quantidade fixa de valores
Primeiro, o usurio informa a quantidade de valores disponveis e em seguida informa cada
um dos valores. O programa calcula a mdia dos nmeros lidos.
Neste caso, ser conveniente utilizar um for, pois vemos que:
Podemos usar uma varivel contadora para controlar o nmero de repeties para a
leitura dos valores.
H necessidade de inicializar e atualizar esta varivel contadora. A inicializao e a
atualizao so instrues simples, e que podem ser acomodadas facilmente em uma
linha do for.
conveniente separar a inicializao e atualizao do bloco que calcula a mdia.
Cdigo fonte:
#include <stdio.h>
#include <stdlib.h>
O que ocorre quando o usurio entra um valor zero ou negativo para quantidade? Modifique
o programa para se precaver contra esses casos.
Caso 2, usando while: Ler uma quantidade fixa de valores
O mesmo programa pode ser escrito usando while, mas torna o cdigo um pouco menos
evidente.
Cdigo fonte:
#include <stdio.h>
#include <stdlib.h>
scanf("%lf", &valor);
while (valor >= 0.0) {
soma += valor;
quantidade++;
scanf("%lf", &valor);
}
A diferena est no uso da estrutura while para determinar o momento para
terminar a repetio da leitura.
O programa precisa ler o primeiro nmero antes de verificar a condio, o que
justifica o scanf antes do while. Se ele for no negativo, ento ele somado no
bloco do while. A varivel quantidade aumentada em uma unidade para saber
quanto nmeros foram somados at agora. Esse valor ser necessrio para o clculo
da mdia. Por fim, necessrio ler o prximo nmero antes de avaliar novamente a
condio do while. Por este motivo, a ltima linha do bloco contm um scanf para
ler tal nmero.
do {
// Solicita a quantidade de nmeros que devem ser lidos
printf("Quantidade de valores: ");
scanf("%d", &quantidade);
soma = 0; // inicializa soma com 0, inclusive nas demais iteracoes
// Solicita cada um dos nmeros e soma-o
for (contador = 1; contador <= quantidade; contador++) {
printf("Valor: ");
scanf("%lf", &valor);
soma += valor;
}
return 0;
}
Consulte: EstruturasRepeticao\Caso5\Caso5.vcproj
for (inicializao;
while (expresso) { teste;
do { sentenas(s);
sentenas(s); atualizao) {
if (condio) {
if (condio) { sentenas(s);
break;
break; if (condio) {
}
} break;
sentenas(s);
sentenas(s); }
} while (expresso);
} sentenas(s);
}
incio
0
expresso teste
sentena(s) 0
1
break 1
1
sentena(s)
sentena(s)
break
expresso break
0
atualizao
fim fim
fim
Figura 10 Fluxo de controle em estruturas de repetio com break
fluxo convencional. A linha contnua representa o fluxo caso o break seja executado.
Exemplo
Um programa que verifica se um nmero primo ou no. O programa utiliza o mesmo
algoritmo que j vimos para encontrar os divisores de um nmero.
Note que o nmero primo contm exatamente dois divisores (1 e o prprio nmero).
Portanto, assim que o terceiro divisor for encontrado, ficar evidente que o nmero no
primo. Nesta situao, o programa utiliza o break para terminar a execuo do while,
evitando continuar as iteraes seguintes, que no seriam teis.
Cdigo fonte
#include <stdio.h>
#include <stdlib.h>
numero_divisores = 0;
for (divisor = 1; divisor <= numero; divisor++) {
resto = numero % divisor;
if (resto == 0) {
numero_divisores = numero_divisores + 1;
if (numero_divisores >= 3) {
break;
}
}
}
if (numero_divisores == 2) {
printf("O numero %d eh primo!\n", numero);
} else {
printf("O numero %d NAO eh primo!\n", numero);
}
return 0;
}
Consulte: ControleExecucao\Divisores03\Divisores03.vcproj
if (numero_divisores == 2) {
printf("O numero %d eh primo!\n", numero);
} else {
printf("O numero %d NAO eh primo!\n", numero);
}
No final, se o nmero de divisores for 2, ento temos um nmero primo. Em
qualquer caso, uma mensagem impressa informando este resultado. Note que o
nmero 1 no considerado primo. Nesse caso, o funcionamento do programa
tambm correto, pois apenas um divisor (ele mesmo) ser encontrado.
Primeiro exemplo de execuo
Digite o numero: 5
O numero 5 eh primo!
Primeiro exemplo de execuo
Digite o numero: 10
O numero 10 NAO eh primo!
for (inicializao;
while (expresso) { do { teste;
comandos(s); comandos(s); atualizao) {
if (condio) { if (condio) { comandos(s);
continue; continue; if (condio) {
} } continue;
comandos(s); comandos(s); }
} } while (expresso); comandos(s);
}
incio
0
expresso teste
0
1 sentena(s)
continue 1
1
sentena(s)
sentena(s)
continue
expresso continue
0
atualizao
fim fim
fim
Figura 11 Fluxo de controle em estruturas de repetio com continue
return 0;
}
Consulte: ControleExecucao\Tangete01\Tangente01.vcproj
Exemplo:
Imprimir os nmeros de 1 at 10.
Cdigo fonte:
#include <stdio.h>
#include <stdlib.h>
/*
* Imprime nmeros de 1 at 10, usando apenas GOTO.
*/
int main() {
int numero = 1;
inicio_repeticao:
if (numero > 10) { goto fim_repeticao; }
printf("%d " , numero);
numero++;
goto inicio_repeticao;
fim_repeticao:
return 0;
}
Consulte: ControleRepeticao\Goto01\Goto01.vcproj
inicio_repeticao:
Em seguida, declara-se uma marca, que identifica o inicio do cdigo que dever ser
repetido 10 vezes.
fim_repeticao:
No final do programa, declara-se outra marca, para definir o ponto para onde saltar
aps a execuo das 10 iteraes.
printf(%d\n , numero);
numero++;
goto inicio_repeticao;
O programa imprime o nmero e atualiza a varivel contadora. O comando goto
fora um desvio para o incio do lao, de modo a realizar novamente todas as
operaes para o prximo nmero na seqncia.
Exemplo de execuo:
1 2 3 4 5 6 7 8 9 10
Casos de uso do goto
Todos as estruturas de repetio podem ser escritas utilizando-se apenas marcas e gotos.
Mesmo assim, o emprego de goto no recomendado por vrios motivos, entre eles:
Dificulta a visualizao do destino de cada goto.
Oculta a estrutura lgica e de execuo do programa. Com o uso de while e for,
fcil identificar as condies de repetio, a inicializao e a atualizao de
variveis, como tambm o bloco que deve ser repetido. Com gotos, os blocos no
estaro mais realados por delimitaes.
Cada programador pode adotar sua prpria lgica de fluxo de execuo. Os
programas tornar-se-o incompreensveis e muito difceis e entender e de manter!
Toda a lgica embutida em um goto pode sempre ser re-escrita de forma muito
mais elegante usando os comandos while, do...while, for e, se necessrio,
tambm os comandos break e continue.