Beruflich Dokumente
Kultur Dokumente
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 parte do cdigo do
programa 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.
incio
0
expresso
1 Sintaxe:
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, parar 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
sentena(s)
Sintaxe:
1 do {
expresso sentena;
sentena;
0 ...
} while (expresso);
fim
Figura 4 Fluxo de controle da Figura 5 Sintaxe da estrutura de repetio
estrutura de repetio do...while do...while
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 at
10, no final de cada iterao temos:
numero = numero + 1;
Em C, a sentena acima significa que a varivel numero recebe um novo valor por causa do
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 ser prticos em estruturas de repetio:
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.
2. O novo valor atribudo varivel, cujo novo valor fica acrescido de uma unidade.
3. O novo valor retornado como o valor da expresso.
Exemplo
Para imprimir os nmeros de 1 at 10 com while:
int numero = 1;
while (numero <= 10) {
printf("%d\n" , numero);
++numero;
}
Consulte: EstruturasRepeticao\while02\while02.vcproj
Existem comandos semelhantes aos antriores, 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.
inicializao
teste
0
1
Sintaxe:
sentena(s)
for (inicializao;
teste;
atualizao) {
atualizao sentena;
sentena;
...
fim }
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 obervamos que o programa
faz a inicializao, que atribui o valor inicial da varivel contadora. Em seguida avalia a
expresso, que verifica 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 figura 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 inicializar a varivel numero com 1, ela agora inicializada com 10. A
cada repetio, a atualizao deve reduzir o valor da varivel correspodente em uma
unidade. Portanto, podemos escrever numero--. A condio deve verificar agora se
o valor de numero maior ou igual que 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 at 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 veremos que:
Existe uma varivel contadora que controla 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 que so 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 desses 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 no 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 utilizado 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 fim, 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;
}
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 de goto pode ser re-escrita de forma muito mais elegante usando
while, do...while, for e, se necessrio, tambm break e continue.