Escolar Documentos
Profissional Documentos
Cultura Documentos
Repeticao Controle
Repeticao Controle
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.
expresso
1
Sintaxe:
while (expresso) {
sentena;
sentena;
...
}
sentena(s)
Figura 2 Sintaxe da estrutura de repetio
while
fim
Figura 1 Fluxo de controle da
estrutura de repetio while
A repetio do while controlada por uma condio que verifica alguma caracterstica do
programa (por exemplo, valores de variveis). Para o uso correto do while, o bloco de
sentenas precisa modificar o estado do sistema de forma a afetar justamente as
caractersticas testadas na expresso. Se isto no ocorrer, ento o while executar
eternamente.
Observao: O programa sempre executa o bloco de sentenas completo. Mesmo que
durante uma execuo do bloco a condio se torne falsa, o programa s verificar este fato
quando avaliar novamente a expresso, preparando para uma nova repetio.
Exemplo
Para imprimir os nmeros de 1 at 10:
int numero = 1;
while (numero <= 10) {
printf("%d\n" , numero);
numero = numero + 1;
}
Consulte: EstruturasRepeticao\while01\while01.vcproj
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
chaves que delimitam o bloco, como na Figura
while (expresso)
3. No entanto, essa forma no delimita
sentena;
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.
Cdigo Fonte
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int numero;
int divisor;
int resto;
printf("Digite o numero: ");
scanf("%d", &numero);
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
As duas linhas pedem ao usurio para digitar o nmero para o qual deseja descobrir
os divisores.
divisor = 1;
while (divisor <= numero) {
...
divisor = divisor + 1;
}
O cdigo executado dentro da repetio calcula o resto da diviso. Caso ele seja
zero, significa que encontramos um divisor. Tal divisor impresso.
Primeiro exemplo de execuo:
Digite o numero: 19
Divisor encontrado: 1
Divisor encontrado: 19
Sintaxe:
incio
do {
sentena(s)
expresso
sentena;
sentena;
...
} while (expresso);
0
fim
Figura 4 Fluxo de controle da
estrutura de repetio do...while
No final da execuo, o valor da varivel numero ser 11, que foi justamente o valor
que tornou a expresso falsa, impedindo uma nova execuo do bloco do...while.
Estrutura de repetio do...while em uma linha
Quando o bloco da estrutura
do...while contm apenas uma nica
Sintaxe:
sentena, pode-se omitir as chaves que
do sentena while (expresso);
delimitam o bloco como na Figura 6.
No entanto, essa forma no delimita
claramente o cdigo do restante do
Figura 6 Sintaxe abreviada da estrutura
condicional do...while
programa. Por ser mais confusa, evite
a forma abreviada!
Exemplo
O programa MDC apresentado para a estrutura de repetio while pode ser re-escrito com
um do...while. Este programa calcula o mximo divisor comum (MDC) entre dois
nmeros positivos.
Cdigo Fonte
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int numeroA;
int numeroB;
int resto;
printf("Digite dois numeros (ordem crescente): ");
scanf("%d %d", &numeroA, &numeroB);
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);
printf("MDC: %d", numeroB);
return 0;
}
Consulte: EstruturasRepeticao\mdc02\mdc02.vcproj
Cada repetio divide um valor pelo outro e guarda o resto. Quando o resto for nulo,
o valor do MDC foi encontrado e a repetio terminada.
Exemplo de execuo
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:
numero = numero + 1;
(retorne numero)
numero = numero - 1;
(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.
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 anteriores, mas que retornam os valores que estavam
armazenados nas variveis antes de se realizar as operaes de incremento ou de
decremento.
Para:
Use o atalho:
Forma original:
(retorne numero)
numero = numero + 1;
(retorne numero)
numero = numero - 1;
Exemplo
int numero = 1, val = 10;
val = numero--;
printf("val = %d, numero = %1d\n" , val, numero);
Observe que o novo valor da varivel val 1, ou seja, o valor original de numero. Esse o valor
retornado pela expresso. Porm, o novo valor que atribudo para numero 0, ou seja, o resultado
da operao de decrscimo.
Operaes aritmticas na forma geral
variavel = variavel op expressao
Use o atalho:
Forma original:
numero = numero + k;
numero = numero - k;
Multiplicar o
varivel por k
da numero *= k;
numero = numero * k;
numero = numero / k;
valor
// Inicializao
// Teste
// Execuo
// Atualizao
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.
10
Sintaxe:
incio
inicializao
teste
1
sentena(s)
for (inicializao;
teste;
atualizao) {
sentena;
sentena;
...
}
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
11
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!
12
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>
int main(int argc, char *argv[]) {
int numero;
int divisor;
int resto;
printf("Digite o numero: ");
scanf("%d", &numero);
for (divisor = 1; divisor <= numero; divisor++) {
resto = numero % divisor;
if (resto == 0) {
printf("Divisor encontrado: %d \n", divisor);
}
}
return 0;
}
Consulte: EstruturasRepeticao\Divisores02\Divisores02.vcproj
13
numero. Dentro do bloco for, calcula-se o resto da diviso. Caso ele seja zero,
significa que encontramos um divisor.
Primeiro exemplo de execuo:
Digite o numero: 19
Divisor encontrado: 1
Divisor encontrado: 19
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.
14
Sugerido quando:
O nmero de repeties controlado por uma varivel controladora.
H necessidade de inicializao e atualizao, mas que sejam simples o suficiente
para que sejam acomodadas na linha do for. Para casos mais complexos, melhor
usar o comando while.
A avaliao da condio no depende de dados obtidos na execuo do bloco.
Considere o uso do for para separar claramente as instrues do controle de repetio
(inicializao e atualizao) das demais instrues do bloco.
Mas adiante, o for ser uma ferramenta til para percorrer elementos de vetores, listas e
matrizes. A varivel contadora do for ser justamente um ndice do vetor ou da matriz.
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.
Cdigo fonte:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int quantidade;
int contador;
double valor;
double soma = 0;
double media;
// Solicita a quantidade de nmeros que devem ser lidos
printf("Quantidade de valores: ");
scanf("%d", &quantidade);
// Solicita cada um dos nmeros e soma-o
for (contador = 1; contador <= quantidade; contador++) {
printf("Valor: ");
scanf("%lf", &valor);
soma += valor;
}
media = soma / quantidade;
printf("Mdia: %f", media);
return 0;
}
15
Consulte: EstruturasRepeticao\Caso1\Caso1.vcproj
O programa solicita que o usurio digite o nmero de valores que devem ser lidos
para calcular a mdia.
for (contador = 1; contador <= quantidade; contador++) {
printf("Valor: ");
scanf("%lf", &valor);
soma += valor;
}
O for executa o bloco repetidamente, uma vez para cada valor de contador entre
1 e o nmero armazenado em quantidade. A cada repetio, solicita um nmero, o
qual somado ao valor anterior em soma, e que substitui o antigo valor nessa
varivel.
media = soma / quantidade;
printf("Mdia: %f", media);
Quantidade de valores: 5
Valor: 3
Valor: 5
Valor: 4
Valor: 6
Valor: 5
Mdia: 4.600000
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.
16
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int quantidade;
int contador;
double valor;
double soma = 0;
double media;
// Solicita a quantidade de nmeros que devem ser lidos
printf("Quantidade de valores: ");
scanf("%d", &quantidade);
// Solicita cada um dos nmeros e soma-o
contador = 1;
while (contador <= quantidade) {
printf("Valor: ");
scanf("%lf", &valor);
soma += valor;
contador++;
}
// Calcula e mostra a mdia
media = soma / quantidade;
printf("Media: %f", media);
return 0;
}
Consulte: EstruturasRepeticao\Caso2\Caso2.vcproj
Cdigo fonte:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int quantidade = 0;
double valor;
double soma = 0;
double media;
// Solicita cada um dos nmeros e soma-o
scanf("%lf", &valor);
while (valor >= 0.0) {
soma += valor;
quantidade++;
17
scanf("%lf", &valor);
}
// Calcula e mostra a mdia
media = soma / quantidade;
printf("Media: %f", media);
return 0;
}
Consulte: EstruturasRepeticao\Caso3\Caso3.vcproj
A mdia calculada da mesma forma como nos dois exemplos anteriores. O que
ocorre se a lista de nmeros for vazia, isto , o usurio entra logo com um primeiro
valor que negativo? Melhore o programa de forma que evite essa condio de
contorno.
Exemplo de execuo:
Escreva os valores, terminando com um nmero negativo.
3 5 4 6 5 -1
Media: 4.600000
18
19
Cdigo Fonte:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int quantidade;
int contador;
double valor;
double soma;
double media;
char repetir;
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;
}
// Calcula e mostra a mdia
media = soma / quantidade;
printf("Media: %f\n\n", media);
printf("Deseja executar o programa novamente? (s/n) ");
scanf(" %c", &repetir);
} while (repetir == 's');
return 0;
}
Consulte: EstruturasRepeticao\Caso5\Caso5.vcproj
20
Media: 14.666667
Deseja executar o programa novamente? (s/n) n
21
Controle de Repetio
Forar interrupo de repetio: break
O comando break um modo conveniente de terminar imediatamente a execuo de um
bloco controlado por uma estrutura de repetio, sem necessidade de esperar a prxima
avaliao da condio. O comando break til para interromper a execuo de uma
estrutura de repetio quando fica evidente que as demais repeties no produziro novos
resultados. Assim, o programa pode economizar algum tempo de execuo. No prximo
exemplo, que verifica se um nmero primo, o comando break ser usado para
interromper as repeties assim que mais de dois divisores forem encontrados.
A Figura 10 ilustra o desvio no fluxo de execuo causado pelo comando break. O break
no espera o trmino da execuo do restante do bloco. As linhas tracejadas mostram o
while (expresso) {
sentenas(s);
if (condio) {
break;
}
sentenas(s);
}
do { sentenas(s);
if (condio) {
break;
}
sentenas(s);
} while (expresso);
for (inicializao;
teste;
atualizao) {
sentenas(s);
if (condio) {
break;
}
sentenas(s);
}
incio
incio
0
incio
inicializao
expresso
sentena(s)
break
sentena(s)
break
teste
1
1
expresso
sentena(s)
break
0
atualizao
fim
fim
fim
fluxo convencional. A linha contnua representa o fluxo caso o break seja executado.
22
} else {
printf("O numero %d NAO eh primo!\n", numero);
}
return 0;
}
Consulte: ControleExecucao\Divisores03\Divisores03.vcproj
numero;
divisor;
resto;
numero_divisores;
23
numero_divisores = 0;
for (divisor = 1; divisor <= numero; divisor++) {
...
}
O cdigo executado dentro da repetio calcula o resto da diviso. Sendo ele zero,
significa que encontramos um divisor. Neste caso, o contador numero_divisores
atualizado. Verifica-se ento se numero_divisores ultrapassou o nmero mximo
de divisores para um nmero primo (2 divisores). Se verdadeiro, o break
interrompe imediatamente a execuo do for, independente de quantas repeties
ainda faltem.
if (numero_divisores == 2) {
printf("O numero %d eh primo!\n", numero);
} else {
printf("O numero %d NAO eh primo!\n", numero);
}
Digite o numero: 10
O numero 10 NAO eh primo!
24
while (expresso) {
comandos(s);
if (condio) {
continue;
}
comandos(s);
}
do {
comandos(s);
if (condio) {
continue;
}
comandos(s);
} while (expresso);
for (inicializao;
teste;
atualizao) {
comandos(s);
if (condio) {
continue;
}
comandos(s);
}
incio
incio
0
expresso
sentena(s)
continue
sentena(s)
continue
inicializao
incio
teste
1
1
expresso
sentena(s)
continue
atualizao
fim
fim
fim
Figura 11 Fluxo de controle em estruturas de repetio com continue
25
Exemplo:
Um programa que imprime uma tabela com a imagem da funo tangente, em intervalos de
10 em 10 graus.
Cdigo fonte
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(int argc, char *argv[]) {
double angulo;
double pi = 3.14159265358979;
for (angulo = 0; angulo <= 180; angulo += 10.0) {
if (angulo == 90.0) {
continue;
}
printf("tan(%f) = %f\n", angulo, tan(angulo/180*pi));
}
return 0;
}
Consulte: ControleExecucao\Tangete01\Tangente01.vcproj
26
tan(70.000000) = 2.747477
tan(80.000000) = 5.671282
tan(100.000000) = -5.671282
tan(110.000000) = -2.747477
tan(120.000000) = -1.732051
tan(130.000000) = -1.191754
tan(140.000000) = -0.839100
tan(150.000000) = -0.577350
tan(160.000000) = -0.363970
tan(170.000000) = -0.176327
tan(180.000000) = -0.000000
Sintaxe:
sentena(s);
...
goto marca2;
...
sentena(s);
...
marca2:
...
sentena(s);
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
27
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.
if (numero > 10) {
goto fim_repeticao;
}
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.
28